Jellyfin rows reload after watching: the Stopped report clears the server's cached lists
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
86eb30f498
commit
1508d2f804
5 files changed
+30
-3
No files matched your search
@@ -543,6 +543,17 @@ class JellyfinAccounts extends ChangeNotifier {
|
|||||||
/// Drops cached browse results (refresh button, after a pick).
|
/// Drops cached browse results (refresh button, after a pick).
|
||||||
void invalidate(String serverId) => _clearMemo(serverId);
|
void invalidate(String serverId) => _clearMemo(serverId);
|
||||||
|
|
||||||
|
final _watched = StreamController<String>.broadcast();
|
||||||
|
|
||||||
|
/// Server ids whose watched state this app just changed (a stop report):
|
||||||
|
/// their cached lists are gone, and browse views reload.
|
||||||
|
Stream<String> get watched => _watched.stream;
|
||||||
|
|
||||||
|
void watchedChanged(String serverId) {
|
||||||
|
_clearMemo(serverId);
|
||||||
|
_watched.add(serverId);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
|
|||||||
@@ -157,7 +157,14 @@ class BrowseController extends ChangeNotifier {
|
|||||||
final JellyfinAccounts accounts;
|
final JellyfinAccounts accounts;
|
||||||
/// Clock for the Continue row's age cut-off (tests pin it).
|
/// Clock for the Continue row's age cut-off (tests pin it).
|
||||||
final DateTime Function() now;
|
final DateTime Function() now;
|
||||||
BrowseController(this.accounts, {this.now = DateTime.now});
|
BrowseController(this.accounts, {this.now = DateTime.now}) {
|
||||||
|
// Back from watching: the rows show what was just watched.
|
||||||
|
_watchedSub = accounts.watched.listen((id) {
|
||||||
|
if (!_disposed && id == serverId) dataChanged();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
late final StreamSubscription<String> _watchedSub;
|
||||||
|
|
||||||
String? _serverId;
|
String? _serverId;
|
||||||
List<BrowseRoute> _stack = const [HomeRoute()];
|
List<BrowseRoute> _stack = const [HomeRoute()];
|
||||||
@@ -259,6 +266,7 @@ class BrowseController extends ChangeNotifier {
|
|||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
|
unawaited(_watchedSub.cancel());
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ class JellyfinProgressReporter {
|
|||||||
this.interval = const Duration(seconds: 10),
|
this.interval = const Duration(seconds: 10),
|
||||||
this.onError,
|
this.onError,
|
||||||
this.onUnauthorized,
|
this.onUnauthorized,
|
||||||
|
this.onStopped,
|
||||||
DateTime Function()? clock,
|
DateTime Function()? clock,
|
||||||
}) : _clock = clock ?? DateTime.now,
|
}) : _clock = clock ?? DateTime.now,
|
||||||
_keepPlayed = playedBefore,
|
_keepPlayed = playedBefore,
|
||||||
@@ -67,6 +68,10 @@ class JellyfinProgressReporter {
|
|||||||
/// marks an item played past its "max resume" share (90 % by default).
|
/// marks an item played past its "max resume" share (90 % by default).
|
||||||
static const _noPositionFrom = 0.85;
|
static const _noPositionFrom = 0.85;
|
||||||
|
|
||||||
|
/// After Stopped (and a mark played) went out: the item's watched
|
||||||
|
/// state on the server may differ from what lists show.
|
||||||
|
final void Function()? onStopped;
|
||||||
|
|
||||||
Future<void> _chain = Future.value();
|
Future<void> _chain = Future.value();
|
||||||
bool _playing = false;
|
bool _playing = false;
|
||||||
bool _dead = false;
|
bool _dead = false;
|
||||||
@@ -178,7 +183,7 @@ class JellyfinProgressReporter {
|
|||||||
itemId: itemId, mediaSourceId: source.id, playSessionId: playSessionId, positionTicks: ticks);
|
itemId: itemId, mediaSourceId: source.id, playSessionId: playSessionId, positionTicks: ticks);
|
||||||
_send('Stopped', () => client.reportPlaybackStopped(report));
|
_send('Stopped', () => client.reportPlaybackStopped(report));
|
||||||
if (ticks == null) _send('played', () => client.markPlayed(itemId));
|
if (ticks == null) _send('played', () => client.markPlayed(itemId));
|
||||||
return _chain;
|
return _chain = _chain.then((_) => onStopped?.call());
|
||||||
}
|
}
|
||||||
|
|
||||||
void _mark(PlayerSnapshot s) {
|
void _mark(PlayerSnapshot s) {
|
||||||
|
|||||||
@@ -1750,6 +1750,7 @@ class SessionCoordinator {
|
|||||||
playedBefore: before?.played ?? false,
|
playedBefore: before?.played ?? false,
|
||||||
resumeTicksBefore: before?.playbackPositionTicks ?? 0,
|
resumeTicksBefore: before?.playbackPositionTicks ?? 0,
|
||||||
onUnauthorized: () => jellyfin.markExpired(ref.serverId),
|
onUnauthorized: () => jellyfin.markExpired(ref.serverId),
|
||||||
|
onStopped: () => jellyfin.watchedChanged(ref.serverId),
|
||||||
onError: (e) {
|
onError: (e) {
|
||||||
if (_jfToastShown) return;
|
if (_jfToastShown) return;
|
||||||
_jfToastShown = true;
|
_jfToastShown = true;
|
||||||
|
|||||||
@@ -1268,7 +1268,9 @@ Jellyfin on the desktop (`lib/src/jellyfin/`, over the core client):
|
|||||||
series) kept alive under `Visibility(maintainState)` so back keeps
|
series) kept alive under `Visibility(maintainState)` so back keeps
|
||||||
scroll and loaded pages; search (300 ms debounce) overlays them. Where
|
scroll and loaded pages; search (300 ms debounce) overlays them. Where
|
||||||
it is (server, stack, a data version that moves after watched-state
|
it is (server, stack, a data version that moves after watched-state
|
||||||
changes so rows reload in place, the Continue keys) is a
|
changes so rows reload in place — a change from the details panel, or
|
||||||
|
`JellyfinAccounts.watched` once a playback's Stopped report went out —,
|
||||||
|
the Continue keys) is a
|
||||||
`BrowseController` shared with the header chips and the details panel.
|
`BrowseController` shared with the header chips and the details panel.
|
||||||
Cards (`cards.dart`) fill the width with whole columns (`fitColumns`);
|
Cards (`cards.dart`) fill the width with whole columns (`fitColumns`);
|
||||||
rows are `HScroll`s, rows and grids lazy builders; library grids page
|
rows are `HScroll`s, rows and grids lazy builders; library grids page
|
||||||
|
|||||||
Reference in new issue
Block a user