Skip to content

Commit

Permalink
feat: Event Video Magnification (bluecherrydvr#252)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdlukaa authored Jul 25, 2024
2 parents 26770a0 + e07cfb3 commit 6dbc1fd
Show file tree
Hide file tree
Showing 19 changed files with 309 additions and 138 deletions.
14 changes: 8 additions & 6 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -547,14 +547,16 @@
"privacyPolicy": "Privacy Policy",
"termsOfService": "Terms of Service",
"@@ADVANCED_OPTIONS": {},
"matrixZoom": "Area Magnification",
"matrixedViewZoom": "Area Magnification enabled",
"matrixedViewZoomDescription": "Magnify a area of the matrix view when selected. This is useful when you have a lot of cameras and want to see a specific area in more detail, or when a multicast stream is provided.",
"matrixMagnification": "Area Magnification",
"matrixedViewMagnification": "Area Magnification enabled",
"matrixedViewMagnificationDescription": "Magnify a area of the matrix view when selected. This is useful when you have a lot of cameras and want to see a specific area in more detail, or when a multicast stream is provided.",
"matrixType": "Matrix type",
"defaultMatrixSize": "Default Magnification Proportion",
"softwareZoom": "Software zoom",
"softwareZoomDescription": "When enabled, the magnification will not happen in the GPU. This is useful when the hardware magnification is not working properly.",
"softwareZoomDescriptionMacOS": "When enabled, the magnification will not happen in the GPU. This is useful when the hardware magnification is not working properly. On macOS, this can not be disabled.",
"softwareMagnification": "Software Magnification",
"softwareMagnificationDescription": "When enabled, the magnification will not happen in the GPU. This is useful when the hardware magnification is not working properly.",
"softwareMagnificationDescriptionMacOS": "When enabled, the magnification will not happen in the GPU. This is useful when the hardware magnification is not working properly. On macOS, this can not be disabled.",
"eventMagnification": "Event Magnification",
"eventMagnificationDescription": "Magnify the event video when selected. This is useful when you want to see the event in more detail.",
"developerOptions": "Developer options",
"openLogFile": "Open log file",
"openAppDataDirectory": "Open app data directory",
Expand Down
14 changes: 8 additions & 6 deletions lib/l10n/app_fr.arb
Original file line number Diff line number Diff line change
Expand Up @@ -523,14 +523,16 @@
"privacyPolicy": "Politique de confidentialité",
"termsOfService": "Conditions 'utilisations",
"@@ADVANCED_OPTIONS": {},
"matrixZoom": "Zoom aatriciel",
"matrixedViewZoom": "Vue zoom matriciel",
"matrixedViewZoomDescription": "Zoomer sur une zone matricielle de 16x16 pour voir plus de détails.",
"matrixMagnification": "Area Magnification",
"matrixedViewMagnification": "Area Magnification enabled",
"matrixedViewMagnificationDescription": "Magnify a area of the matrix view when selected. This is useful when you have a lot of cameras and want to see a specific area in more detail, or when a multicast stream is provided.",
"matrixType": "Type de matrice",
"defaultMatrixSize": "Taille de matrice par défaut",
"softwareZoom": "Zoom logiciel",
"softwareZoomDescription": "Lorsque activé, le zoom matriciel n'utilisera pas le GPU. Cette option est utile lorsque le zoom matériel ne fonctionne pas correctement.",
"softwareZoomDescriptionMacOS": "Lorsque activé, le zoom matriciel n'utilisera pas le GPU. Cette option est utile lorsque le zoom matériel ne fonctionne pas correctement. Sur macOS, cette option ne peut être désactivée.",
"softwareMagnification": "Software Magnification",
"softwareMagnificationDescription": "When enabled, the magnification will not happen in the GPU. This is useful when the hardware magnification is not working properly.",
"softwareMagnificationDescriptionMacOS": "When enabled, the magnification will not happen in the GPU. This is useful when the hardware magnification is not working properly. On macOS, this can not be disabled.",
"eventMagnification": "Event Magnification",
"eventMagnificationDescription": "Magnify the event video when selected. This is useful when you want to see the event in more detail.",
"developerOptions": "Options de développement",
"openLogFile": "Ovrir les fichiers logs",
"openAppDataDirectory": "Ouvrir le répertoir de l'application",
Expand Down
14 changes: 8 additions & 6 deletions lib/l10n/app_pl.arb
Original file line number Diff line number Diff line change
Expand Up @@ -547,14 +547,16 @@
"privacyPolicy": "Privacy Policy",
"termsOfService": "Terms of Service",
"@@ADVANCED_OPTIONS": {},
"matrixZoom": "Matrix Zoom",
"matrixedViewZoom": "Matrixed view zoom",
"matrixedViewZoomDescription": "Zoom in on a 16x16 matrixed view to see more detail.",
"matrixMagnification": "Area Magnification",
"matrixedViewMagnification": "Area Magnification enabled",
"matrixedViewMagnificationDescription": "Magnify a area of the matrix view when selected. This is useful when you have a lot of cameras and want to see a specific area in more detail, or when a multicast stream is provided.",
"matrixType": "Matrix type",
"defaultMatrixSize": "Default Matrix Size",
"softwareZoom": "Software zoom",
"softwareZoomDescription": "When enabled, the matrix zoom will not happen in the GPU. This is useful when the hardware zoom is not working properly.",
"softwareZoomDescriptionMacOS": "When enabled, the matrix zoom will not happen in the GPU. This is useful when the hardware zoom is not working properly. On macOS, this can not be disabled.",
"softwareMagnification": "Software Magnification",
"softwareMagnificationDescription": "When enabled, the magnification will not happen in the GPU. This is useful when the hardware magnification is not working properly.",
"softwareMagnificationDescriptionMacOS": "When enabled, the magnification will not happen in the GPU. This is useful when the hardware magnification is not working properly. On macOS, this can not be disabled.",
"eventMagnification": "Event Magnification",
"eventMagnificationDescription": "Magnify the event video when selected. This is useful when you want to see the event in more detail.",
"developerOptions": "Developer options",
"openLogFile": "Open log file",
"openAppDataDirectory": "Open app data directory",
Expand Down
14 changes: 8 additions & 6 deletions lib/l10n/app_pt.arb
Original file line number Diff line number Diff line change
Expand Up @@ -547,14 +547,16 @@
"privacyPolicy": "Política de Privacidade",
"termsOfService": "Termos de Serviço",
"@@ADVANCED_OPTIONS": {},
"matrixZoom": "Zoom da Matriz",
"matrixedViewZoom": "Zoom em Visualização Matrixial",
"matrixedViewZoomDescription": "Dê zoom em uma visualização matrixial 16x16 para ver mais detalhes.",
"matrixMagnification": "Ampliar",
"matrixedViewMagnification": "Ampliação de Área ativada",
"matrixedViewMagnificationDescription": "Ampliar a área da visualização da matriz quando selecionado. Isso é útil quando você tem muitas câmeras e deseja ver uma área específica com mais detalhes, ou quando uma stream multicast é usada.",
"matrixType": "Tipo de Matrix",
"defaultMatrixSize": "Tamanho Padrão da Matriz",
"softwareZoom": "Zoom do Software",
"softwareZoomDescription": "Quando ativado, o zoom não ocorrerá na GPU. Isso é útil quando o zoom do hardware não está funcionando corretamente.",
"softwareZoomDescriptionMacOS": "Quando ativado, o zoom da matriz não ocorrerá na GPU. Isso é útil quando o zoom do hardware não está funcionando corretamente. No macOS, isso não pode ser desativado.",
"softwareMagnification": "Ampliação de Software",
"softwareMagnificationDescription": "Quando ativado, a ampliação não ocorrerá na GPU. Isso é útil quando a ampliação no hardware não está funcionando corretamente.",
"softwareMagnificationDescriptionMacOS": "Quando ativado, a ampliação não ocorrerá na GPU. Isso é útil quando a ampliação no hardware não está funcionando corretamente. No macOS, isso não pode ser desativado.",
"eventMagnification": "Ampliar Evento",
"eventMagnificationDescription": "Ampliar o vídeo do evento quando selecionado. Isso é útil quando você deseja ver o evento em mais detalhes.",
"developerOptions": "Opções de Desenvolvedor",
"openLogFile": "Abrir Arquivo de Log",
"openAppDataDirectory": "Abrir Diretório de Dados do Aplicativo",
Expand Down
5 changes: 3 additions & 2 deletions lib/models/device.dart
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,12 @@ class Device {
this.resolutionY = 480,
this.hasPTZ = false,
this.url,
this.matrixType = MatrixType.t16,
MatrixType? matrixType,
this.overlays = const [],
this.preferredStreamingType,
this.externalData,
}) : server = Server.dump();
}) : server = Server.dump(),
matrixType = matrixType ?? SettingsProvider.instance.kMatrixSize.value;

String get uri => 'live/$id';

Expand Down
8 changes: 6 additions & 2 deletions lib/providers/desktop_view_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,9 @@ class DesktopViewProvider extends UnityProvider {
/// Updates a device in all the layouts.
///
/// If [reload] is `true`, the device player will be reloaded.
Future<void> updateDevice(
///
/// Return the new device.
Device updateDevice(
Device previousDevice,
Device device, {
bool reload = false,
Expand All @@ -343,6 +345,8 @@ class DesktopViewProvider extends UnityProvider {
}

notifyListeners();
return save(notifyListeners: false);
save(notifyListeners: false);

return device;
}
}
15 changes: 11 additions & 4 deletions lib/providers/settings_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ class SettingsProvider extends UnityProvider {
);

// Other
final kDefaultBetaMatrixedZoomEnabled = _SettingsOption(
final kMatrixedZoomEnabled = _SettingsOption(
def: false,
key: 'other.matrixed_zoom_enabled',
);
Expand All @@ -411,6 +411,10 @@ class SettingsProvider extends UnityProvider {
? () => true
: null,
);
final kEventsMatrixedZoom = _SettingsOption(
def: true,
key: 'other.zoom_matrixed_zoom_enabled',
);
final kShowDebugInfo = _SettingsOption(
def: kDebugMode,
key: 'other.show_debug_info',
Expand Down Expand Up @@ -477,9 +481,10 @@ class SettingsProvider extends UnityProvider {
kAllowCrashReports.loadData(data),
kAutoUpdate.loadData(data),
kShowReleaseNotes.loadData(data),
kDefaultBetaMatrixedZoomEnabled.loadData(data),
kMatrixedZoomEnabled.loadData(data),
kMatrixSize.loadData(data),
kSoftwareZooming.loadData(data),
kEventsMatrixedZoom.loadData(data),
kShowDebugInfo.loadData(data),
kShowNetworkUsage.loadData(data),
]);
Expand Down Expand Up @@ -559,10 +564,12 @@ class SettingsProvider extends UnityProvider {
kAutoUpdate.key: kAutoUpdate.saveAs(kAutoUpdate.value),
kShowReleaseNotes.key:
kShowReleaseNotes.saveAs(kShowReleaseNotes.value),
kDefaultBetaMatrixedZoomEnabled.key: kDefaultBetaMatrixedZoomEnabled
.saveAs(kDefaultBetaMatrixedZoomEnabled.value),
kMatrixedZoomEnabled.key:
kMatrixedZoomEnabled.saveAs(kMatrixedZoomEnabled.value),
kMatrixSize.key: kMatrixSize.saveAs(kMatrixSize.value),
kSoftwareZooming.key: kSoftwareZooming.saveAs(kSoftwareZooming.value),
kEventsMatrixedZoom.key:
kEventsMatrixedZoom.saveAs(kEventsMatrixedZoom.value),
kShowDebugInfo.key: kShowDebugInfo.saveAs(kShowDebugInfo.value),
kShowNetworkUsage.key:
kShowNetworkUsage.saveAs(kShowNetworkUsage.value),
Expand Down
108 changes: 80 additions & 28 deletions lib/screens/events_timeline/desktop/timeline.dart
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ class TimelineTile {
quality: UnityVideoQuality.p480,
enableCache: true,
title: device.fullName,
softwareZoom: SettingsProvider.instance.kSoftwareZooming.value,
matrixType: SettingsProvider.instance.kMatrixSize.value,
);
videoController.setMultipleDataSource(
events.map((event) => event.videoUrl),
Expand Down Expand Up @@ -110,49 +112,58 @@ class TimelineEvent {
return [
TimelineEvent(
duration: const Duration(minutes: 1),
startTime: DateTime(2023).add(
Duration(hours: Random().nextInt(4), minutes: Random().nextInt(60)),
),
startTime: DateTime.now()
.add(
Duration(
hours: Random().nextInt(4), minutes: Random().nextInt(60)),
)
.toUtc(),
event: Event.dump(),
),
TimelineEvent(
duration: const Duration(hours: 1),
startTime: DateTime(2023).add(Duration(hours: Random().nextInt(4) + 5)),
startTime: DateTime.now()
.add(Duration(hours: Random().nextInt(4) + 5))
.toUtc(),
event: Event.dump(),
),
TimelineEvent(
duration: const Duration(minutes: 1),
startTime: DateTime(2023).add(Duration(hours: Random().nextInt(4) + 9)),
startTime: DateTime.now()
.add(Duration(hours: Random().nextInt(4) + 9))
.toUtc(),
event: Event.dump(),
),
TimelineEvent(
duration: const Duration(minutes: 1),
startTime: DateTime(2023).add(
Duration(
hours: Random().nextInt(4) + 13,
minutes: Random().nextInt(60),
),
),
startTime: DateTime.now()
.add(
Duration(
hours: Random().nextInt(4) + 13,
minutes: Random().nextInt(60),
),
)
.toUtc(),
event: Event.dump(),
),
TimelineEvent(
duration: const Duration(minutes: 1),
startTime: DateTime(2023).add(
Duration(
hours: Random().nextInt(4) + 14,
minutes: Random().nextInt(60),
),
),
startTime: DateTime.now()
.add(Duration(
hours: Random().nextInt(4) + 14,
minutes: Random().nextInt(60),
))
.toUtc(),
event: Event.dump(),
),
TimelineEvent(
duration: const Duration(minutes: 1),
startTime: DateTime(2023).add(
Duration(
hours: Random().nextInt(4) + 20,
minutes: Random().nextInt(60),
),
),
startTime: DateTime.now()
.add(Duration(
hours: Random().nextInt(4) + 20,
minutes: Random().nextInt(60),
))
.toUtc(),
event: Event.dump(),
),
];
Expand All @@ -179,13 +190,14 @@ class Timeline extends ChangeNotifier {
final List<TimelineTile> tiles = [];

/// All the events must have happened in the same day
final DateTime date;
late final DateTime date;

Timeline({
required List<TimelineTile> tiles,
required this.date,
required DateTime date,
Duration initialPosition = Duration.zero,
}) {
this.date = DateTime(date.year, date.month, date.day).toLocal();
currentPosition = initialPosition;

add(tiles.where((tile) => tile.events.isNotEmpty));
Expand All @@ -201,6 +213,29 @@ class Timeline extends ChangeNotifier {
zoomController.addListener(notifyListeners);
}

Timeline.dump()
: this(
tiles: [
TimelineTile(
device: Device.dump(name: 'device1'),
events: TimelineEvent.fakeData,
),
TimelineTile(
device: Device.dump(name: 'device2'),
events: TimelineEvent.fakeData,
),
TimelineTile(
device: Device.dump(name: 'device3'),
events: TimelineEvent.fakeData,
),
TimelineTile(
device: Device.dump(name: 'device4'),
events: TimelineEvent.fakeData,
),
],
date: DateTime.now(),
);

void _eventCallback(TimelineTile tile, {bool notify = true}) {
if (tile.videoController.duration <= Duration.zero) return;

Expand Down Expand Up @@ -511,6 +546,8 @@ class _TimelineEventsViewState extends State<TimelineEventsView> {

final verticalScrollController = ScrollController();

bool _isCollapsed = false;

@override
void initState() {
super.initState();
Expand Down Expand Up @@ -597,6 +634,16 @@ class _TimelineEventsViewState extends State<TimelineEventsView> {
end: 8.0,
),
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
SquaredIconButton(
icon:
Icon(_isCollapsed ? Icons.expand_more : Icons.expand_less),
onPressed: () {
setState(() {
_isCollapsed = !_isCollapsed;
});
},
tooltip: _isCollapsed ? loc.expand : loc.collapse,
),
Expanded(
child: Row(mainAxisAlignment: MainAxisAlignment.end, children: [
if (timeline.pausedToBuffer.isNotEmpty)
Expand Down Expand Up @@ -696,11 +743,16 @@ class _TimelineEventsViewState extends State<TimelineEventsView> {
'${settings.kDateFormat.value.format(timeline.currentDate)} '
'${timelineTimeFormat.format(timeline.currentDate)}',
),
ConstrainedBox(
constraints: const BoxConstraints(
maxHeight: _kTimelineTileHeight * 5.0,
AnimatedContainer(
duration: const Duration(milliseconds: 300),
constraints: BoxConstraints(
maxHeight: _isCollapsed ? 0.0 : _kTimelineTileHeight * 5.0,
),
child: LayoutBuilder(builder: (context, constraints) {
if (constraints.maxHeight < _kTimelineTileHeight / 1.9) {
return const SizedBox.shrink();
}

final tileWidth =
(constraints.maxWidth - _kDeviceNameWidth) * timeline.zoom;
final hourWidth = tileWidth / 24;
Expand Down
Loading

0 comments on commit 6dbc1fd

Please sign in to comment.