forked from Foxyz/sync_replay_project
Restructure step 3: your server, Invite, version gate, AppGraph
- One server per app run (loopback, no password); Invite attaches an all-interfaces listener to the same server and Stop sharing detaches it (guests told with 4016); members, media and Up next never reset. No solo mode: you're home on your own server unless in a friend's. - Navigation: none / yours / friend; a join passes a version gate on /health first (clear "they/you need to update", update offer). - Invite as a value (host, port, name, password flag, version, fp reserved); addresses filtered (loopback, link-local, 198.18/15, bridges) and ranked; Sharing chip, Copy invite, Stop sharing. - Alone looks like a plain player (alone replaces solo). - AppGraph builds and disposes systems; widgets use AppScope; SessionState deleted; a test caps the remaining singletons. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
629be0d9ed
commit
4d00b7455e
86 files changed
+2993
-2071
No files matched your search
@@ -21,6 +21,11 @@ import 'package:starsync/src/shell/library_tab.dart' show putUpJellyfinMedia;
|
||||
import 'jellyfin_accounts_test.dart';
|
||||
import 'jellyfin_browser_test.dart' show app, setSize, settle;
|
||||
|
||||
import 'test_graph.dart';
|
||||
|
||||
/// This file's composition root (see test_graph.dart).
|
||||
final _graph = testGraph();
|
||||
|
||||
const episodeId = 'b18826be994070a79f9b52bc0f66f052'; // Black Summoner S1E6
|
||||
const nextEpisodeId = '74c50bdbf83e8fef231dd7710058e197'; // S1E7
|
||||
const seriesId = 'e9aec9c14a1fcab775111844112b4cf7';
|
||||
@@ -485,7 +490,7 @@ void main() {
|
||||
SeriesRoute(const JellyfinItem(id: arifuretaId, name: 'Arifureta', type: 'Series'),
|
||||
seasonId: season2Id),
|
||||
]));
|
||||
await tester.pumpWidget(app(JellyfinBrowser(accounts: accounts, onSelect: (_) {}, onPutUp: (_) {})));
|
||||
await tester.pumpWidget(scoped(_graph, app(JellyfinBrowser(accounts: accounts, onSelect: (_) {}, onPutUp: (_) {}))));
|
||||
await settle(tester);
|
||||
final s2 = tester.widget<ChoiceChip>(find.byKey(const ValueKey('season-$season2Id')));
|
||||
expect(s2.selected, isTrue);
|
||||
@@ -506,18 +511,18 @@ void main() {
|
||||
|
||||
testWidgets('end card: Next prompt, countdown with Cancel', (tester) async {
|
||||
var play = 0, cancel = 0;
|
||||
await tester.pumpWidget(app(EndOfEpisodeCard(
|
||||
next: next, countdown: null, onPlayNow: () => play++, onCancel: () => cancel++)));
|
||||
await tester.pumpWidget(scoped(_graph, app(EndOfEpisodeCard(
|
||||
next: next, countdown: null, onPlayNow: () => play++, onCancel: () => cancel++))));
|
||||
expect(find.text('Next: S1E7 Battle with the Heroes'), findsOneWidget);
|
||||
expect(find.byKey(const ValueKey('auto-advance-cancel')), findsNothing);
|
||||
await tester.tap(find.byKey(const ValueKey('play-next')));
|
||||
expect(play, 1);
|
||||
|
||||
await tester.pumpWidget(app(EndOfEpisodeCard(
|
||||
await tester.pumpWidget(scoped(_graph, app(EndOfEpisodeCard(
|
||||
next: next,
|
||||
countdown: AutoAdvance(mediaId: 3, secondsLeft: 7, next: next, swapper: false),
|
||||
onPlayNow: () => play++,
|
||||
onCancel: () => cancel++)));
|
||||
onCancel: () => cancel++))));
|
||||
expect(find.text('Next episode in 7 s'), findsOneWidget);
|
||||
await tester.tap(find.byKey(const ValueKey('auto-advance-cancel')));
|
||||
expect(cancel, 1);
|
||||
@@ -525,7 +530,7 @@ void main() {
|
||||
|
||||
testWidgets('next-episode pill: faint at rest, lit on hover, click puts it up', (tester) async {
|
||||
var pressed = 0;
|
||||
await tester.pumpWidget(app(Align(child: NextEpisodePill(episode: next, onPressed: () => pressed++))));
|
||||
await tester.pumpWidget(scoped(_graph, app(Align(child: NextEpisodePill(episode: next, onPressed: () => pressed++)))));
|
||||
double opacity() => tester.widget<AnimatedOpacity>(find.descendant(
|
||||
of: find.byType(NextEpisodePill), matching: find.byType(AnimatedOpacity))).opacity;
|
||||
expect(opacity(), lessThan(0.5));
|
||||
@@ -541,10 +546,10 @@ void main() {
|
||||
|
||||
testWidgets('blocked card offers to link an account', (tester) async {
|
||||
var link = 0;
|
||||
await tester.pumpWidget(app(JellyfinBlockedCard(
|
||||
await tester.pumpWidget(scoped(_graph, app(JellyfinBlockedCard(
|
||||
blocked: const BlockedPlay(serverId: fixtureServerId, serverName: 'Example Server'),
|
||||
onLinkAccount: () => link++,
|
||||
onRetry: () {})));
|
||||
onRetry: () {}))));
|
||||
expect(find.text('No Jellyfin account here for Example Server, and nobody is passing it on'),
|
||||
findsOneWidget);
|
||||
await tester.tap(find.byKey(const ValueKey('link-jellyfin-account')));
|
||||
|
||||
Reference in new issue
Block a user