feat: analytics abstraction with debug backend and game event wiring

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 13:35:31 +09:00
parent 6d2d97bfcc
commit 074a21ea2b
7 changed files with 161 additions and 5 deletions
+5
View File
@@ -4,6 +4,7 @@ import '../data/content_repository.dart';
import '../data/save_repository.dart';
import '../data/streak.dart';
import '../game/models/season.dart';
import '../services/analytics_service.dart';
import '../services/audio_service.dart';
import 'endless_best_notifier.dart';
import 'game_session_notifier.dart';
@@ -66,6 +67,10 @@ final endlessBestProvider = NotifierProvider<EndlessBestNotifier, int>(
EndlessBestNotifier.new,
);
final analyticsProvider = Provider<AnalyticsService>(
(ref) => AnalyticsService(DebugAnalyticsBackend()),
);
/// The visual theme of whatever season is in play; fallback outside seasons
/// (home, endless). Pure model — UI converts via ThemeColors.
final activeThemeProvider = Provider<SeasonTheme>((ref) {
+4
View File
@@ -23,6 +23,10 @@ class SeasonFlowNotifier extends Notifier<SeasonFlow?> {
void startSeasonStage(SeasonPack pack, int index) {
state = SeasonFlow(pack: pack, index: index);
ref.read(gameSessionProvider.notifier).startStage(pack.stages[index]);
ref.read(analyticsProvider).stageStart(
seasonId: pack.seasonId,
stageId: pack.stages[index].id,
);
}
Future<void> recordWin({required int stars, required int score}) async {
+4 -3
View File
@@ -25,16 +25,17 @@ class TutorialNotifier extends Notifier<TutorialStep?> {
Future<void> dismissHud() async {
if (state != TutorialStep.explainHud) return;
await _finish();
await _finish(skipped: false);
}
Future<void> skip() async {
if (state == null) return;
await _finish();
await _finish(skipped: true);
}
Future<void> _finish() async {
Future<void> _finish({required bool skipped}) async {
state = null;
ref.read(analyticsProvider).tutorialFinished(skipped: skipped);
await ref.read(saveRepositoryProvider).markTutorialDone();
}
}