feat: watch together buffering indicators

This commit is contained in:
edde746
2026-04-14 22:07:13 +02:00
parent 6eb5c847af
commit 1e1bb9176a
35 changed files with 192 additions and 45 deletions
@@ -352,6 +352,7 @@ class _ParticipantNotificationOverlayState extends State<ParticipantNotification
ParticipantEventType.paused => t.watchTogether.participantPaused(name: n.event.displayName),
ParticipantEventType.resumed => t.watchTogether.participantResumed(name: n.event.displayName),
ParticipantEventType.seeked => t.watchTogether.participantSeeked(name: n.event.displayName),
ParticipantEventType.buffering => t.watchTogether.participantBuffering(name: n.event.displayName),
};
return Container(
margin: const EdgeInsets.only(bottom: 4),
@@ -381,41 +382,67 @@ class SyncingIndicator extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer<WatchTogetherProvider>(
builder: (context, provider, child) {
if (!provider.isSyncing) {
return const SizedBox.shrink();
}
return Positioned(
bottom: 80,
left: 0,
right: 0,
child: Center(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: const BoxDecoration(
color: Colors.black54,
borderRadius: BorderRadius.all(Radius.circular(20)),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 14,
height: 14,
child: PlatformDetector.isTV()
? const Icon(Symbols.sync_rounded, size: 14, color: Colors.white)
: const CircularProgressIndicator(strokeWidth: 2, color: Colors.white),
),
const SizedBox(width: 8),
Text(t.watchTogether.syncing, style: const TextStyle(color: Colors.white, fontSize: 12)),
],
),
),
),
);
return Selector<WatchTogetherProvider, bool>(
selector: (_, provider) => provider.isSyncing,
builder: (context, isSyncing, child) {
if (!isSyncing) return const SizedBox.shrink();
return _StatusPill(tvIcon: Symbols.sync_rounded, label: t.watchTogether.syncing);
},
);
}
}
/// Indicator shown when playback is deferred waiting for participants to load
class WaitingForParticipantsIndicator extends StatelessWidget {
const WaitingForParticipantsIndicator({super.key});
@override
Widget build(BuildContext context) {
return Selector<WatchTogetherProvider, bool>(
selector: (_, provider) => provider.isDeferredPlay,
builder: (context, isDeferredPlay, child) {
if (!isDeferredPlay) return const SizedBox.shrink();
return _StatusPill(tvIcon: Symbols.hourglass_empty_rounded, label: t.watchTogether.waitingForParticipants);
},
);
}
}
class _StatusPill extends StatelessWidget {
final IconData tvIcon;
final String label;
const _StatusPill({required this.tvIcon, required this.label});
@override
Widget build(BuildContext context) {
return Positioned(
bottom: 80,
left: 0,
right: 0,
child: Center(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: const BoxDecoration(
color: Colors.black54,
borderRadius: BorderRadius.all(Radius.circular(20)),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 14,
height: 14,
child: PlatformDetector.isTV()
? Icon(tvIcon, size: 14, color: Colors.white)
: const CircularProgressIndicator(strokeWidth: 2, color: Colors.white),
),
const SizedBox(width: 8),
Text(label, style: const TextStyle(color: Colors.white, fontSize: 12)),
],
),
),
),
);
}
}