feat: session content sync trigger and newest-season selection

Add seasonRefreshProvider (once-per-session FutureProvider) and activeSeason()
helper; HomeScreen listens and invalidates seasonsProvider when new packs arrive;
season_map_screen and season_title_screen switch from list.first to activeSeason.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 13:28:39 +09:00
parent 73a56aeeb1
commit 4fa5564975
5 changed files with 76 additions and 2 deletions
+59
View File
@@ -0,0 +1,59 @@
import 'package:block_seasons/data/content_repository.dart';
import 'package:block_seasons/game/models/season.dart';
import 'package:block_seasons/game/models/stage.dart';
import 'package:block_seasons/state/providers.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
class _FakeRepo extends ContentRepository {
_FakeRepo(this.result);
final bool result;
int calls = 0;
@override
Future<bool> refresh() async {
calls++;
return result;
}
}
SeasonPack _pack(String id) => SeasonPack(
schemaVersion: 1,
seasonId: id,
version: 1,
title: const {'en': 'Test Season', 'ko': '테스트 시즌'},
theme: SeasonTheme.fallback,
stages: [
StageConfig(
id: 's1',
seed: 1,
moveLimit: 10,
preset: const [],
objectives: const [],
stars: const StarThresholds(twoMovesLeft: 2, threeMovesLeft: 4),
generatorProfile: 'mid',
),
],
);
void main() {
test('seasonRefreshProvider runs refresh once and exposes the result',
() async {
final repo = _FakeRepo(true);
final container = ProviderContainer(
overrides: [contentRepositoryProvider.overrideWithValue(repo)],
);
addTearDown(container.dispose);
expect(await container.read(seasonRefreshProvider.future), isTrue);
// Re-reading does not re-run (FutureProvider caches).
expect(await container.read(seasonRefreshProvider.future), isTrue);
expect(repo.calls, 1);
});
test('activeSeason picks the newest by id', () {
final p1 = _pack('season_001');
final p2 = _pack('season_002');
expect(activeSeason([p1, p2]).seasonId, 'season_002');
});
}