diff --git a/.metadata b/.metadata index 72538e9..39b64a7 100644 --- a/.metadata +++ b/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: "aa5f4a28e9a8f121a2719c28d0c9a9c33dd798c4" + revision: "c63733310f2751959df940005e9decc68b39da6e" channel: "main" project_type: app @@ -13,11 +13,11 @@ project_type: app migration: platforms: - platform: root - create_revision: aa5f4a28e9a8f121a2719c28d0c9a9c33dd798c4 - base_revision: aa5f4a28e9a8f121a2719c28d0c9a9c33dd798c4 - - platform: web - create_revision: aa5f4a28e9a8f121a2719c28d0c9a9c33dd798c4 - base_revision: aa5f4a28e9a8f121a2719c28d0c9a9c33dd798c4 + create_revision: c63733310f2751959df940005e9decc68b39da6e + base_revision: c63733310f2751959df940005e9decc68b39da6e + - platform: macos + create_revision: c63733310f2751959df940005e9decc68b39da6e + base_revision: c63733310f2751959df940005e9decc68b39da6e # User provided section diff --git a/assets/.gitignore b/assets/.gitignore new file mode 100644 index 0000000..51cf312 --- /dev/null +++ b/assets/.gitignore @@ -0,0 +1 @@ +unsplash_client_id diff --git a/lib/main.dart b/lib/main.dart index 4887b4f..d6df563 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; +import 'package:photos/src/model/content_provider.dart'; import 'src/model/app.dart'; import 'src/model/auth.dart'; @@ -26,7 +27,7 @@ void settingsMain() { void dream() async { _runWithErrorChecking(() async { await PhotosAppBinding.ensureInitialized(); - AuthBinding.instance.signInSilently(); + await ContentProviderBinding.instance.init(); runApp(const PhotosApp()); }); } diff --git a/lib/src/extensions/matrix_4.dart b/lib/src/extensions/matrix_4.dart index c576390..1974c21 100644 --- a/lib/src/extensions/matrix_4.dart +++ b/lib/src/extensions/matrix_4.dart @@ -1,10 +1,10 @@ import 'dart:typed_data'; -import 'dart:ui'; +import 'dart:ui' as ui; import 'package:vector_math/vector_math_64.dart'; extension Matrix4Extensions on Matrix4 { - Size transformSize(Size size) { + ui.Size transformSize(ui.Size size) { final Float64List storage = this.storage; final double width = (storage[0] * size.width) + (storage[4] * size.height) + @@ -12,7 +12,7 @@ extension Matrix4Extensions on Matrix4 { final double height = (storage[1] * size.width) + (storage[5] * size.height) + storage[13]; - return Size(width, height); + return ui.Size(width, height); } Vector3 transform2(Vector3 arg) { diff --git a/lib/src/model/app.dart b/lib/src/model/app.dart index ee4799e..bd901c3 100644 --- a/lib/src/model/app.dart +++ b/lib/src/model/app.dart @@ -2,14 +2,16 @@ import 'dart:developer' as developer; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; -import 'package:photos/src/model/dream.dart'; import 'auth.dart'; +import 'content_provider.dart'; +import 'dream.dart'; import 'files.dart'; +import 'google_photos.dart'; import 'photos_api.dart'; import 'ui.dart'; -class PhotosAppBinding extends AppBindingBase with ChangeNotifier, FilesBinding, DreamBinding, AuthBinding, UiBinding, PhotosApiBinding { +class PhotosAppBinding extends AppBindingBase with ChangeNotifier, FilesBinding, DreamBinding, AuthBinding, UiBinding, PhotosApiBinding, ContentProviderBinding, GooglePhotosContentProvider { /// Creates and initializes the application binding if necessary. /// /// Applications should call this method before calling [runApp]. diff --git a/lib/src/model/content_provider.dart b/lib/src/model/content_provider.dart new file mode 100644 index 0000000..721295e --- /dev/null +++ b/lib/src/model/content_provider.dart @@ -0,0 +1,27 @@ +import 'dart:ui' as ui; + +import 'package:flutter/widgets.dart'; +import 'package:photos/src/photos_library_api/media_item.dart'; + +import 'app.dart'; + +mixin ContentProviderBinding on AppBindingBase { + /// The singleton instance of this object. + static late ContentProviderBinding _instance; + static ContentProviderBinding get instance => _instance; + + @override + @protected + @mustCallSuper + Future initInstances() async { + await super.initInstances(); + _instance = this; + } + + Future init(); + + Widget buildHome(BuildContext context); + + /// Gets the URL to load this media item at the specified size. + String getMediaItemUrl(MediaItem item, ui.Size size); +} diff --git a/lib/src/model/google_photos.dart b/lib/src/model/google_photos.dart new file mode 100644 index 0000000..2a555c7 --- /dev/null +++ b/lib/src/model/google_photos.dart @@ -0,0 +1,152 @@ +import 'dart:async'; +import 'dart:ui' as ui; + +import 'package:flutter/widgets.dart'; +import 'package:photos/src/photos_library_api/media_item.dart'; +import 'package:photos/src/ui/common/notifications.dart'; +import 'package:photos/src/ui/photos/app.dart'; +import 'package:photos/src/ui/photos/photos_page.dart'; + +import 'auth.dart'; +import 'content_provider.dart'; +import 'files.dart'; +import 'photo.dart'; +import 'photo_producer.dart'; +import 'photos_api.dart'; + +mixin GooglePhotosContentProvider on ContentProviderBinding { + @override + Future init() async { + await AuthBinding.instance.signInSilently(); + } + + @override + Widget buildHome(BuildContext context) { + switch (PhotosApp.of(context).state) { + case PhotosLibraryApiState.pendingAuthentication: + // Show a blank screen while we try to non-interactively sign in. + return Container(); + case PhotosLibraryApiState.unauthenticated: + return const MontageScaffold( + producer: AssetPhotoProducer(), + bottomBarNotification: NeedToLoginNotification(), + ); + case PhotosLibraryApiState.authenticated: + case PhotosLibraryApiState.authenticationExpired: + return MontageContainer(producer: GooglePhotosPhotoProducer()); + case PhotosLibraryApiState.rateLimited: + return const AssetPhotosMontageContainer(); + } + } + + @override + String getMediaItemUrl(MediaItem item, ui.Size size) =>'${item.baseUrl}=w${size.width.toInt()}-h${size.height.toInt()}'; +} + +/// A [PhotoProducer] that produces photos from Google Photos using +/// the specified [model] object. +/// +/// If the Google Photos API fails for any reason, this photo producer will +/// fall back to producing photos that are pulled statically from assets that +/// are bundled with this app (or, as a last resort, Todd's profile pic). +class GooglePhotosPhotoProducer extends PhotoProducer { + GooglePhotosPhotoProducer(); + + final List queue = []; + Completer? _queueCompleter; + + /// How many photos to load from the Google Photos API in one request. + /// + /// Batching saves the number of requests being made to the photos API, which + /// is not only more efficient, but it makes it less likely that the app will + /// be rate limited. + static const int _batchSize = 50; + + /// Makes a batch request to the Google Photos API, and adds all the media + /// items that it loaded into the [queue]. + /// + /// This method depends on the entire set of photo IDs having already been + /// loaded so that we can choose random photos from the main set. See + /// [PhotosLibraryApiModel.populateDatabase] for more info. + /// + /// If this method is called, and then it is called again while the first + /// call's future is still pending, then the existing future will be reused + /// and returned. + Future _queueItems() { + if (_queueCompleter != null) { + return _queueCompleter!.future; + } + _queueCompleter = Completer(); + final Future result = _doQueueItems(); + _queueCompleter!.complete(result); + _queueCompleter = null; + return result; + } + + /// Method that does the actual work of queueing media items. + /// + /// Assuming the database files have been created, this method will always + /// make a request to the Google Photos API, even if other requests are still + /// pending. To ensure that we reuse existing pending requests, use + /// [_queueItems] instead. + Future _doQueueItems() async { + final FilesBinding files = FilesBinding.instance; + if (!files.photosFile.existsSync()) { + // We haven't yet finished loading the set of photo IDs from which to + // choose the next batch of media items; nothing to queue. + return; + } + + final PhotosApiBinding photosApi = PhotosApiBinding.instance; + final List mediaItemIds = await photosApi.pickRandomMediaItems(_batchSize); + Iterable items = await photosApi.getMediaItems(mediaItemIds); + items = items.where((MediaItem item) => item.size != null); + assert(() { + if (items.length != _batchSize) { + debugPrint('Expecting $_batchSize items, but retrieved ${items.length}'); + } + return true; + }()); + queue.insertAll(0, items); + } + + @override + Future produce({ + required BuildContext context, + required Size sizeConstraints, + double scaleMultiplier = 1, + }) async { + final ui.FlutterView window = View.of(context); + + if (queue.isEmpty) { + // The queue can still be empty after this call, e.g. if the database + // files haven't been created yet. + await _queueItems(); + } + + if (queue.isEmpty) { + // ignore: use_build_context_synchronously + return await const AssetPhotoProducer().produce( + context: context, + sizeConstraints: sizeConstraints, + scaleMultiplier: scaleMultiplier, + ); + } else { + final double scale = window.devicePixelRatio * scaleMultiplier; + final MediaItem mediaItem = queue.removeLast(); + final Size photoLogicalSize = applyBoxFit( + BoxFit.scaleDown, + mediaItem.size!, + sizeConstraints, + ).destination; + return Photo( + id: mediaItem.id, + mediaItem: mediaItem, + size: photoLogicalSize, + scale: scale, + boundingConstraints: sizeConstraints, + image: NetworkImage(ContentProviderBinding.instance.getMediaItemUrl(mediaItem, photoLogicalSize * scale), scale: scale), + ); + } + } +} diff --git a/lib/src/model/photo_producer.dart b/lib/src/model/photo_producer.dart index 76489be..d44d519 100644 --- a/lib/src/model/photo_producer.dart +++ b/lib/src/model/photo_producer.dart @@ -1,17 +1,14 @@ import 'dart:async'; -import 'dart:ui' as ui; import 'package:flutter/widgets.dart'; +import 'package:photos/src/photos_library_api/media_item.dart'; +import 'package:photos/src/photos_library_api/media_metadata.dart'; -import '../photos_library_api/media_item.dart'; -import '../photos_library_api/media_metadata.dart'; - -import 'files.dart'; +import 'content_provider.dart'; import 'photo.dart'; -import 'photos_api.dart'; abstract class PhotoProducer { - const PhotoProducer._(); + const PhotoProducer(); /// Produces a [Photo] that fits within the specified size constraints. Future produce({ @@ -21,144 +18,10 @@ abstract class PhotoProducer { }); } -/// A [PhotoProducer] that produces photos from Google Photos using -/// the specified [model] object. -/// -/// If the Google Photos API fails for any reason, this photo producer will -/// fall back to producing photos that are pulled statically from assets that -/// are bundled with this app (or, as a last resort, Todd's profile pic). -class GooglePhotosPhotoProducer extends PhotoProducer { - GooglePhotosPhotoProducer() : super._(); - - final List queue = []; - Completer? _queueCompleter; - - /// How many photos to load from the Google Photos API in one request. - /// - /// Batching saves the number of requests being made to the photos API, which - /// is not only more efficient, but it makes it less likely that the app will - /// be rate limited. - static const int _batchSize = 50; - - /// Makes a batch request to the Google Photos API, and adds all the media - /// items that it loaded into the [queue]. - /// - /// This method depends on the entire set of photo IDs having already been - /// loaded so that we can choose random photos from the main set. See - /// [PhotosLibraryApiModel.populateDatabase] for more info. - /// - /// If this method is called, and then it is called again while the first - /// call's future is still pending, then the existing future will be reused - /// and returned. - Future _queueItems() { - if (_queueCompleter != null) { - return _queueCompleter!.future; - } - _queueCompleter = Completer(); - final Future result = _doQueueItems(); - _queueCompleter!.complete(result); - _queueCompleter = null; - return result; - } - - /// Method that does the actual work of queueing media items. - /// - /// Assuming the database files have been created, this method will always - /// make a request to the Google Photos API, even if other requests are still - /// pending. To ensure that we reuse existing pending requests, use - /// [_queueItems] instead. - Future _doQueueItems() async { - final FilesBinding files = FilesBinding.instance; - if (!files.photosFile.existsSync()) { - // We haven't yet finished loading the set of photo IDs from which to - // choose the next batch of media items; nothing to queue. - return; - } - - final PhotosApiBinding photosApi = PhotosApiBinding.instance; - final List mediaItemIds = await photosApi.pickRandomMediaItems(_batchSize); - Iterable items = await photosApi.getMediaItems(mediaItemIds); - items = items.where((MediaItem item) => item.size != null); - assert(() { - if (items.length != _batchSize) { - debugPrint('Expecting $_batchSize items, but retrieved ${items.length}'); - } - return true; - }()); - queue.insertAll(0, items); - } - - @override - Future produce({ - required BuildContext context, - required Size sizeConstraints, - double scaleMultiplier = 1, - }) async { - final ui.FlutterView window = View.of(context); - - if (queue.isEmpty) { - // The queue can still be empty after this call, e.g. if the database - // files haven't been created yet. - await _queueItems(); - } - - if (queue.isEmpty) { - // ignore: use_build_context_synchronously - return await const AssetPhotoProducer().produce( - context: context, - sizeConstraints: sizeConstraints, - scaleMultiplier: scaleMultiplier, - ); - } else { - final double scale = window.devicePixelRatio * scaleMultiplier; - final MediaItem mediaItem = queue.removeLast(); - final Size photoLogicalSize = applyBoxFit( - BoxFit.scaleDown, - mediaItem.size!, - sizeConstraints, - ).destination; - return Photo( - id: mediaItem.id, - mediaItem: mediaItem, - size: photoLogicalSize, - scale: scale, - boundingConstraints: sizeConstraints, - image: NetworkImage(mediaItem.getSizedUrl(photoLogicalSize * scale), scale: scale), - ); - } - } -} - -class ImmediateImageStreamCompleter extends ImageStreamCompleter { - ImmediateImageStreamCompleter(ImageInfo image) { - setImage(image); - } -} - -class ImageBackedPhoto extends Photo { - const ImageBackedPhoto({ - required super.id, - super.mediaItem, - required super.size, - required super.scale, - required super.boundingConstraints, - required super.image, - required this.backingImage, - }); - - final ui.Image backingImage; - - @override - void dispose() { - backingImage.dispose(); - super.dispose(); - } -} - /// A [PhotoProducer] that produces photos that are pulled statically /// from assets that are bundled with this app. class AssetPhotoProducer extends PhotoProducer { - const AssetPhotoProducer() : super._(); + const AssetPhotoProducer(); static const List _assets = [ 'assets/DSC_0013.jpg', @@ -203,7 +66,7 @@ class AssetPhotoProducer extends PhotoProducer { /// A [PhotoProducer] that produces a single static photo. class StaticPhotoProducer extends PhotoProducer { - const StaticPhotoProducer() : super._(); + const StaticPhotoProducer(); @override Future produce({ @@ -226,7 +89,7 @@ class StaticPhotoProducer extends PhotoProducer { size: staticSize, scale: View.of(context).devicePixelRatio, boundingConstraints: sizeConstraints, - image: NetworkImage(staticMediaItem.getSizedUrl(staticSize)), + image: NetworkImage(ContentProviderBinding.instance.getMediaItemUrl(staticMediaItem, staticSize)), ); } } diff --git a/lib/src/model/unsplash.dart b/lib/src/model/unsplash.dart new file mode 100644 index 0000000..8b473de --- /dev/null +++ b/lib/src/model/unsplash.dart @@ -0,0 +1,131 @@ +import 'dart:async'; +import 'dart:convert' show json; +import 'dart:io' show HttpStatus; +import 'dart:ui' as ui; + +import 'package:flutter/services.dart'; +import 'package:http/http.dart' as http; +import 'package:flutter/widgets.dart'; + +import 'package:photos/src/model/photo_producer.dart'; +import 'package:photos/src/photos_library_api/media_item.dart'; +import 'package:photos/src/photos_library_api/media_metadata.dart'; +import 'package:photos/src/ui/photos/photos_page.dart'; + +import 'content_provider.dart'; +import 'photo.dart'; + +mixin UnsplashContentProvider on ContentProviderBinding { + @override + Future init() async { + // No-op + } + + @override + Widget buildHome(BuildContext context) { + return MontageContainer(producer: UnsplashPhotoProducer()); + } + + @override + String getMediaItemUrl(MediaItem item, ui.Size size) =>'${item.baseUrl}&w=${size.width.toInt()}&h=${size.height.toInt()}&fit=max&fm=jpg'; +} + +class UnsplashPhotoProducer extends PhotoProducer { + UnsplashPhotoProducer(); + + int _iter = _maxSize; + final List queue = []; + Completer? _queueCompleter; + + static const int _batchSize = 30; + static const int _maxSize = 1200; + + Future _queueItems() { + if (_queueCompleter != null) { + return _queueCompleter!.future; + } + _queueCompleter = Completer(); + final Future result = _doQueueItems(); + _queueCompleter!.complete(result); + _queueCompleter = null; + return result; + } + + /// Method that does the actual work of queueing media items. + /// + /// Assuming the database files have been created, this method will always + /// make a request to the Google Photos API, even if other requests are still + /// pending. To ensure that we reuse existing pending requests, use + /// [_queueItems] instead. + Future _doQueueItems() async { + final String clientId = await rootBundle.loadString('assets/unsplash_client_id'); + final Uri url = Uri.https('api.unsplash.com', '/photos/random', { + 'count': '$_batchSize', + }); + final http.Response response = await http.get(url, headers: { + 'Authorization': 'Client-ID $clientId' + }); + + if (response.statusCode != HttpStatus.ok) { + throw '~!@ BAD RESPONSE\n\n${response.headers}\n\n${response.body}'; + } + + final List> data = json.decode(response.body).cast>(); + final List items = []; + for (Map datum in data) { + items.add(MediaItem( + id: datum['id'], + description: datum['description'], + productUrl: datum['links']['html'], + baseUrl: datum['urls']['raw'], + mediaMetadata: MediaMetadata( + width: datum['width'].toString(), + height: datum['height'].toString(), + ), + )); + } + queue.addAll(items); + } + + @override + Future produce({ + required BuildContext context, + required Size sizeConstraints, + double scaleMultiplier = 1, + }) async { + final ui.FlutterView window = View.of(context); + + if (++_iter >= _maxSize) { + _iter = 0; + } + + if (_iter >= queue.length) { + await _queueItems(); + } + + if (_iter >= queue.length) { + // ignore: use_build_context_synchronously + return await const AssetPhotoProducer().produce( + context: context, + sizeConstraints: sizeConstraints, + scaleMultiplier: scaleMultiplier, + ); + } else { + final double scale = window.devicePixelRatio * scaleMultiplier; + final MediaItem mediaItem = queue[_iter]; + final Size photoLogicalSize = applyBoxFit( + BoxFit.scaleDown, + mediaItem.size!, + sizeConstraints, + ).destination; + return Photo( + id: mediaItem.id, + mediaItem: mediaItem, + size: photoLogicalSize, + scale: scale, + boundingConstraints: sizeConstraints, + image: NetworkImage(ContentProviderBinding.instance.getMediaItemUrl(mediaItem, photoLogicalSize * scale), scale: scale), + ); + } + } +} diff --git a/lib/src/photos_library_api/media_item.dart b/lib/src/photos_library_api/media_item.dart index aab4be0..305e54b 100644 --- a/lib/src/photos_library_api/media_item.dart +++ b/lib/src/photos_library_api/media_item.dart @@ -1,10 +1,7 @@ -import 'dart:io'; -import 'dart:ui'; +import 'dart:ui' as ui; -import 'package:flutter/foundation.dart'; import 'package:json_annotation/json_annotation.dart'; -import 'http_status_exception.dart'; import 'media_metadata.dart'; part 'media_item.g.dart'; @@ -70,30 +67,13 @@ class MediaItem { final MediaMetadata mediaMetadata; /// The original raw size (in photo pixels) of the media item. - Size? get size { + ui.Size? get size { if (mediaMetadata.width == null || mediaMetadata.height == null) { return null; } int width = int.parse(mediaMetadata.width!); int height = int.parse(mediaMetadata.height!); - return Size(width.toDouble(), height.toDouble()); - } - - /// Gets the URL to load this media item at the specified size. - String getSizedUrl(Size size) =>'$baseUrl=w${size.width.toInt()}-h${size.height.toInt()}'; - - /// Loads and returns the bytes of this media item. - Future load(Size size) async { - final String url = getSizedUrl(size); - final HttpClient httpClient = HttpClient(); - final Uri resolved = Uri.base.resolve(url); - final HttpClientRequest request = await httpClient.getUrl(resolved); - final HttpClientResponse response = await request.close(); - if (response.statusCode != HttpStatus.ok) { - throw HttpStatusException(response.statusCode); - } - - return await consolidateHttpClientResponseBytes(response); + return ui.Size(width.toDouble(), height.toDouble()); } Map toJson() => _$MediaItemToJson(this); diff --git a/lib/src/ui/photos/app.dart b/lib/src/ui/photos/app.dart index ea73802..ac1b13f 100644 --- a/lib/src/ui/photos/app.dart +++ b/lib/src/ui/photos/app.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart' show CircularProgressIndicator, Icons; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart' hide Notification; +import 'package:photos/src/model/content_provider.dart'; import 'package:photos/src/model/dream.dart'; import 'package:photos/src/model/photos_api.dart'; @@ -9,7 +10,6 @@ import 'package:photos/src/ui/common/app.dart'; import 'package:photos/src/ui/common/debug.dart'; import 'package:photos/src/ui/common/notifications.dart'; -import 'home.dart'; import 'shortcuts.dart'; class PhotosApp extends StatefulWidget { @@ -196,7 +196,7 @@ class _PhotosAppState extends State with AppControllerMixin[ - const PhotosHome(), + ContentProviderBinding.instance.buildHome(context), NotificationsPanel( upperLeft: ErrorsNotification(errors), upperRight: _showPerformanceMetrics @@ -296,8 +296,8 @@ class _PhotosAppScope extends InheritedWidget { required this.state, required this.apiState, required this.isShowDebugInfo, - required Widget child, - }) : super(child: child); + required super.child, + }); final _PhotosAppState state; final PhotosLibraryApiState apiState; diff --git a/lib/src/ui/photos/home.dart b/lib/src/ui/photos/home.dart deleted file mode 100644 index 9a693a9..0000000 --- a/lib/src/ui/photos/home.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'package:flutter/widgets.dart'; - -import 'package:photos/src/model/photo_producer.dart'; -import 'package:photos/src/model/photos_api.dart'; -import 'package:photos/src/ui/common/notifications.dart'; - -import 'app.dart'; -import 'photos_page.dart'; - -class PhotosHome extends StatelessWidget { - const PhotosHome({super.key}); - - @override - Widget build(BuildContext context) { - switch (PhotosApp.of(context).state) { - case PhotosLibraryApiState.pendingAuthentication: - // Show a blank screen while we try to non-interactively sign in. - return Container(); - case PhotosLibraryApiState.unauthenticated: - return const MontageScaffold( - producer: AssetPhotoProducer(), - bottomBarNotification: NeedToLoginNotification(), - ); - case PhotosLibraryApiState.authenticated: - case PhotosLibraryApiState.authenticationExpired: - return const GooglePhotosMontageContainer(); - case PhotosLibraryApiState.rateLimited: - return const AssetPhotosMontageContainer(); - } - } -} diff --git a/lib/src/ui/photos/intents.dart b/lib/src/ui/photos/intents.dart index 5d4b9c6..43e6ed5 100644 --- a/lib/src/ui/photos/intents.dart +++ b/lib/src/ui/photos/intents.dart @@ -10,6 +10,16 @@ class FastForwardIntent extends Intent { const FastForwardIntent(); } +class GoFasterIntent extends Intent { + /// Creates a const [GoFasterIntent]. + const GoFasterIntent(); +} + +class GoSlowerIntent extends Intent { + /// Creates a const [GoSlowerIntent]. + const GoSlowerIntent(); +} + class ZoomIntent extends Intent { /// Creates a const [ZoomIntent]. const ZoomIntent(); diff --git a/lib/src/ui/photos/montage.dart b/lib/src/ui/photos/montage.dart index 51fd46c..5845ef0 100644 --- a/lib/src/ui/photos/montage.dart +++ b/lib/src/ui/photos/montage.dart @@ -158,7 +158,7 @@ class IndexSlot { } class MontageElement extends RenderObjectElement { - MontageElement(Montage widget) : super(widget); + MontageElement(super.widget); late List _children; diff --git a/lib/src/ui/photos/photos_page.dart b/lib/src/ui/photos/photos_page.dart index da5a068..c8d9315 100644 --- a/lib/src/ui/photos/photos_page.dart +++ b/lib/src/ui/photos/photos_page.dart @@ -79,17 +79,6 @@ class _MontageScaffoldState extends State { } } -/// A widget that builds a [MontageContainer] with photos produces using an -/// instance of [GooglePhotosPhotoProducer]. -class GooglePhotosMontageContainer extends StatelessWidget { - const GooglePhotosMontageContainer({super.key}); - - @override - Widget build(BuildContext context) { - return MontageContainer(producer: GooglePhotosPhotoProducer()); - } -} - /// A widget that builds a [MontageContainer] with photos produces using an /// instance of [AssetPhotoProducer]. class AssetPhotosMontageContainer extends StatelessWidget { @@ -162,6 +151,7 @@ class MontageFrameDriver extends StatefulWidget { class _MontageFrameDriverState extends State { int? _scheduledFrameCallbackId; int _currentFrame = 0; + int _speed = 1; Timer? _resumeTimer; static const Duration _resumeDuration = Duration(seconds: 5); @@ -181,20 +171,30 @@ class _MontageFrameDriverState extends State { } void _onFrame(Duration timeStamp) async { - setState(() => _currentFrame++); + setState(() => _currentFrame += _speed); _scheduleFrame(rescheduling: true); } void _handleRewind(Intent intent) { _cancelFrame(); _scheduleResume(); - setState(() => _currentFrame -= 20); + setState(() => _currentFrame -= 20 * _speed); } void _handleFastForward(Intent intent) { _cancelFrame(); _scheduleResume(); - setState(() => _currentFrame+= 20); + setState(() => _currentFrame+= 20 * _speed); + } + + void _handleGoFaster(Intent intent) { + setState(() => _speed++); + } + + void _handleGoSlower(Intent intent) { + setState(() { + _speed = math.max(_speed - 1, 1); + }); } void _scheduleResume() { @@ -238,6 +238,8 @@ class _MontageFrameDriverState extends State { actions: >{ RewindIntent: CallbackAction(onInvoke: _handleRewind), FastForwardIntent: CallbackAction(onInvoke: _handleFastForward), + GoFasterIntent: CallbackAction(onInvoke: _handleGoFaster), + GoSlowerIntent: CallbackAction(onInvoke: _handleGoSlower), }, child: MontageSpinDriver( frame: _currentFrame, @@ -428,6 +430,7 @@ class _PhotoCardState extends State { } void _subscribeImageStream() { + _unsubscribeImageStream(); assert(_photoFuture == null); assert(_currentPhoto != null); final ImageConfiguration config = createLocalImageConfiguration(context); diff --git a/lib/src/ui/photos/shortcuts.dart b/lib/src/ui/photos/shortcuts.dart index bdcec51..a2bdf22 100644 --- a/lib/src/ui/photos/shortcuts.dart +++ b/lib/src/ui/photos/shortcuts.dart @@ -18,6 +18,8 @@ class PhotosShortcutManager extends ShortcutManager { SingleActivator(LogicalKeyboardKey.arrowRight): FastForwardIntent(), SingleActivator(LogicalKeyboardKey.mediaFastForward): FastForwardIntent(), SingleActivator(LogicalKeyboardKey.mediaSkipForward): FastForwardIntent(), + SingleActivator(LogicalKeyboardKey.arrowUp): GoFasterIntent(), + SingleActivator(LogicalKeyboardKey.arrowDown): GoSlowerIntent(), SingleActivator(LogicalKeyboardKey.keyS): SpinIntent(), SingleActivator(LogicalKeyboardKey.add): ZoomIntent(), SingleActivator(LogicalKeyboardKey.minus): ShrinkIntent(), diff --git a/lib/src/ui/settings/app.dart b/lib/src/ui/settings/app.dart index 235b519..34b9592 100644 --- a/lib/src/ui/settings/app.dart +++ b/lib/src/ui/settings/app.dart @@ -103,8 +103,8 @@ class _SettingsAppScope extends InheritedWidget { const _SettingsAppScope({ required this.state, required this.isShowDebugInfo, - required Widget child, - }) : super(child: child); + required super.child, + }); final _SettingsAppState state; final bool isShowDebugInfo; diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index e777c67..e0ff237 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,8 +5,12 @@ import FlutterMacOS import Foundation +import google_sign_in_ios import path_provider_foundation +import video_player_avfoundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin")) } diff --git a/macos/Podfile b/macos/Podfile index c795730..b52666a 100644 --- a/macos/Podfile +++ b/macos/Podfile @@ -1,4 +1,4 @@ -platform :osx, '10.14' +platform :osx, '10.15' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 480d69b..9309995 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -1,23 +1,69 @@ PODS: + - AppAuth (1.7.5): + - AppAuth/Core (= 1.7.5) + - AppAuth/ExternalUserAgent (= 1.7.5) + - AppAuth/Core (1.7.5) + - AppAuth/ExternalUserAgent (1.7.5): + - AppAuth/Core - FlutterMacOS (1.0.0) + - google_sign_in_ios (0.0.1): + - AppAuth (>= 1.7.4) + - Flutter + - FlutterMacOS + - GoogleSignIn (~> 7.1) + - GTMSessionFetcher (>= 3.4.0) + - GoogleSignIn (7.1.0): + - AppAuth (< 2.0, >= 1.7.3) + - GTMAppAuth (< 5.0, >= 4.1.1) + - GTMSessionFetcher/Core (~> 3.3) + - GTMAppAuth (4.1.1): + - AppAuth/Core (~> 1.7) + - GTMSessionFetcher/Core (< 4.0, >= 3.3) + - GTMSessionFetcher (3.5.0): + - GTMSessionFetcher/Full (= 3.5.0) + - GTMSessionFetcher/Core (3.5.0) + - GTMSessionFetcher/Full (3.5.0): + - GTMSessionFetcher/Core - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS + - video_player_avfoundation (0.0.1): + - Flutter + - FlutterMacOS DEPENDENCIES: - FlutterMacOS (from `Flutter/ephemeral`) + - google_sign_in_ios (from `Flutter/ephemeral/.symlinks/plugins/google_sign_in_ios/darwin`) - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - video_player_avfoundation (from `Flutter/ephemeral/.symlinks/plugins/video_player_avfoundation/darwin`) + +SPEC REPOS: + trunk: + - AppAuth + - GoogleSignIn + - GTMAppAuth + - GTMSessionFetcher EXTERNAL SOURCES: FlutterMacOS: :path: Flutter/ephemeral + google_sign_in_ios: + :path: Flutter/ephemeral/.symlinks/plugins/google_sign_in_ios/darwin path_provider_foundation: :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + video_player_avfoundation: + :path: Flutter/ephemeral/.symlinks/plugins/video_player_avfoundation/darwin SPEC CHECKSUMS: + AppAuth: 501c04eda8a8d11f179dbe8637b7a91bb7e5d2fa FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 - path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 + google_sign_in_ios: 07375bfbf2620bc93a602c0e27160d6afc6ead38 + GoogleSignIn: d4281ab6cf21542b1cfaff85c191f230b399d2db + GTMAppAuth: f69bd07d68cd3b766125f7e072c45d7340dea0de + GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6 + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3 -PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367 +PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3 -COCOAPODS: 1.11.2 +COCOAPODS: 1.14.3 diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 08bbfa1..148ad28 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -27,8 +27,8 @@ 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; - D9F60CEA650D376BE9F8207C /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23AE34E3AC906325C152397D /* Pods_RunnerTests.framework */; }; - FCFD508D922F4FFF5A16CCAA /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 273D2FEA3C21437DD0BF37DB /* Pods_Runner.framework */; }; + 72E51920DBF8270CBB66D0C8 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDDC69302AB853604EC38A91 /* Pods_RunnerTests.framework */; }; + 792680BAF2E8870B60AE089A /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6F9A8BD508DE09AB121BDCC /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -62,11 +62,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 009F920AF625C7CB049115F7 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; - 1EF483A20C4038196F5280CE /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; - 23AE34E3AC906325C152397D /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 273D2FEA3C21437DD0BF37DB /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 2ABA930C6A4A1812BAF688AC /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 1E0E2579677A23F7C83266C9 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; @@ -83,11 +79,15 @@ 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 561834080736D641FFF069E9 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 69CCE15166D59BE354C61177 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; - 9C315F5C18F8C9C40BE527F0 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - A968D7D4FC6433C62CD1457F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - BCB9D19103247F4A6B426079 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + BA88BC4B8B9E819B2CB6E805 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + CDDC69302AB853604EC38A91 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + E19E3793C09C370A09202AAB /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + E7B974306AA17BC6BF744332 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + F6F9A8BD508DE09AB121BDCC /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -95,7 +95,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - D9F60CEA650D376BE9F8207C /* Pods_RunnerTests.framework in Frameworks */, + 72E51920DBF8270CBB66D0C8 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -103,13 +103,27 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - FCFD508D922F4FFF5A16CCAA /* Pods_Runner.framework in Frameworks */, + 792680BAF2E8870B60AE089A /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 17A3879A3A31C25B1BAD9394 /* Pods */ = { + isa = PBXGroup; + children = ( + BA88BC4B8B9E819B2CB6E805 /* Pods-Runner.debug.xcconfig */, + 1E0E2579677A23F7C83266C9 /* Pods-Runner.release.xcconfig */, + 561834080736D641FFF069E9 /* Pods-Runner.profile.xcconfig */, + E7B974306AA17BC6BF744332 /* Pods-RunnerTests.debug.xcconfig */, + E19E3793C09C370A09202AAB /* Pods-RunnerTests.release.xcconfig */, + 69CCE15166D59BE354C61177 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; 331C80D6294CF71000263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( @@ -137,7 +151,7 @@ 331C80D6294CF71000263BE5 /* RunnerTests */, 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, - 489034E8D634C640BBF89041 /* Pods */, + 17A3879A3A31C25B1BAD9394 /* Pods */, ); sourceTree = ""; }; @@ -185,25 +199,11 @@ path = Runner; sourceTree = ""; }; - 489034E8D634C640BBF89041 /* Pods */ = { - isa = PBXGroup; - children = ( - A968D7D4FC6433C62CD1457F /* Pods-Runner.debug.xcconfig */, - 9C315F5C18F8C9C40BE527F0 /* Pods-Runner.release.xcconfig */, - BCB9D19103247F4A6B426079 /* Pods-Runner.profile.xcconfig */, - 009F920AF625C7CB049115F7 /* Pods-RunnerTests.debug.xcconfig */, - 2ABA930C6A4A1812BAF688AC /* Pods-RunnerTests.release.xcconfig */, - 1EF483A20C4038196F5280CE /* Pods-RunnerTests.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( - 273D2FEA3C21437DD0BF37DB /* Pods_Runner.framework */, - 23AE34E3AC906325C152397D /* Pods_RunnerTests.framework */, + F6F9A8BD508DE09AB121BDCC /* Pods_Runner.framework */, + CDDC69302AB853604EC38A91 /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -215,7 +215,7 @@ isa = PBXNativeTarget; buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( - 2DAF7E67ACBB8C58AC434BC0 /* [CP] Check Pods Manifest.lock */, + F46326858AD7E0DEACEC9F53 /* [CP] Check Pods Manifest.lock */, 331C80D1294CF70F00263BE5 /* Sources */, 331C80D2294CF70F00263BE5 /* Frameworks */, 331C80D3294CF70F00263BE5 /* Resources */, @@ -234,13 +234,14 @@ isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - F04D6A5BFFF805AABD1F3C78 /* [CP] Check Pods Manifest.lock */, + FEF015AFAD4E3F59984034B1 /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, - F4939A8C74538DEE21164D7F /* [CP] Embed Pods Frameworks */, + AAA785153AC2EBF22A67CDDD /* [CP] Embed Pods Frameworks */, + 996E30797EF09B446E2CD728 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -258,8 +259,9 @@ 33CC10E52044A3C60003C045 /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 331C80D4294CF70F00263BE5 = { @@ -322,67 +324,79 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 2DAF7E67ACBB8C58AC434BC0 /* [CP] Check Pods Manifest.lock */ = { + 3399D490228B24CF009A79C7 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", ); - name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; }; - 3399D490228B24CF009A79C7 /* ShellScript */ = { + 33CC111E2044C6BF0003C045 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, ); inputPaths = ( + Flutter/ephemeral/tripwire, ); outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; - 33CC111E2044C6BF0003C045 /* ShellScript */ = { + 996E30797EF09B446E2CD728 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( - Flutter/ephemeral/FlutterInputs.xcfilelist, - ); - inputPaths = ( - Flutter/ephemeral/tripwire, + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", ); + name = "[CP] Copy Pods Resources"; outputFileListPaths = ( - Flutter/ephemeral/FlutterOutputs.xcfilelist, + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + AAA785153AC2EBF22A67CDDD /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; }; - F04D6A5BFFF805AABD1F3C78 /* [CP] Check Pods Manifest.lock */ = { + F46326858AD7E0DEACEC9F53 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -397,28 +411,33 @@ outputFileListPaths = ( ); outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - F4939A8C74538DEE21164D7F /* [CP] Embed Pods Frameworks */ = { + FEF015AFAD4E3F59984034B1 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - name = "[CP] Embed Pods Frameworks"; + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -472,7 +491,7 @@ /* Begin XCBuildConfiguration section */ 331C80DB294CF71000263BE5 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 009F920AF625C7CB049115F7 /* Pods-RunnerTests.debug.xcconfig */; + baseConfigurationReference = E7B974306AA17BC6BF744332 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -487,7 +506,7 @@ }; 331C80DC294CF71000263BE5 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 2ABA930C6A4A1812BAF688AC /* Pods-RunnerTests.release.xcconfig */; + baseConfigurationReference = E19E3793C09C370A09202AAB /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -502,7 +521,7 @@ }; 331C80DD294CF71000263BE5 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 1EF483A20C4038196F5280CE /* Pods-RunnerTests.profile.xcconfig */; + baseConfigurationReference = 69CCE15166D59BE354C61177 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -520,6 +539,7 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -543,9 +563,11 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -575,6 +597,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 10.15; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; @@ -593,6 +616,7 @@ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -616,9 +640,11 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -646,6 +672,7 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -669,9 +696,11 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -701,6 +730,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 10.15; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -721,6 +751,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 10.15; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 8fbaee5..720dcb9 100644 --- a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ Bool { return true } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } } diff --git a/macos/Runner/Configs/AppInfo.xcconfig b/macos/Runner/Configs/AppInfo.xcconfig index b383619..f36f57e 100644 --- a/macos/Runner/Configs/AppInfo.xcconfig +++ b/macos/Runner/Configs/AppInfo.xcconfig @@ -11,4 +11,4 @@ PRODUCT_NAME = Photos Screensaver PRODUCT_BUNDLE_IDENTIFIER = dev.tvolkert.photos // The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2023 tvolkert.dev. All rights reserved. +PRODUCT_COPYRIGHT = Copyright © 2024 tvolkert.dev. All rights reserved. diff --git a/macos/Runner/MainFlutterWindow.swift b/macos/Runner/MainFlutterWindow.swift index 2722837..3cc05eb 100644 --- a/macos/Runner/MainFlutterWindow.swift +++ b/macos/Runner/MainFlutterWindow.swift @@ -3,7 +3,7 @@ import FlutterMacOS class MainFlutterWindow: NSWindow { override func awakeFromNib() { - let flutterViewController = FlutterViewController.init() + let flutterViewController = FlutterViewController() let windowFrame = self.frame self.contentViewController = flutterViewController self.setFrame(windowFrame, display: true) diff --git a/macos/RunnerTests/RunnerTests.swift b/macos/RunnerTests/RunnerTests.swift index 5418c9f..61f3bd1 100644 --- a/macos/RunnerTests/RunnerTests.swift +++ b/macos/RunnerTests/RunnerTests.swift @@ -1,5 +1,5 @@ -import FlutterMacOS import Cocoa +import FlutterMacOS import XCTest class RunnerTests: XCTestCase { diff --git a/pubspec.lock b/pubspec.lock index e61f1de..8a36a98 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,26 +5,31 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 + sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 url: "https://pub.dev" source: hosted - version: "64.0.0" + version: "72.0.0" + _macros: + dependency: transitive + description: dart + source: sdk + version: "0.3.2" analyzer: dependency: transitive description: name: analyzer - sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" + sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 url: "https://pub.dev" source: hosted - version: "6.2.0" + version: "6.7.0" args: dependency: transitive description: name: args - sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.5.0" async: dependency: transitive description: @@ -61,34 +66,34 @@ packages: dependency: transitive description: name: build_daemon - sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65" + sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.0.2" build_resolvers: dependency: transitive description: name: build_resolvers - sha256: "6c4dd11d05d056e76320b828a1db0fc01ccd376922526f8e9d6c796a5adbac20" + sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.4.2" build_runner: dependency: "direct dev" description: name: build_runner - sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b" + sha256: "644dc98a0f179b872f612d3eb627924b578897c629788e858157fa5e704ca0c7" url: "https://pub.dev" source: hosted - version: "2.4.6" + version: "2.4.11" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41" + sha256: e3c79f69a64bdfcd8a776a3c28db4eb6e3fb5356d013ae5eb2e52007706d5dbe url: "https://pub.dev" source: hosted - version: "7.2.10" + version: "7.3.1" built_collection: dependency: transitive description: @@ -101,10 +106,10 @@ packages: dependency: transitive description: name: built_value - sha256: ff627b645b28fb8bdb69e645f910c2458fd6b65f6585c3a53e0626024897dedf + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb url: "https://pub.dev" source: hosted - version: "8.6.2" + version: "8.9.2" characters: dependency: transitive description: @@ -133,10 +138,10 @@ packages: dependency: transitive description: name: code_builder - sha256: "4ad01d6e56db961d29661561effde45e519939fdaeb46c351275b182eac70189" + sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 url: "https://pub.dev" source: hosted - version: "4.5.0" + version: "4.10.0" collection: dependency: transitive description: @@ -173,10 +178,10 @@ packages: dependency: transitive description: name: dart_style - sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55" + sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.3.6" fake_async: dependency: transitive description: @@ -189,10 +194,10 @@ packages: dependency: transitive description: name: ffi - sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" file: dependency: "direct main" description: @@ -218,10 +223,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4" + sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" url: "https://pub.dev" source: hosted - version: "2.0.2" + version: "4.0.0" flutter_test: dependency: "direct dev" description: flutter @@ -236,10 +241,10 @@ packages: dependency: transitive description: name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "4.0.0" glob: dependency: transitive description: @@ -252,57 +257,58 @@ packages: dependency: transitive description: name: google_identity_services_web - sha256: "7940fdc3b1035db4d65d387c1bdd6f9574deaa6777411569c05ecc25672efacd" + sha256: "9482364c9f8b7bd36902572ebc3a7c2b5c8ee57a9c93e6eb5099c1a9ec5265d8" url: "https://pub.dev" source: hosted - version: "0.2.1" + version: "0.3.1+1" google_sign_in: dependency: "direct main" description: name: google_sign_in - sha256: aab6fdc41374014494f9e9026b9859e7309639d50a0bf4a2a412467a5ae4abc6 + sha256: "0b8787cb9c1a68ad398e8010e8c8766bfa33556d2ab97c439fb4137756d7308f" url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "6.2.1" google_sign_in_android: - dependency: "direct overridden" + dependency: transitive description: - path: "/Users/tvolkert/project/flutter/plugins/packages/google_sign_in/google_sign_in_android" - relative: false - source: path - version: "6.1.5" + name: google_sign_in_android + sha256: d30fb34b659679ea74397e9748b4ab5d720720d57dcc79538f1b3c4a68654cb3 + url: "https://pub.dev" + source: hosted + version: "6.1.27" google_sign_in_ios: dependency: transitive description: name: google_sign_in_ios - sha256: "6ec0e13a4c5c646471b9f6a25ceb3ae76d339889d4c0f79b729bf0714215a63e" + sha256: a058c9880be456f21e2e8571c1126eaacd570bdc5b6c6d9d15aea4bdf22ca9fe url: "https://pub.dev" source: hosted - version: "5.6.2" + version: "5.7.6" google_sign_in_platform_interface: dependency: transitive description: name: google_sign_in_platform_interface - sha256: e69553c0fc6a76216e9d06a8c3767e291ad9be42171f879aab7ab708569d4393 + sha256: "1f6e5787d7a120cc0359ddf315c92309069171306242e181c09472d1b00a2971" url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.5" google_sign_in_web: dependency: transitive description: name: google_sign_in_web - sha256: c4ef88c4033797908b8533e97216f51442909162bafc03dd42e8d1a057561c52 + sha256: d606264c7a1a526a3aa79d938b85a601d8589731a478bd4a3dcbdeb14a572228 url: "https://pub.dev" source: hosted - version: "0.12.0+3" + version: "0.12.4+1" graphs: dependency: transitive description: name: graphs - sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" html: dependency: transitive description: @@ -315,10 +321,10 @@ packages: dependency: "direct main" description: name: http - sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.2" http_multi_server: dependency: transitive description: @@ -347,34 +353,58 @@ packages: dependency: transitive description: name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf url: "https://pub.dev" source: hosted - version: "0.6.7" + version: "0.7.1" json_annotation: dependency: "direct main" description: name: json_annotation - sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" url: "https://pub.dev" source: hosted - version: "4.8.1" + version: "4.9.0" json_serializable: dependency: "direct dev" description: name: json_serializable - sha256: aa1f5a8912615733e0fdc7a02af03308933c93235bdc8d50d0b0c8a8ccb0b969 + sha256: ea1432d167339ea9b5bb153f0571d0039607a873d6e04e0117af043f14a1fd4b url: "https://pub.dev" source: hosted - version: "6.7.1" + version: "6.8.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + url: "https://pub.dev" + source: hosted + version: "10.0.5" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + url: "https://pub.dev" + source: hosted + version: "3.0.5" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" lints: dependency: transitive description: name: lints - sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "4.0.0" logging: dependency: transitive description: @@ -383,38 +413,46 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + macros: + dependency: transitive + description: + name: macros + sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" + url: "https://pub.dev" + source: hosted + version: "0.1.2-main.4" matcher: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.15.0" mime: dependency: transitive description: name: mime - sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.5" package_config: dependency: transitive description: @@ -427,74 +465,74 @@ packages: dependency: "direct main" description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_provider: dependency: "direct main" description: name: path_provider - sha256: "909b84830485dbcd0308edf6f7368bc8fd76afa26a270420f34cabea2a6467a0" + sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161 url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.3" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "5d44fc3314d969b84816b569070d7ace0f1dea04bd94a83f74c4829615d22ad8" + sha256: "30c5aa827a6ae95ce2853cdc5fe3971daaac00f6f081c419c013f7f57bff2f5e" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.2.7" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "1b744d3d774e5a879bb76d6cd1ecee2ba2c6960c03b1020cd35212f6aa267ac5" + sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.4.0" path_provider_linux: dependency: transitive description: name: path_provider_linux - sha256: ba2b77f0c52a33db09fc8caf85b12df691bf28d983e84cf87ff6d693cfa007b3 + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.2.1" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - sha256: bced5679c7df11190e1ddc35f3222c858f328fff85c3942e46e7f5589bf9eb84 + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" path_provider_windows: dependency: transitive description: name: path_provider_windows - sha256: ee0e0d164516b90ae1f970bdf29f726f1aa730d7cfc449ecc74c495378b705da + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.0" platform: dependency: transitive description: name: platform - sha256: "57c07bf82207aee366dfaa3867b3164e4f03a238a461a11b0e8a3a510d51203d" + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.5" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - sha256: "43798d895c929056255600343db8f049921cbec94d31ec87f1dc5c16c01935dd" + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted - version: "2.1.5" + version: "2.1.8" pool: dependency: transitive description: @@ -515,18 +553,10 @@ packages: dependency: transitive description: name: pubspec_parse - sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 - url: "https://pub.dev" - source: hosted - version: "1.2.3" - quiver: - dependency: transitive - description: - name: quiver - sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47 + sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "1.3.0" shelf: dependency: transitive description: @@ -539,10 +569,10 @@ packages: dependency: transitive description: name: shelf_web_socket - sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "2.0.0" sky_engine: dependency: transitive description: flutter @@ -552,10 +582,10 @@ packages: dependency: transitive description: name: source_gen - sha256: fc0da689e5302edb6177fdd964efcb7f58912f43c28c2047a808f5bfff643d16 + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.5.0" source_helper: dependency: transitive description: @@ -600,10 +630,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" term_glyph: dependency: transitive description: @@ -616,10 +646,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.7.3" timing: dependency: transitive description: @@ -648,42 +678,50 @@ packages: dependency: "direct main" description: name: video_player - sha256: "3fd106c74da32f336dc7feb65021da9b0207cb3124392935f1552834f7cce822" + sha256: e30df0d226c4ef82e2c150ebf6834b3522cf3f654d8e2f9419d376cdc071425d url: "https://pub.dev" source: hosted - version: "2.7.0" + version: "2.9.1" video_player_android: dependency: transitive description: name: video_player_android - sha256: f338a5a396c845f4632959511cad3542cdf3167e1b2a1a948ef07f7123c03608 + sha256: fdc0331ce9f808cc2714014cb8126bd6369943affefd54f8fdab0ea0bb617b7f url: "https://pub.dev" source: hosted - version: "2.4.9" + version: "2.5.2" video_player_avfoundation: dependency: transitive description: name: video_player_avfoundation - sha256: f5f5b7fe8c865be8a57fe80c2dca130772e1db775b7af4e5c5aa1905069cfc6c + sha256: d1e9a824f2b324000dc8fb2dcb2a3285b6c1c7c487521c63306cc5b394f68a7c url: "https://pub.dev" source: hosted - version: "2.4.9" + version: "2.6.1" video_player_platform_interface: dependency: transitive description: name: video_player_platform_interface - sha256: "1ca9acd7a0fb15fb1a990cb554e6f004465c6f37c99d2285766f08a4b2802988" + sha256: "236454725fafcacf98f0f39af0d7c7ab2ce84762e3b63f2cbb3ef9a7e0550bc6" url: "https://pub.dev" source: hosted - version: "6.2.0" + version: "6.2.2" video_player_web: dependency: transitive description: name: video_player_web - sha256: "44ce41424d104dfb7cf6982cc6b84af2b007a24d126406025bf40de5d481c74c" + sha256: ff4d69a6614b03f055397c27a71c9d3ddea2b2a23d71b2ba0164f59ca32b8fe2 + url: "https://pub.dev" + source: hosted + version: "2.3.1" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc url: "https://pub.dev" source: hosted - version: "2.0.16" + version: "14.2.4" watcher: dependency: transitive description: @@ -696,34 +734,34 @@ packages: dependency: transitive description: name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" url: "https://pub.dev" source: hosted - version: "0.3.0" - web_socket_channel: + version: "0.5.1" + web_socket: dependency: transitive description: - name: web_socket_channel - sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + name: web_socket + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" url: "https://pub.dev" source: hosted - version: "2.4.0" - win32: + version: "0.1.6" + web_socket_channel: dependency: transitive description: - name: win32 - sha256: "9e82a402b7f3d518fb9c02d0e9ae45952df31b9bf34d77baf19da2de03fc2aaa" + name: web_socket_channel + sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" url: "https://pub.dev" source: hosted - version: "5.0.7" + version: "3.0.1" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: f0c26453a2d47aa4c2570c6a033246a3fc62da2fe23c7ffdd0a7495086dc0247 + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.0.4" yaml: dependency: transitive description: @@ -733,5 +771,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.2.0-194.0.dev <4.0.0" - flutter: ">=3.7.0" + dart: ">=3.4.0 <4.0.0" + flutter: ">=3.22.0" diff --git a/pubspec.yaml b/pubspec.yaml index 3b1c3ef..eedde41 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: photos description: A Google Photos leanback experience -version: 1.0.11+11 +version: 1.0.12+12 environment: sdk: ">=3.0.0" @@ -24,9 +24,14 @@ dev_dependencies: build_runner: any json_serializable: any -dependency_overrides: - google_sign_in_android: - path: /Users/tvolkert/project/flutter/plugins/packages/google_sign_in/google_sign_in_android +# dependency_overrides: +# google_sign_in_android: +# path: /Users/tvolkert/project/flutter/plugins/packages/google_sign_in/google_sign_in_android +# google_sign_in_ios: +# git: +# url: https://github.com/stuartmorgan/packages.git +# ref: google-sign-in-macos +# path: packages/google_sign_in/google_sign_in_ios builders: json_serializable: any