Skip to content

Commit

Permalink
feat: Press late label to dismiss the late video automatically
Browse files Browse the repository at this point in the history
  • Loading branch information
bdlukaa committed Feb 6, 2024
1 parent 07d30a2 commit 1eb92f4
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 72 deletions.
15 changes: 13 additions & 2 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -488,10 +488,21 @@
"contain": "Contain",
"fill": "Fill",
"cover": "Cover",
"@@Late stream behavior": {},
"lateStreamBehavior": "Late stream behavior",
"lateStreamBehaviorDescription": "What to do when a stream is late",
"automatic": "Automatic",
"manual": "Manual",
"automaticBehavior": "Automatic",
"automaticBehaviorDescription": "The app will try to reposition the stream automatically",
"manualBehavior": "Manual",
"manualBehaviorDescription": "Press {label} to reposition the stream",
"@manualBehaviorDescription": {
"placeholders": {
"label": {
"type": "String"
}
}
},
"neverBehaviorDescription": "The app will not try to reposition the stream",
"@@LOCALIZATION": {},
"dateLanguage": "Date and Language",
"language": "Language",
Expand Down
15 changes: 13 additions & 2 deletions lib/l10n/app_fr.arb
Original file line number Diff line number Diff line change
Expand Up @@ -462,10 +462,21 @@
"contain": "Contenir",
"fill": "Remplir",
"cover": "Couvrir",
"@@Late stream behavior": {},
"lateStreamBehavior": "Late stream behavior",
"lateStreamBehaviorDescription": "What to do when a stream is late",
"automatic": "Automatic",
"manual": "Manual",
"automaticBehavior": "Automatic",
"automaticBehaviorDescription": "The app will try to reposition the stream automatically",
"manualBehavior": "Manual",
"manualBehaviorDescription": "Press {label} to reposition the stream",
"@manualBehaviorDescription": {
"placeholders": {
"label": {
"type": "String"
}
}
},
"neverBehaviorDescription": "The app will not try to reposition the stream",
"@@LOCALIZATION": {},
"dateLanguage": "Date et Langue",
"language": "Langue",
Expand Down
15 changes: 13 additions & 2 deletions lib/l10n/app_pl.arb
Original file line number Diff line number Diff line change
Expand Up @@ -488,10 +488,21 @@
"contain": "Zawartość",
"fill": "Wypełnienie",
"cover": "Pokrycie",
"@@Late stream behavior": {},
"lateStreamBehavior": "Late stream behavior",
"lateStreamBehaviorDescription": "What to do when a stream is late",
"automatic": "Automatic",
"manual": "Manual",
"automaticBehavior": "Automatic",
"automaticBehaviorDescription": "The app will try to reposition the stream automatically",
"manualBehavior": "Manual",
"manualBehaviorDescription": "Press {label} to reposition the stream",
"@manualBehaviorDescription": {
"placeholders": {
"label": {
"type": "String"
}
}
},
"neverBehaviorDescription": "The app will not try to reposition the stream",
"@@LOCALIZATION": {},
"dateLanguage": "Date and Language",
"language": "Language",
Expand Down
15 changes: 13 additions & 2 deletions lib/l10n/app_pt.arb
Original file line number Diff line number Diff line change
Expand Up @@ -488,10 +488,21 @@
"contain": "Limitar",
"fill": "Preencher",
"cover": "Cobrir",
"@@Late stream behavior": {},
"lateStreamBehavior": "Transmissão atrasada",
"lateStreamBehaviorDescription": "O que fazer quando a transmissão está atrasada.",
"automatic": "Automático",
"manual": "Manual",
"automaticBehavior": "Automático",
"automaticBehaviorDescription": "A transmissão será reajustada automaticamente",
"manualBehavior": "Manual",
"manualBehaviorDescription": "Pressione {label} para reposicionar a transmissão",
"@manualBehaviorDescription": {
"placeholders": {
"label": {
"type": "String"
}
}
},
"neverBehaviorDescription": "A transmissão não será reajustada",
"@@LOCALIZATION": {},
"dateLanguage": "Data e Idioma",
"language": "Idioma",
Expand Down
4 changes: 2 additions & 2 deletions lib/providers/settings_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -405,8 +405,8 @@ extension LateVideoBehaviorExtension on LateVideoBehavior {
String locale(BuildContext context) {
final loc = AppLocalizations.of(context);
return switch (this) {
LateVideoBehavior.automatic => loc.automatic,
LateVideoBehavior.manual => loc.manual,
LateVideoBehavior.automatic => loc.automaticBehavior,
LateVideoBehavior.manual => loc.manualBehavior,
LateVideoBehavior.never => loc.never,
};
}
Expand Down
131 changes: 70 additions & 61 deletions lib/widgets/device_grid/video_status_label.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class VideoStatusLabel extends StatefulWidget {
State<VideoStatusLabel> createState() => _VideoStatusLabelState();
}

enum _VideoLabel {
enum VideoLabel {
/// When the video hasn't loaded any frame yet.
loading,

Expand Down Expand Up @@ -77,17 +77,17 @@ class _VideoStatusLabelState extends State<VideoStatusLabel> {
_source.contains('media/mjpeg') ||
_source.contains('.m3u8') /* hls */);

_VideoLabel get status => widget.video.error != null
? _VideoLabel.error
VideoLabel get status => widget.video.error != null
? VideoLabel.error
: isLoading
? _VideoLabel.loading
? VideoLabel.loading
: !isLive
? _VideoLabel.recorded
? VideoLabel.recorded
: widget.video.player.isImageOld
? _VideoLabel.timedOut
? VideoLabel.timedOut
: widget.video.player.isLate
? _VideoLabel.late
: _VideoLabel.live;
? VideoLabel.late
: VideoLabel.live;

bool _openWithTap = false;
OverlayEntry? entry;
Expand Down Expand Up @@ -147,28 +147,8 @@ class _VideoStatusLabelState extends State<VideoStatusLabel> {

@override
Widget build(BuildContext context) {
final loc = AppLocalizations.of(context);
final theme = Theme.of(context);
final settings = context.watch<SettingsProvider>();

final text = switch (status) {
_VideoLabel.live => loc.live,
_VideoLabel.loading => loc.loading,
_VideoLabel.recorded => loc.recorded,
_VideoLabel.timedOut => loc.timedOut,
_VideoLabel.error => loc.error,
_VideoLabel.late => loc.late,
};

final color = switch (status) {
_VideoLabel.live => Colors.red.shade600,
_VideoLabel.loading => Colors.blue,
_VideoLabel.recorded => Colors.green,
_VideoLabel.timedOut => Colors.amber.shade600,
_VideoLabel.error => Colors.grey,
_VideoLabel.late => Colors.purple,
};

// This opens the overlay when a property is updated. This is a frame late
if (isOverlayOpen) {
WidgetsBinding.instance.addPostFrameCallback((_) {
Expand All @@ -177,7 +157,7 @@ class _VideoStatusLabelState extends State<VideoStatusLabel> {
});
}

final isLateDismissal = status == _VideoLabel.late &&
final isLateDismissal = status == VideoLabel.late &&
settings.lateVideoBehavior == LateVideoBehavior.manual;

return MouseRegion(
Expand All @@ -197,48 +177,77 @@ class _VideoStatusLabelState extends State<VideoStatusLabel> {
showOverlay();
}
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 500),
padding: const EdgeInsetsDirectional.symmetric(
horizontal: 4.0,
vertical: 2.0,
),
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(4.0),
),
child: Row(mainAxisSize: MainAxisSize.min, children: [
if (status == _VideoLabel.loading)
const Padding(
padding: EdgeInsetsDirectional.only(end: 8.0),
child: SizedBox(
height: 12.0,
width: 12.0,
child: CircularProgressIndicator.adaptive(
strokeWidth: 1.5,
valueColor: AlwaysStoppedAnimation(Colors.white),
),
),
),
Text(
text,
style: theme.textTheme.labelSmall?.copyWith(
color: color.computeLuminance() > 0.5
? Colors.black
: Colors.white,
child: VideoStatusLabelIndicator(status: status),
),
);
}
}

class VideoStatusLabelIndicator extends StatelessWidget {
final VideoLabel status;

const VideoStatusLabelIndicator({super.key, required this.status});

@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final loc = AppLocalizations.of(context);
final text = switch (status) {
VideoLabel.live => loc.live,
VideoLabel.loading => loc.loading,
VideoLabel.recorded => loc.recorded,
VideoLabel.timedOut => loc.timedOut,
VideoLabel.error => loc.error,
VideoLabel.late => loc.late,
};

final color = switch (status) {
VideoLabel.live => Colors.red.shade600,
VideoLabel.loading => Colors.blue,
VideoLabel.recorded => Colors.green,
VideoLabel.timedOut => Colors.amber.shade600,
VideoLabel.error => Colors.grey,
VideoLabel.late => Colors.purple,
};

return AnimatedContainer(
duration: const Duration(milliseconds: 500),
padding: const EdgeInsetsDirectional.symmetric(
horizontal: 4.0,
vertical: 2.0,
),
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(4.0),
),
child: Row(mainAxisSize: MainAxisSize.min, children: [
if (status == VideoLabel.loading)
const Padding(
padding: EdgeInsetsDirectional.only(end: 8.0),
child: SizedBox(
height: 12.0,
width: 12.0,
child: CircularProgressIndicator.adaptive(
strokeWidth: 1.5,
valueColor: AlwaysStoppedAnimation(Colors.white),
),
),
]),
),
Text(
text,
style: theme.textTheme.labelSmall?.copyWith(
color: color.computeLuminance() > 0.5 ? Colors.black : Colors.white,
),
),
),
]),
);
}
}

class _DeviceVideoInfo extends StatelessWidget {
final Device device;
final VideoViewInheritance video;
final _VideoLabel label;
final VideoLabel label;
final bool isLive;

final Event? event;
Expand Down
52 changes: 51 additions & 1 deletion lib/widgets/settings/desktop/server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import 'package:bluecherry_client/providers/settings_provider.dart';
import 'package:bluecherry_client/utils/extensions.dart';
import 'package:bluecherry_client/widgets/device_grid/video_status_label.dart';
import 'package:bluecherry_client/widgets/settings/desktop/settings.dart';
import 'package:bluecherry_client/widgets/settings/mobile/settings.dart';
import 'package:flutter/material.dart';
Expand Down Expand Up @@ -125,6 +126,7 @@ class CamerasSettings extends StatelessWidget {

@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final settings = context.watch<SettingsProvider>();
final loc = AppLocalizations.of(context);
return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Expand Down Expand Up @@ -180,7 +182,55 @@ class CamerasSettings extends StatelessWidget {
borderRadius: BorderRadius.circular(6.0),
child: ListTile(
title: Text(loc.lateStreamBehavior),
subtitle: Text(loc.lateStreamBehaviorDescription),
subtitle: RichText(
text: TextSpan(
text: loc.lateStreamBehaviorDescription,
style: theme.textTheme.bodyMedium,
children: [
const TextSpan(text: '\n'),
switch (settings.lateVideoBehavior) {
LateVideoBehavior.automatic => TextSpan(
text: loc.automaticBehaviorDescription,
style: const TextStyle(fontWeight: FontWeight.w600),
),
LateVideoBehavior.manual => TextSpan(
children: [
...() {
final list = loc
.manualBehaviorDescription(
'manualBehaviorDescription',
)
.split(' ');

return list.map((part) {
if (part == 'manualBehaviorDescription') {
return const WidgetSpan(
child: Padding(
padding: EdgeInsetsDirectional.only(
start: 2.0,
end: 6.0,
),
child: VideoStatusLabelIndicator(
status: VideoLabel.late,
),
),
);
} else {
return TextSpan(text: '$part ');
}
});
}()
],
style: const TextStyle(fontWeight: FontWeight.w600),
),
LateVideoBehavior.never => TextSpan(
text: loc.neverBehaviorDescription,
style: const TextStyle(fontWeight: FontWeight.w600),
)
},
],
),
),
trailing: DropdownButton<LateVideoBehavior>(
value: settings.lateVideoBehavior,
onChanged: (v) {
Expand Down

0 comments on commit 1eb92f4

Please sign in to comment.