checkForUpdates method

Future<PatchInfo?> checkForUpdates()

Check for available patches

Returns PatchInfo if an update is available, null otherwise.

Implementation

Future<PatchInfo?> checkForUpdates() async {
  _ensureInitialized();

  try {
    if (_config.enableDebugLogging) {
      print('[QuicUI] Checking for updates...');
    }

    final client = http.Client();
    final headers = {
      'Authorization': 'Bearer $_apiKey',
      'apikey': _apiKey,
      'Content-Type': 'application/json',
    };

    // Detect platform and architecture
    String platform;
    String architecture;

    if (Platform.isAndroid) {
      platform = 'android';
      // Default to arm64-v8a (most common), could be detected via platform channel
      architecture = 'arm64-v8a';
    } else if (Platform.isIOS) {
      platform = 'ios';
      // Default to arm64 (physical devices)
      architecture = 'arm64';
    } else {
      platform = 'unknown';
      architecture = 'unknown';
    }

    final bodyMap = {
      'appId': _config.appId,
      'currentVersion': _config.appVersion,
      'platform': platform,
      'architecture': architecture,
      'acceptCompression': ['xz', 'gz', 'bz2'],
    };

    final requestUrl = '$_backendUrl/patches-check';
    if (_config.enableDebugLogging) {
      print('[QuicUI] POST $requestUrl');
    }

    // Use internal backend URL (not exposed through Config)
    final response = await client.post(
      Uri.parse(requestUrl),
      headers: headers,
      body: jsonEncode(bodyMap),
    );

    if (_config.enableDebugLogging) {
      print('[QuicUI] Response status: ${response.statusCode}');
    }

    if (response.statusCode == 200) {
      final jsonResponse = jsonDecode(response.body) as Map<String, dynamic>;
      final patchAvailable = jsonResponse['updateAvailable'] as bool? ??
                              jsonResponse['patchAvailable'] as bool? ?? false;

      if (_config.enableDebugLogging) {
        print('[QuicUI] Patch available: $patchAvailable');
      }

      if (patchAvailable) {
        final patchInfo = PatchInfo(
          patchId: jsonResponse['patchId'] as String,
          version: jsonResponse['version'] as String,
          createdAt: DateTime.now(),
          size: jsonResponse['size'] as int? ?? jsonResponse['downloadSize'] as int? ?? 0,
          downloadUrl: '$_backendUrl${jsonResponse['downloadUrl'] as String}',
          signature: jsonResponse['hash'] as String,
          platform: platform,
        );

        if (_config.enableDebugLogging) {
          final compression = jsonResponse['compression'] as String?;
          final uncompressedSize = jsonResponse['uncompressedSize'] as int?;
          print('[QuicUI] ✅ Patch found: ${patchInfo.version} (${patchInfo.size} bytes, compression: $compression, uncompressed: $uncompressedSize bytes)');
        }

        _config.onPatchAvailable?.call(patchInfo);
        client.close();
        return patchInfo;
      } else {
        if (_config.enableDebugLogging) {
          print('[QuicUI] No patch available');
        }
        client.close();
        return null;
      }
    } else {
      if (_config.enableDebugLogging) {
        print('[QuicUI] ❌ Server returned error: ${response.statusCode}');
      }
      client.close();
      return null;
    }
  } catch (e, stackTrace) {
    if (_config.enableDebugLogging) {
      print('[QuicUI] ❌ Exception during checkForUpdates: $e');
      print('[QuicUI] Stack trace: $stackTrace');
    }
    _config.onError?.call('Error checking for updates: $e');
    return null;
  }
}