app_environment_config.dart 4.32 KB
import 'package:doublefeel_flutter/app/utils/platform_compact.dart';
import 'package:doublefeel_flutter/core/network/dio_client.dart';
import 'package:doublefeel_flutter/core/platform/pigeon_api_facade.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:get/get.dart';

import '../constants/app_const.dart';
import '../constants/storage_const.dart';
import '../../data/local/local_storage.dart';
import 'app_environment.dart';

/// Resolves API base URL and third-party keys by environment.
class AppEnvironmentConfig {
  AppEnvironmentConfig(this._storage);

  final LocalStorage _storage;
  final AppPlatformHostApi _platformHostApi = AppPlatformHostApi();

  final Rx<AppEnvironment> environment = AppEnvironment.release.obs;

  Future<AppEnvironmentConfig> init() async {
    environment.value = await _storage.readEnvironment();
    _isNativeDebug = await _platformHostApi.isDebugEnvoriment();
    if (isOhos()) {
      region.value = AppRegion.china;
    } else {
      final stored = await _storage.readRegion();
      if (stored == null) {
        final detected = await _detectRegion();
        await setRegion(detected);
      } else {
        region.value = stored;
      }
      if (stored == AppRegion.global) {
        await _storage.setTermsAgreed(true);
      }
    }
    return this;
  }

  Future<AppRegion> _detectRegion() async {
    try {
      return await _platformHostApi.isChinaRegion()
          ? AppRegion.china
          : AppRegion.global;
    } catch (_) {
      return _detectRegionFromLocale();
    }
  }

  AppRegion _detectRegionFromLocale() {
    final country = WidgetsBinding
        .instance.platformDispatcher.locale.countryCode
        ?.toUpperCase();
    return switch (country) {
      'CN' => AppRegion.china,
      _ => AppRegion.global,
    };
  }

  Future<void> setEnvironment(AppEnvironment value) async {
    environment.value = value;
    await _storage.writeEnvironment(value);
  }

  bool _isNativeDebug = false;

  bool get isDebug => kDebugMode || _isNativeDebug;

  final Rx<AppRegion> region = AppRegion.global.obs;

  Future<void> setRegion(AppRegion value) async {
    region.value = value;
    try {
      await _storage.writeRegion(value);
      if (Get.isRegistered<DioClient>()) {
        Get.find<DioClient>().refreshBaseUrl();
      }
    } catch (e) {
      debugPrint('setRegion failed: $e');
    }
  }

  get hideChooseRegion => _storage.hideChooseRegion;

  Future<void> updateHideChooseRegion(bool value) async {
    await _storage.writeHideChooseRegion(value);
  }

  String get serverBaseUrl {
    final regionUrl = switch (region.value) {
      AppRegion.china => AppConst.serverBaseUrl,
      AppRegion.global => AppConst.serverBaseUrlGlobal,
    };
    return resolveServerUrl(regionUrl);
  }

  /// WebSocket endpoint resolved from the active API host.
  ///
  /// This keeps the socket in the same China/global and dev/xlab environment
  /// as the REST APIs.
  String get webSocketUrl {
    final serverUri = Uri.parse(serverBaseUrl);
    final webSocketScheme = serverUri.scheme == 'https' ? 'wss' : 'ws';
    return serverUri
        .replace(
          scheme: webSocketScheme,
          path: AppConst.webSocketPath,
          query: null,
          fragment: null,
        )
        .toString();
  }

  String resolveServerUrl(String url) {
    return resolveServerUrlFor(environment.value, url);
  }

  String resolveServerUrlFor(AppEnvironment targetEnvironment, String url) {
    try {
      final uri = Uri.parse(url);
      final host = uri.host;
      final resolvedHost = switch (targetEnvironment) {
        AppEnvironment.xlab => '${AppConst.prefixXlabServerHost}-$host',
        AppEnvironment.dev => '${AppConst.prefixDevServerHost}-$host',
        AppEnvironment.release => host,
      };
      if (resolvedHost == host) {
        return url;
      }
      return uri.replace(host: resolvedHost).toString();
    } catch (_) {
      return url;
    }
  }

  String get rongCloudAppKey => environment.value == AppEnvironment.dev
      ? AppConst.appKeyRongCloudDev
      : AppConst.appKeyRongCloudProduct;

  String get thinkingDataAppId => environment.value == AppEnvironment.dev
      ? AppConst.appIdThinkingDataDebug
      : AppConst.appIdThinkingDataRelease;

  static const environmentPrefsName = StorageConst.appEnvironmentPrefsName;
}

enum AppRegion { china, global }