Files
arcx-app/lib/features/config/application/app_config_controller.dart
2026-08-08 10:57:54 +08:00

62 lines
2.0 KiB
Dart

import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../core/constants/app_defaults.dart';
import '../../../core/providers/app_providers.dart';
import '../../../data/local/models/models.dart';
final appConfigProvider =
AsyncNotifierProvider<AppConfigNotifier, AppConfig>(AppConfigNotifier.new);
class AppConfigNotifier extends AsyncNotifier<AppConfig> {
@override
Future<AppConfig> build() async {
final isar = await ref.watch(isarProvider.future);
final config = await isar.appConfigs.get(AppDefaults.singletonId);
if (config != null) return config;
final fresh = AppConfig.createDefault();
await isar.writeTxn(() => isar.appConfigs.put(fresh));
return fresh;
}
Future<AppConfig> _persist(AppConfig config) async {
final isar = await ref.read(isarProvider.future);
await isar.writeTxn(() => isar.appConfigs.put(config));
state = AsyncData(config);
return config;
}
/// Called after a scoring session is saved successfully.
Future<void> incrementTrialCount() async {
final current = state.value;
if (current == null || current.isVipUnlocked) return;
final next = current.copyWith(
usedTrialCount: current.usedTrialCount + 1,
);
await _persist(next);
}
/// Marks the app as unlocked via IAP purchase or restore.
Future<void> markUnlocked({required bool fromRestore}) async {
final current = state.value;
if (current == null) return;
final next = current.copyWith(
isVipUnlocked: true,
vipUnlockedAt: DateTime.now(),
entitlementSource:
fromRestore ? EntitlementSource.restore : EntitlementSource.purchase,
);
await _persist(next);
}
Future<void> setLastError(String? message) async {
final current = state.value;
if (current == null) return;
await _persist(current.copyWith(lastIapErrorMessage: message));
}
/// Debug-only: instantly unlock without going through App Store.
Future<void> debugUnlock() async {
await markUnlocked(fromRestore: false);
}
}