user_preferences_storage.dart 4.46 KB
import 'dart:convert';

import 'package:doublefeel_flutter/core/config/app_environment_config.dart';
import 'package:doublefeel_flutter/core/services/raw_data_service/platform_ios/health_raw_data_core_service.dart';
import 'package:doublefeel_flutter/pigeon/health_kit_raw_data_api.g.dart';
import 'package:doublefeel_flutter/pigeon/platform_api.g.dart';
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';

import '../models/local/user_preferences.dart';
import '../models/user/user_models.dart';
import '../models/vip/vip_info.dart';

/// Persists [UserPreferences] as JSON.
class UserPreferencesStorage {
  UserPreferencesStorage(this._prefs);

  final SharedPreferences _prefs;

  static const _storageKey = 'double_feel_user_preferences_json';

  final Rx<UserPreferences> preferences = UserPreferences.empty.obs;

  Future<UserPreferencesStorage> init() async {
    await _load();
    return this;
  }

  // bool get isBound => (preferences.value.partnerUserInfo?.id ?? 0) > 0;

  String get accessToken => preferences.value.accessToken;

  String get rongcloudToken => preferences.value.rongcloudToken;

  Future<void> _load() async {
    final raw = _prefs.getString(_storageKey);
    if (raw == null || raw.isEmpty) {
      preferences.value = UserPreferences.empty;
      return;
    }
    try {
      final map = jsonDecode(raw) as Map<String, dynamic>;
      preferences.value = UserPreferences.fromJson(map);
    } catch (_) {
      preferences.value = UserPreferences.empty;
    }
    _syncLoginInfoToNative(userInfo: preferences.value);
  }

  Future<void> _syncLoginInfoToNative(
      {required UserPreferences userInfo}) async {
    if (userInfo.accessToken.isEmpty) {
      try {
        if (Get.isRegistered<AppEnvironmentConfig>()) {
          await PlatformHostApi().logout();
        }
      } on Exception {
        return;
      }
      return;
    }
    try {
      if (Get.isRegistered<AppEnvironmentConfig>()) {
        var env = Get.find<AppEnvironmentConfig>();
        await PlatformHostApi()
            .updateLoginInfo(jsonEncode(userInfo), env.serverBaseUrl);
        await _syncHealthRawDatabaseToNative();
      }
    } on Exception {
      return;
    }
  }

  Future<void> _syncHealthRawDatabaseToNative() async {
    if (!Get.isRegistered<HealthRawDataCoreService>()) return;
    final databasePath =
        await Get.find<HealthRawDataCoreService>().databaseFilePath();
    await HealthKitRawDataHostApi().syncDatabase(
      hrDataPath: databasePath,
      hrvDataPath: databasePath,
      sleepDataPath: databasePath,
      avgRealtimeStressDataPath: databasePath,
    );
  }

  Future<void> _persist(UserPreferences value) async {
    preferences.value = value;
    await _prefs.setString(_storageKey, jsonEncode(value.toJson()));
  }

  Future<void> update(UserPreferences value) => _persist(value);

  Future<void> updateAccessToken(String token) async {
    await _persist(preferences.value.copyWith(accessToken: token));
  }

  Future<void> updateRongcloudToken(String token) async {
    await _persist(preferences.value.copyWith(rongcloudToken: token));
  }

  Future<void> updateMeUserInfo(UserInfoResponse info) async {
    await _persist(preferences.value.copyWith(meUserInfo: info));
  }

  Future<void> updatePartnerUserInfo(UserInfoResponse info) async {
    await _persist(preferences.value.copyWith(partnerUserInfo: info));
  }

  Future<void> updateBothUserInfo({
    UserInfoResponse? me,
    UserInfoResponse? partner,
  }) async {
    await _persist(
      preferences.value.copyWith(
        meUserInfo: me ?? preferences.value.meUserInfo,
        partnerUserInfo: partner ?? preferences.value.partnerUserInfo,
      ),
    );
  }

  Future<void> updateVipInfo(UserPreferencesVipInfo vipInfo) async {
    await _persist(preferences.value.copyWith(vipInfo: vipInfo));
  }

  Future<void> updateFromLogin({
    required String accessToken,
    UserInfoResponse? me,
    UserInfoResponse? partner,
    VipInfo? vip,
  }) async {
    final userInfo = UserPreferences(
      accessToken: accessToken,
      meUserInfo: me,
      partnerUserInfo: partner,
      vipInfo: vip != null ? UserPreferencesVipInfo.fromVipInfo(vip) : null,
    );
    await _persist(userInfo);
    await _syncLoginInfoToNative(userInfo: userInfo);
  }

  Future<void> clearPartnerUserInfo() async {
    await _persist(preferences.value.copyWith(clearPartner: true));
  }

  Future<void> clear() async {
    await _prefs.remove(_storageKey);
    preferences.value = UserPreferences.empty;
  }
}