user_account_storage.dart 3.84 KB
import 'package:shared_preferences/shared_preferences.dart';

/// 账号级持久化存储。
///
/// 与 [UserPreferencesStorage] 的区别:
/// - [UserPreferencesStorage] 存储会话数据,退登时 clear() 会全部清除。
/// - [UserAccountStorage] 存储账号元数据,退登不清除,按 userId 隔离。
///
/// 适合存储:新手引导进度、账号历史记录等跨会话数据。
class UserAccountStorage {
  UserAccountStorage(this._prefs);

  final SharedPreferences _prefs;

  // ─── Keys ──────────────────────────────────────────────────────────────────

  /// Onboarding 阶段 key,按 userId 隔离
  static String _onboardingKey(int userId) =>
      'account_onboarding_stage_$userId';

  /// Apple Health 上传时间记录 key,按 userId 隔离。
  static String _appleHealthUploadRecordKey(int userId) =>
      'apple_health_upload_local_records_$userId';

  /// Apple Health 上传测试页上次同步时间 key,按 userId 隔离。
  static String _appleHealthUploadTestLastSyncTimeKey(int userId) =>
      'apple_health_upload_test_last_sync_time_$userId';

  /// Onboarding 已全部完成的哨兵值
  static const int _kOnboardingCompleted = -1;

  // ─── Onboarding 阶段 ───────────────────────────────────────────────────────
  //
  // 存储规则:
  //   null(key 不存在)  → 从未开始
  //   0 ~ N(页码)       → 进行中,记录上次停留的页码
  //   -1(kCompleted)    → 已全部完成
  //
  // 状态机:
  //   null ──[进入引导]──▶ 0 ──[翻页]──▶ 1 ... N ──[完成]──▶ -1
  //    ↑                                                        │
  //    └───────────────────[resetOnboarding]───────────────────┘

  /// 是否已完成全部引导流程。
  bool hasCompletedOnboarding(int userId) =>
      _prefs.getInt(_onboardingKey(userId)) == _kOnboardingCompleted;

  /// 是否已开始过引导(包括进行中和已完成)。
  bool hasStartedOnboarding(int userId) =>
      _prefs.getInt(_onboardingKey(userId)) != null;

  /// 中途退出时上次停留的页码;null 表示从未开始或已完成。
  int? onboardingResumeStage(int userId) {
    final v = _prefs.getInt(_onboardingKey(userId));
    if (v == null || v == _kOnboardingCompleted) return null;
    return v;
  }

  /// 每次翻页时调用,保存当前页码进度。
  Future<void> saveOnboardingStage(int userId, int pageIndex) =>
      _prefs.setInt(_onboardingKey(userId), pageIndex);

  /// 引导全部完成时调用。
  Future<void> markOnboardingCompleted(int userId) =>
      _prefs.setInt(_onboardingKey(userId), _kOnboardingCompleted);

  // ─── Apple Health 上传记录 ────────────────────────────────────────────────

  String? appleHealthUploadLocalRecordJson(int userId) =>
      _prefs.getString(_appleHealthUploadRecordKey(userId));

  Future<void> saveAppleHealthUploadLocalRecordJson(
    int userId,
    String value,
  ) =>
      _prefs.setString(_appleHealthUploadRecordKey(userId), value);

  Future<void> clearAppleHealthUploadLocalRecord(int userId) =>
      _prefs.remove(_appleHealthUploadRecordKey(userId));

  int? appleHealthUploadTestLastSyncTime(int userId) =>
      _prefs.getInt(_appleHealthUploadTestLastSyncTimeKey(userId));

  Future<void> saveAppleHealthUploadTestLastSyncTime(
    int userId,
    int latestSyncTime,
  ) =>
      _prefs.setInt(
        _appleHealthUploadTestLastSyncTimeKey(userId),
        latestSyncTime,
      );
}