diff --git a/lib/src/models/data/video.dart b/lib/src/models/data/video.dart index 6f2041fb1..357311952 100644 --- a/lib/src/models/data/video.dart +++ b/lib/src/models/data/video.dart @@ -79,6 +79,14 @@ class VideoModel extends Model { notifyListeners(); } + /// Takes a screenshot of the current frame. + Future saveFrame(CameraFeed feed) async { + final List? cachedFrame = feed.frame; + if (cachedFrame == null) throw ArgumentError.notNull("Feed for ${feed.name}"); + await services.files.writeImage(cachedFrame, feed.name); + models.home.setMessage(severity: Severity.info, text: "Screenshot saved"); + } + /// Gets the camera feed with the given ID. CameraFeed getCameraFeed(CameraName id) => allFeeds.firstWhere((feed) => feed.id == id); diff --git a/lib/src/services/files.dart b/lib/src/services/files.dart index 8aaa7b637..86026b119 100644 --- a/lib/src/services/files.dart +++ b/lib/src/services/files.dart @@ -54,4 +54,12 @@ class FilesService extends Service { return settings; } } + + /// Saves the current frame in the feed to the camera's output directory. + Future writeImage(List image, String cameraName) async { + final dir = Directory("${outputDir.path}/$cameraName"); + if (!(await dir.exists())) await dir.create(); + final timestamp = DateTime.now().toString(); + await File("${dir.path}/$timestamp.jpg").writeAsBytes(image); + } } diff --git a/lib/src/widgets/atomic/video_feed.dart b/lib/src/widgets/atomic/video_feed.dart index 8341c9696..f30863429 100644 --- a/lib/src/widgets/atomic/video_feed.dart +++ b/lib/src/widgets/atomic/video_feed.dart @@ -83,21 +83,26 @@ class VideoFeedState extends State { child: image == null ? Text(errorMessage) : Row(children: [Expanded(child: RawImage(image: image, fit: BoxFit.fill))]), ), - Positioned( - top: 4, - right: 4, - child: PopupMenuButton( - tooltip: "Select a feed", - icon: const Icon(Icons.more_horiz), - onSelected: selectNewFeed, - itemBuilder: (_) => [ - for (final other in VideoModel.allFeeds) PopupMenuItem( - value: other, - child: Text(other.name), - ), - ] - ) - ) + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + if (feed.isActive) IconButton( + icon: const Icon(Icons.camera_alt), + onPressed: () => models.video.saveFrame(feed), + ), + PopupMenuButton( + tooltip: "Select a feed", + icon: const Icon(Icons.more_horiz), + onSelected: selectNewFeed, + itemBuilder: (_) => [ + for (final other in VideoModel.allFeeds) PopupMenuItem( + value: other, + child: Text(other.name), + ), + ] + ) + ] + ), ] );