From 1bf66592fe251a0ed997f99e259cb660d7f8e9ba Mon Sep 17 00:00:00 2001 From: Furkan Date: Sat, 31 Dec 2022 16:43:05 +0300 Subject: [PATCH] extraRecentMedia parameter added. MediaFile.file() added. Documantation changed --- .flutter-plugins-dependencies | 2 +- README.md | 39 +++++++----- .../lib/examples/gallery_picker_example.dart | 10 ++-- .../examples/pick_medias_with_builder.dart | 8 +-- example/lib/examples/whatsapp_pick_photo.dart | 2 +- example/lib/main.dart | 20 ++++--- example/pubspec.lock | 2 +- example/pubspec.yaml | 1 + lib/controller/gallery_controller.dart | 59 ++++++++++++++++--- lib/gallery_picker.dart | 38 +++++++----- lib/models/config.dart | 9 ++- lib/models/gallery_album.dart | 53 ++++++++--------- lib/models/gallery_media.dart | 4 +- lib/models/media_file.dart | 36 +++++++++-- ...ilder.dart => gallery_picker_builder.dart} | 7 ++- lib/views/album_view/album_appbar.dart | 2 +- lib/views/album_view/album_medias_view.dart | 29 ++++++++- lib/views/bottom_sheet.dart | 41 ++++++++----- .../gallery_picker_view.dart | 30 ++++++---- 19 files changed, 268 insertions(+), 124 deletions(-) rename lib/user_widgets/{files_stream_builder.dart => gallery_picker_builder.dart} (67%) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index dd28913..8d4740d 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"permission_handler_apple","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\permission_handler_apple-9.0.7\\\\","native_build":true,"dependencies":[]},{"name":"photo_gallery","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\photo_gallery-1.1.1\\\\","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\video_player_avfoundation-2.3.8\\\\","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\video_thumbnail-0.5.3\\\\","native_build":true,"dependencies":[]}],"android":[{"name":"permission_handler_android","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\permission_handler_android-10.2.0\\\\","native_build":true,"dependencies":[]},{"name":"photo_gallery","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\photo_gallery-1.1.1\\\\","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\video_player_android-2.3.10\\\\","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\video_thumbnail-0.5.3\\\\","native_build":true,"dependencies":[]}],"macos":[],"linux":[],"windows":[{"name":"permission_handler_windows","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\permission_handler_windows-0.1.2\\\\","native_build":true,"dependencies":[]}],"web":[{"name":"video_player_web","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\video_player_web-2.0.13\\\\","dependencies":[]}]},"dependencyGraph":[{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"photo_gallery","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_thumbnail","dependencies":[]}],"date_created":"2022-12-30 05:18:44.302087","version":"3.3.9"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"permission_handler_apple","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\permission_handler_apple-9.0.7\\\\","native_build":true,"dependencies":[]},{"name":"photo_gallery","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\photo_gallery-1.1.1\\\\","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\video_player_avfoundation-2.3.8\\\\","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\video_thumbnail-0.5.3\\\\","native_build":true,"dependencies":[]}],"android":[{"name":"permission_handler_android","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\permission_handler_android-10.2.0\\\\","native_build":true,"dependencies":[]},{"name":"photo_gallery","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\photo_gallery-1.1.1\\\\","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\video_player_android-2.3.10\\\\","native_build":true,"dependencies":[]},{"name":"video_thumbnail","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\video_thumbnail-0.5.3\\\\","native_build":true,"dependencies":[]}],"macos":[],"linux":[],"windows":[{"name":"permission_handler_windows","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\permission_handler_windows-0.1.2\\\\","native_build":true,"dependencies":[]}],"web":[{"name":"video_player_web","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\video_player_web-2.0.13\\\\","dependencies":[]}]},"dependencyGraph":[{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"photo_gallery","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"video_thumbnail","dependencies":[]}],"date_created":"2022-12-31 16:40:26.960029","version":"3.3.10"} \ No newline at end of file diff --git a/README.md b/README.md index ef3bfc9..e34b9fc 100644 --- a/README.md +++ b/README.md @@ -83,12 +83,12 @@ Quick and simple usage example: ### Pick Single File ```dart -MediaFile? media = await GalleryPicker.pickMedias(context: context,singleMedia: true); +MediaFile? singleMedia = await GalleryPicker.pickMedia(context: context,singleMedia: true); ``` ### Pick Multiple Files ```dart -List? medias = await GalleryPicker.pickMedias(context: context); +List? media = await GalleryPicker.pickMedia(context: context); ``` ### Get All Media Files in Gallery @@ -121,7 +121,8 @@ There is an example at `example/lib/examples/bottom_sheet_example.dart` to see h title: Text(widget.title), ), body: BottomSheetLayout( - onSelect: (medias) {}, + config: Config() + onSelect: (media) {}, child: Column( children: [ ``` @@ -130,13 +131,13 @@ There is an example at `example/lib/examples/bottom_sheet_example.dart` to see h Within the Gallery Picker you can design a page that will be redirected after selecting any image(s). -Note: There are two builder called multipleMediasBuilder and heroBuilder. If you designed both of them, multipleMediasBuilder will be shown after picking multiple media files, heroBuilder will be shown after picking a single media. Use given hero tag to view your Hero image. You can see a simple example below. +Note: There are two builder called multipleMediaBuilder and heroBuilder. If you designed both of them, multipleMediaBuilder will be shown after picking multiple media files, heroBuilder will be shown after picking a single media. Use given hero tag to view your Hero image. You can see a simple example below. There is an example at `example/lib/examples/pick_medias_with_builder.dart` to see how it could be done. ```dart - GalleryPicker.pickMediasWithBuilder( - multipleMediasBuilder: ((medias, context) { + GalleryPicker.pickMediaWithBuilder( + multipleMediaBuilder: ((media, context) { return Scaffold( appBar: AppBar( title: const Text('Flippers Page'), @@ -146,9 +147,9 @@ There is an example at `example/lib/examples/pick_medias_with_builder.dart` to s mainAxisSpacing: 5, crossAxisSpacing: 5, children: [ - for (var media in medias) + for (var mediaFile in media) ThumbnailMedia( - media: media, + media: mediaFile, ) ], ), @@ -159,7 +160,7 @@ There is an example at `example/lib/examples/pick_medias_with_builder.dart` to s MaterialPageRoute( builder: (context) => MyHomePage( title: "Selected Medias", - medias: medias, + medias: media, )), ); GalleryPicker.dispose(); @@ -220,7 +221,7 @@ A Config class is provided to user to customize your gallery picker. You can cus #### Customizable appereance features ```dart -List? medias = await GalleryPicker.pickMedias( +List? media = await GalleryPicker.pickMedia( context: context, config: Config( backgroundColor: Colors.white, @@ -273,7 +274,7 @@ List? medias = await GalleryPicker.pickMedias( #### Appearance Mode ```dart -List? medias = await GalleryPicker.pickMedias( +List? media = await GalleryPicker.pickMedia( context: context, config: Config( mode: Mode.dark @@ -284,9 +285,19 @@ List? medias = await GalleryPicker.pickMedias( #### Give an initial selected media files ```dart -List? medias = await GalleryPicker.pickMedias( +List? media = await GalleryPicker.pickMedia( context: context, - initSelectedMedias: this.selectedMedias, + initSelectedMedia: initSelectedMedia, + ) +``` +#### Give extra media files that will be included in recent +You can give extra pictures to appear on the recent page. You should define these files with MediaFile.file() + +```dart +MediaFile file = MediaFile.file(id: "id", file: File("path"), type: MediaType.image); +List? media = await GalleryPicker.pickMedia( + context: context, + extraRecentMedia: [file], ) ``` #### Select your priority page @@ -294,7 +305,7 @@ List? medias = await GalleryPicker.pickMedias( There are two pages called "Recent" and "Gallery". You could change the initial page. ```dart -List? medias = await GalleryPicker.pickMedias( +List? media = await GalleryPicker.pickMedia( context: context, startWithRecent: true, ) diff --git a/example/lib/examples/gallery_picker_example.dart b/example/lib/examples/gallery_picker_example.dart index 1ac9dfe..e33afa2 100644 --- a/example/lib/examples/gallery_picker_example.dart +++ b/example/lib/examples/gallery_picker_example.dart @@ -123,21 +123,21 @@ class _GalleryPickerExampleState extends State { ), ), floatingActionButton: FloatingActionButton( - onPressed: pickMedias, + onPressed: pickMedia, tooltip: 'Increment', child: const Icon(Icons.add), ), ); } - Future pickMedias() async { - List? medias = await GalleryPicker.pickMedias( + Future pickMedia() async { + List? media = await GalleryPicker.pickMedia( context: context, config: Config(mode: Mode.dark), ); - if (medias != null) { + if (media != null) { setState(() { - selectedMedias += medias; + selectedMedias += media; }); } } diff --git a/example/lib/examples/pick_medias_with_builder.dart b/example/lib/examples/pick_medias_with_builder.dart index bc9c95f..bd28b82 100644 --- a/example/lib/examples/pick_medias_with_builder.dart +++ b/example/lib/examples/pick_medias_with_builder.dart @@ -27,7 +27,7 @@ class _PickMediasWithBuilderState extends State { children: [ const Spacer(), TextButton( - onPressed: pickMediasWithBuilder, + onPressed: pickMediaWithBuilder, child: Container( width: 300, height: 60, @@ -49,9 +49,9 @@ class _PickMediasWithBuilderState extends State { ); } - pickMediasWithBuilder() { - GalleryPicker.pickMediasWithBuilder( - multipleMediasBuilder: ((medias, context) { + pickMediaWithBuilder() { + GalleryPicker.pickMediaWithBuilder( + multipleMediaBuilder: ((medias, context) { return MultipleMediasView(medias); }), heroBuilder: (tag, media, context) { diff --git a/example/lib/examples/whatsapp_pick_photo.dart b/example/lib/examples/whatsapp_pick_photo.dart index f490afe..e7304f1 100644 --- a/example/lib/examples/whatsapp_pick_photo.dart +++ b/example/lib/examples/whatsapp_pick_photo.dart @@ -79,7 +79,7 @@ class _WhatsappPickPhotoState extends State { this.selectedMedias = selectedMedias; setState(() {}); }, - initSelectedMedias: selectedMedias, + initSelectedMedia: selectedMedias, config: Config(mode: Mode.dark), child: Stack( children: [ diff --git a/example/lib/main.dart b/example/lib/main.dart index d9b1638..467720a 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -163,28 +163,30 @@ class _MyHomePageState extends State { ), ), floatingActionButton: FloatingActionButton( - onPressed: pickMedias, + onPressed: pickMedia, tooltip: 'Increment', child: const Icon(Icons.add), ), ); } - Future pickMedias() async { - List? medias = await GalleryPicker.pickMedias( + Future pickMedia() async { + List? media = await GalleryPicker.pickMedia( context: context, - initSelectedMedias: selectedMedias, + config: Config(lastWeek: "Bu hafta"), + initSelectedMedia: selectedMedias, + extraRecentMedia: selectedMedias, startWithRecent: true); - if (medias != null) { + if (media != null) { setState(() { - selectedMedias += medias; + selectedMedias += media; }); } } - pickMediasWithBuilder() { - GalleryPicker.pickMediasWithBuilder( - multipleMediasBuilder: ((medias, context) { + pickMediaWithBuilder() { + GalleryPicker.pickMediaWithBuilder( + multipleMediaBuilder: ((medias, context) { return MultipleMediasView(medias); }), heroBuilder: (tag, media, context) { diff --git a/example/pubspec.lock b/example/pubspec.lock index 3975517..26eaa51 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -136,7 +136,7 @@ packages: source: sdk version: "0.0.0" gallery_picker: - dependency: "direct overridden" + dependency: "direct dev" description: path: ".." relative: true diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 77f908a..5a7221a 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -49,6 +49,7 @@ dev_dependencies: # rules and activating additional ones. flutter_lints: ^2.0.0 camera: ^0.10.1 + gallery_picker: ^0.0.6 dependency_overrides: gallery_picker: diff --git a/lib/controller/gallery_controller.dart b/lib/controller/gallery_controller.dart index 1556399..56dfb0a 100644 --- a/lib/controller/gallery_controller.dart +++ b/lib/controller/gallery_controller.dart @@ -19,12 +19,16 @@ class PhoneGalleryController extends GetxController { {required this.onSelect, required this.heroBuilder, required this.isRecent, - List? initSelectedMedias, + required List? initSelectedMedias, + required List? extraRecentMedia, required this.multipleMediasBuilder}) { this.config = config ?? Config(); if (initSelectedMedias != null) { _selectedFiles = initSelectedMedias.map((e) => e).toList(); } + if (extraRecentMedia != null) { + _extraRecentMedia = extraRecentMedia.map((e) => e).toList(); + } } bool isRecent; Function(List selectedMedias) onSelect; @@ -36,20 +40,32 @@ class PhoneGalleryController extends GetxController { List _galleryAlbums = []; List get galleryAlbums => _galleryAlbums; List _selectedFiles = []; + List? _extraRecentMedia; List get selectedFiles => _selectedFiles; bool _isInitialized = false; bool get isInitialized => _isInitialized; + List? get extraRecentMedia => _extraRecentMedia; bool _pickerMode = false; bool get pickerMode => _pickerMode; - void updateSelectedFiles(List medias) { - _selectedFiles = medias; + void updateSelectedFiles(List media) { + _selectedFiles = media.map((e) => e).toList(); if (selectedFiles.isNotEmpty) { _pickerMode = true; } update(); } + void updateExtraRecentMedia(List media) { + _extraRecentMedia = media.map((e) => e).toList(); + GalleryAlbum? recentTmp = recent; + if (recentTmp != null) { + _extraRecentMedia!.removeWhere( + (element) => recentTmp.files.any((file) => element.id == file.id)); + } + update(); + } + void changeAlbum(GalleryAlbum? album) { selectedAlbum = album; _selectedFiles.clear(); @@ -106,7 +122,15 @@ class PhoneGalleryController extends GetxController { GalleryMedia? media = await PhoneGalleryController.collectGallery; if (media != null) { _galleryAlbums = media.albums; + if (_extraRecentMedia != null) { + GalleryAlbum? recentTmp = recent; + if (recentTmp != null) { + _extraRecentMedia!.removeWhere((element) => + recentTmp.files.any((file) => element.id == file.id)); + } + } } + _isInitialized = true; update(); } @@ -121,13 +145,13 @@ class PhoneGalleryController extends GetxController { await PhotoGallery.listAlbums(mediumType: MediumType.video); for (var photoAlbum in photoAlbums) { - GalleryAlbum entireGalleryAlbum = GalleryAlbum(album: photoAlbum); + GalleryAlbum entireGalleryAlbum = GalleryAlbum.album(photoAlbum); await entireGalleryAlbum.initialize(); entireGalleryAlbum.setType = AlbumType.image; if (videoAlbums.any((element) => element.name == photoAlbum.name)) { Album videoAlbum = videoAlbums .singleWhere((element) => element.name == photoAlbum.name); - GalleryAlbum videoGalleryAlbum = GalleryAlbum(album: videoAlbum); + GalleryAlbum videoGalleryAlbum = GalleryAlbum.album(videoAlbum); await videoGalleryAlbum.initialize(); DateTime? lastPhotoDate = entireGalleryAlbum.lastDate; DateTime? lastVideoDate = videoGalleryAlbum.lastDate; @@ -165,7 +189,7 @@ class PhoneGalleryController extends GetxController { tempGalleryAlbums.add(entireGalleryAlbum); } for (var videoAlbum in videoAlbums) { - GalleryAlbum galleryVideoAlbum = GalleryAlbum(album: videoAlbum); + GalleryAlbum galleryVideoAlbum = GalleryAlbum.album(videoAlbum); await galleryVideoAlbum.initialize(); galleryVideoAlbum.setType = AlbumType.video; tempGalleryAlbums.add(galleryVideoAlbum); @@ -178,10 +202,31 @@ class PhoneGalleryController extends GetxController { } GalleryAlbum? get recent { - return _isInitialized + return _galleryAlbums.isNotEmpty ? _galleryAlbums.singleWhere((element) => element.album.name == "All") : null; } + //GalleryAlbum? get recent { + // if (_isInitialized) { + // GalleryAlbum? recent; + // for (var album in _galleryAlbums) { + // if (recent == null || (album.count > recent.count)) { + // recent = album; + // } + // } + // if (recent != null) { + // return GalleryAlbum( + // album: recent.album, + // type: recent.type, + // thumbnail: recent.thumbnail, + // dateCategories: recent.dateCategories); + // } else { + // return null; + // } + // } else { + // return null; + // } + //} List sortAlbumMediaDates(List mediumList) { mediumList.sort((a, b) { diff --git a/lib/gallery_picker.dart b/lib/gallery_picker.dart index b9a0c9f..0e8d50a 100644 --- a/lib/gallery_picker.dart +++ b/lib/gallery_picker.dart @@ -11,7 +11,7 @@ export 'user_widgets/album_categories_view.dart'; export 'user_widgets/album_medias.dart'; export 'user_widgets/date_category_view.dart'; export 'user_widgets/thumbnail_album.dart'; -export 'user_widgets/files_stream_builder.dart'; +export 'user_widgets/gallery_picker_builder.dart'; export 'user_widgets/photo_provider.dart'; export 'user_widgets/video_provider.dart'; export 'user_widgets/media_provider.dart'; @@ -48,45 +48,53 @@ class GalleryPicker { } } - static Future?> pickMedias( + static Future?> pickMedia( {Config? config, bool startWithRecent = false, - List? initSelectedMedias, + bool singleMedia = false, + List? initSelectedMedia, + List? extraRecentMedia, required BuildContext context}) async { - List? medias; + List? media; await Navigator.push( context, MaterialPageRoute( builder: (context) => GalleryPickerView( - onSelect: (mediasTmp) { - medias = mediasTmp; + onSelect: (mediaTmp) { + media = mediaTmp; }, config: config, - initSelectedMedias: initSelectedMedias, + singleMedia: singleMedia, + initSelectedMedia: initSelectedMedia, + extraRecentMedia: extraRecentMedia, startWithRecent: startWithRecent, )), ); - return medias; + return media; } - static Future pickMediasWithBuilder( + static Future pickMediaWithBuilder( {Config? config, - required Widget Function(List medias, BuildContext context)? - multipleMediasBuilder, + required Widget Function(List media, BuildContext context)? + multipleMediaBuilder, Widget Function(String tag, MediaFile media, BuildContext context)? heroBuilder, - List? initSelectedMedias, + bool singleMedia = false, + List? initSelectedMedia, + List? extraRecentMedia, bool startWithRecent = false, required BuildContext context}) async { await Navigator.push( context, MaterialPageRoute( builder: (context) => GalleryPickerView( - onSelect: (medias) {}, - multipleMediasBuilder: multipleMediasBuilder, + onSelect: (media) {}, + multipleMediaBuilder: multipleMediaBuilder, heroBuilder: heroBuilder, + singleMedia: singleMedia, config: config, - initSelectedMedias: initSelectedMedias, + initSelectedMedia: initSelectedMedia, + extraRecentMedia: extraRecentMedia, startWithRecent: startWithRecent, )), ); diff --git a/lib/models/config.dart b/lib/models/config.dart index d7f0598..ae55019 100644 --- a/lib/models/config.dart +++ b/lib/models/config.dart @@ -13,7 +13,13 @@ class Config { appbarTextStyle, selectedMenuStyle, unselectedMenuStyle; - String recents, gallery, lastMonth, lastWeek, tapPhotoSelect, selected; + String recents, + recent, + gallery, + lastMonth, + lastWeek, + tapPhotoSelect, + selected; List months; Mode mode; @@ -28,6 +34,7 @@ class Config { TextStyle? textStyle, TextStyle? appbarTextStyle, this.recents = "RECENTS", + this.recent = "Recent", this.gallery = "GALLERY", this.lastMonth = "Last Month", this.lastWeek = "Last Week", diff --git a/lib/models/gallery_album.dart b/lib/models/gallery_album.dart index 3dc5158..751b007 100644 --- a/lib/models/gallery_album.dart +++ b/lib/models/gallery_album.dart @@ -1,26 +1,36 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import 'package:intl/intl.dart'; import 'package:photo_gallery/photo_gallery.dart'; +import '../controller/gallery_controller.dart'; import '/models/media_file.dart'; import '/models/medium.dart'; +import 'config.dart'; class GalleryAlbum { - Album album; + late Album album; late List? thumbnail; List dateCategories = []; + late AlbumType type; int get count => dateCategories.expand((element) => element.files).toList().length; String? get name => album.name; + GalleryAlbum.album(this.album); + + GalleryAlbum( + {required this.album, + required this.type, + this.thumbnail, + this.dateCategories = const []}); + List get medias { return dateCategories .expand((element) => element.files) .toList(); } - late AlbumType type; - set setType(AlbumType type) { this.type = type; } @@ -36,10 +46,6 @@ class GalleryAlbum { } } - GalleryAlbum({ - required this.album, - }); - Future initialize() async { List dateCategory = []; for (var medium in sortAlbumMediaDates((await album.listMedia()).items)) { @@ -76,14 +82,15 @@ class GalleryAlbum { dateCategories.expand((element) => element.files).toList(); String getDateCategory(Medium mediaFile) { + Config config = Get.find().config; if (daysBetween(mediaFile.lastDate!) <= 3) { - return "Recent"; + return config.recent; } else if (daysBetween(mediaFile.lastDate!) > 3 && daysBetween(mediaFile.lastDate!) <= 7) { - return "Last week"; + return config.lastWeek; } else if (daysBetween(mediaFile.lastDate!) > 7 && daysBetween(mediaFile.lastDate!) <= 31) { - return "Last month"; + return config.lastMonth; } else if (daysBetween(mediaFile.lastDate!) > 31 && daysBetween(mediaFile.lastDate!) <= 365) { return DateFormat.MMMM().format(mediaFile.lastDate!).toString(); @@ -140,31 +147,19 @@ class GalleryAlbum { } } -List dates = [ - "Recent", - "Last week", - "Last month", - "January", - "February", - "March", - "April", - "May", - "June", - "July", - "August", - "September", - "October", - "November", - "December" -]; - class DateCategory { String name; List files; DateCategory({required this.files, required this.name}); int getIndexOfCategory() { - int index = dates.indexOf(name); + Config config = Get.find().config; + int index = [ + config.recent, + config.lastWeek, + config.lastMonth, + config.months + ].indexOf(name); if (index == -1) { return 3000 - int.parse(name); } else { diff --git a/lib/models/gallery_media.dart b/lib/models/gallery_media.dart index da5f167..36d0c29 100644 --- a/lib/models/gallery_media.dart +++ b/lib/models/gallery_media.dart @@ -5,12 +5,12 @@ import 'gallery_album.dart'; class GalleryMedia { List albums; GalleryAlbum? get recent { - return albums.singleWhere((element) => element.album.name == "All"); + return albums.singleWhere((element) => element.name == "All"); } GalleryAlbum? getAlbum(String name) { try { - return albums.singleWhere((element) => element.album.name == name); + return albums.singleWhere((element) => element.name == name); } catch (e) { if (kDebugMode) { print(e); diff --git a/lib/models/media_file.dart b/lib/models/media_file.dart index c6498cd..c671441 100644 --- a/lib/models/media_file.dart +++ b/lib/models/media_file.dart @@ -3,10 +3,13 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:get/get.dart'; import 'package:photo_gallery/photo_gallery.dart'; +import 'package:video_thumbnail/video_thumbnail.dart'; import '../controller/gallery_controller.dart'; +enum MediaType { image, video } + class MediaFile { - Medium medium; + late Medium medium; MediumType? type; Uint8List? thumbnail; Uint8List? data; @@ -17,18 +20,39 @@ class MediaFile { type = medium.mediumType; id = medium.id; } - Future getThumbnail() async { + MediaFile.file( + {required this.id, required this.file, required MediaType type}) { + this.type = type == MediaType.image ? MediumType.image : MediumType.video; + medium = Medium(id: id); + } + + Future getThumbnail() async { try { - thumbnail = - Uint8List.fromList(await medium.getThumbnail(highQuality: true)); + if (file != null) { + thumbnail = await VideoThumbnail.thumbnailData( + video: file!.path, + imageFormat: ImageFormat.JPEG, + maxWidth: + 128, // specify the width of the thumbnail, let the height auto-scaled to keep the source aspect ratio + quality: 25, + ); + } else { + thumbnail = + Uint8List.fromList(await medium.getThumbnail(highQuality: true)); + } } catch (e) { thumbnailFailed = true; } + return thumbnail; } Future getFile() async { - file = await medium.getFile(); - return file!; + if (file == null) { + file = await medium.getFile(); + return file!; + } else { + return file!; + } } Future getData() async { diff --git a/lib/user_widgets/files_stream_builder.dart b/lib/user_widgets/gallery_picker_builder.dart similarity index 67% rename from lib/user_widgets/files_stream_builder.dart rename to lib/user_widgets/gallery_picker_builder.dart index 3a7c8b3..afe660f 100644 --- a/lib/user_widgets/files_stream_builder.dart +++ b/lib/user_widgets/gallery_picker_builder.dart @@ -3,9 +3,10 @@ import 'package:get/get.dart'; import '../controller/picker_listener.dart'; import '../models/media_file.dart'; -class FilesStreamBuilder extends StatelessWidget { - final Widget Function(List? medias, BuildContext context) builder; - FilesStreamBuilder({super.key, required this.builder}) { +class GalleryPickerBuilder extends StatelessWidget { + final Widget Function(List? selectedFiles, BuildContext context) + builder; + GalleryPickerBuilder({super.key, required this.builder}) { Get.put(PickerListener()); } diff --git a/lib/views/album_view/album_appbar.dart b/lib/views/album_view/album_appbar.dart index 548e88d..6c54b48 100644 --- a/lib/views/album_view/album_appbar.dart +++ b/lib/views/album_view/album_appbar.dart @@ -50,7 +50,7 @@ class AlbumAppBar extends StatelessWidget with PreferredSizeWidget { Widget getTitle() { if (!controller.pickerMode && controller.selectedFiles.isEmpty) { return Text( - album.album.name!, + album.name!, style: controller.config.appbarTextStyle, ); } else if (controller.pickerMode && controller.selectedFiles.isEmpty) { diff --git a/lib/views/album_view/album_medias_view.dart b/lib/views/album_view/album_medias_view.dart index 2733086..7de4713 100644 --- a/lib/views/album_view/album_medias_view.dart +++ b/lib/views/album_view/album_medias_view.dart @@ -19,7 +19,7 @@ class AlbumMediasView extends StatelessWidget { children: [ ListView( children: [ - for (var category in galleryAlbum.dateCategories) + for (var category in checkCategories(galleryAlbum.dateCategories)) DateCategoryWiew( category: category, controller: controller, @@ -36,4 +36,31 @@ class AlbumMediasView extends StatelessWidget { ], ); } + + List checkCategories(List categories) { + if (controller.isRecent && + controller.extraRecentMedia != null && + controller.extraRecentMedia!.isNotEmpty) { + List categoriesTmp = categories.map((e) => e).toList(); + int index = categoriesTmp + .indexWhere((element) => element.name == controller.config.recent); + if (index != -1) { + DateCategory category = DateCategory(files: [ + ...controller.extraRecentMedia!, + ...categoriesTmp[index].files + ], name: categoriesTmp[index].name); + categoriesTmp[index] = category; + return categoriesTmp; + } else { + return [ + DateCategory( + files: controller.extraRecentMedia!, + name: controller.config.recent), + ...categoriesTmp + ]; + } + } else { + return categories; + } + } } diff --git a/lib/views/bottom_sheet.dart b/lib/views/bottom_sheet.dart index dd4ab2f..c36c283 100644 --- a/lib/views/bottom_sheet.dart +++ b/lib/views/bottom_sheet.dart @@ -8,12 +8,14 @@ import '../controller/bottom_sheet_controller.dart'; class BottomSheetLayout extends StatefulWidget { final Widget child; final Config? config; - final List? initSelectedMedias; - final Function(List selectedMedias) onSelect; + final List? initSelectedMedia; + final List? extraRecentMedia; + final bool singleMedia; + final Function(List selectedMedia) onSelect; final Widget Function(String tag, MediaFile media, BuildContext context)? heroBuilder; - final Widget Function(List medias, BuildContext context)? - multipleMediasBuilder; + final Widget Function(List media, BuildContext context)? + multipleMediaBuilder; final bool startWithRecent; BottomSheetLayout( {super.key, @@ -21,13 +23,20 @@ class BottomSheetLayout extends StatefulWidget { required this.onSelect, this.config, this.heroBuilder, - this.initSelectedMedias, - this.multipleMediasBuilder, + this.initSelectedMedia, + this.extraRecentMedia, + this.singleMedia = false, + this.multipleMediaBuilder, this.startWithRecent = true}) { - if (initSelectedMedias != null && - GetInstance().isRegistered()) { - Get.find() - .updateSelectedFiles(initSelectedMedias!); + if (GetInstance().isRegistered()) { + if (initSelectedMedia != null) { + Get.find() + .updateSelectedFiles(initSelectedMedia!); + } + if (extraRecentMedia != null) { + Get.find() + .updateExtraRecentMedia(extraRecentMedia!); + } } } @@ -97,8 +106,10 @@ class _BottomSheetLayoutState extends State { config: widget.config, sheetController: bottomSheetBarController, heroBuilder: widget.heroBuilder, - multipleMediasBuilder: widget.multipleMediasBuilder, - initSelectedMedias: widget.initSelectedMedias, + multipleMediaBuilder: widget.multipleMediaBuilder, + singleMedia: widget.singleMedia, + initSelectedMedia: widget.initSelectedMedia, + extraRecentMedia: widget.extraRecentMedia, startWithRecent: widget.startWithRecent, ) : Container( @@ -115,8 +126,10 @@ class _BottomSheetLayoutState extends State { config: widget.config, sheetController: bottomSheetBarController, heroBuilder: widget.heroBuilder, - multipleMediasBuilder: widget.multipleMediasBuilder, - initSelectedMedias: widget.initSelectedMedias, + singleMedia: widget.singleMedia, + multipleMediaBuilder: widget.multipleMediaBuilder, + initSelectedMedia: widget.initSelectedMedia, + extraRecentMedia: widget.extraRecentMedia, startWithRecent: widget.startWithRecent, ), viewPicker: controller.isClosing ? false : viewCollapsedPicker, diff --git a/lib/views/gallery_picker_view/gallery_picker_view.dart b/lib/views/gallery_picker_view/gallery_picker_view.dart index 235c6b7..fbdd025 100644 --- a/lib/views/gallery_picker_view/gallery_picker_view.dart +++ b/lib/views/gallery_picker_view/gallery_picker_view.dart @@ -4,6 +4,7 @@ import 'package:get/get.dart'; import '../../controller/bottom_sheet_controller.dart'; import '../../controller/gallery_controller.dart'; import '../../models/config.dart'; +import '../../models/gallery_album.dart'; import '../../models/media_file.dart'; import '../album_categories_view/album_categories_view.dart'; import '../album_view/album_page.dart'; @@ -13,24 +14,26 @@ import 'reload_gallery.dart'; class GalleryPickerView extends StatefulWidget { final Config? config; - final Function(List selectedMedias) onSelect; + final Function(List selectedMedia) onSelect; final Widget Function(String tag, MediaFile media, BuildContext context)? heroBuilder; - final Widget Function(List medias, BuildContext context)? - multipleMediasBuilder; + final Widget Function(List media, BuildContext context)? + multipleMediaBuilder; final bool startWithRecent; final BottomSheetBarController? sheetController; - final List? initSelectedMedias; + final List? initSelectedMedia; + final List? extraRecentMedia; final bool singleMedia; const GalleryPickerView( {super.key, this.config, required this.onSelect, - this.initSelectedMedias, + this.initSelectedMedia, + this.extraRecentMedia, this.singleMedia = false, this.sheetController, this.heroBuilder, - this.multipleMediasBuilder, + this.multipleMediaBuilder, this.startWithRecent = false}); @override @@ -54,8 +57,9 @@ class _GalleryPickerState extends State { galleryController = Get.put(PhoneGalleryController(widget.config, onSelect: widget.onSelect, heroBuilder: widget.heroBuilder, - multipleMediasBuilder: widget.multipleMediasBuilder, - initSelectedMedias: widget.initSelectedMedias, + multipleMediasBuilder: widget.multipleMediaBuilder, + initSelectedMedias: widget.initSelectedMedia, + extraRecentMedia: widget.extraRecentMedia, isRecent: widget.startWithRecent)); config = galleryController.config; } @@ -83,10 +87,15 @@ class _GalleryPickerState extends State { super.dispose(); } + GalleryAlbum? selectedAlbum; @override Widget build(BuildContext context) { double width = MediaQuery.of(context).size.width; return GetBuilder(builder: (controller) { + if (controller.selectedAlbum == null && selectedAlbum != null) { + _scrollController = PageController(initialPage: 1); + } + selectedAlbum = controller.selectedAlbum; return GetInstance().isRegistered() ? controller.selectedAlbum == null ? Scaffold( @@ -208,8 +217,9 @@ class _GalleryPickerState extends State { galleryController = Get.put(PhoneGalleryController(config, onSelect: widget.onSelect, heroBuilder: widget.heroBuilder, - initSelectedMedias: widget.initSelectedMedias, - multipleMediasBuilder: widget.multipleMediasBuilder, + initSelectedMedias: widget.initSelectedMedia, + extraRecentMedia: widget.extraRecentMedia, + multipleMediasBuilder: widget.multipleMediaBuilder, isRecent: widget.startWithRecent)); await controller.initializeAlbums(); if (bottomSheetController != null) {