gallery_picker/lib/controller/gallery_controller.dart

372 lines
11 KiB
Dart
Raw Normal View History

2023-01-20 09:58:21 +03:00
import 'dart:async';
2022-12-29 08:45:28 +03:00
import 'dart:io';
2023-07-15 16:44:35 +03:00
import 'package:device_info_plus/device_info_plus.dart';
2022-12-25 12:30:20 +03:00
import 'package:flutter/cupertino.dart';
2022-12-30 05:18:18 +03:00
import 'package:flutter/foundation.dart';
2022-12-25 12:30:20 +03:00
import 'package:flutter/material.dart';
import 'package:get/get.dart';
2022-12-29 08:45:28 +03:00
import 'package:permission_handler/permission_handler.dart';
2022-12-25 12:30:20 +03:00
import 'package:photo_gallery/photo_gallery.dart';
2023-07-15 16:44:35 +03:00
import '../models/config.dart';
import '../models/gallery_media.dart';
2022-12-25 12:30:20 +03:00
import '../models/media_file.dart';
2024-02-24 22:33:52 +03:00
import '/models/gallery_album.dart';
import '/models/medium.dart';
2022-12-29 08:45:28 +03:00
import 'picker_listener.dart';
2022-12-25 12:30:20 +03:00
class PhoneGalleryController extends GetxController {
late Config config;
2023-01-20 09:58:21 +03:00
void configuration(Config? config,
{required dynamic Function(List<MediaFile>) onSelect,
required Widget Function(String, MediaFile, BuildContext)? heroBuilder,
required bool isRecent,
required bool startWithRecent,
required List<MediaFile>? initSelectedMedias,
required List<MediaFile>? extraRecentMedia,
2023-01-20 09:58:21 +03:00
required Widget Function(List<MediaFile>, BuildContext)?
multipleMediasBuilder}) {
this.onSelect = onSelect;
this.heroBuilder = heroBuilder;
this.isRecent = isRecent;
this.startWithRecent = startWithRecent;
this.multipleMediasBuilder = multipleMediasBuilder;
pageController = PageController();
pickerPageController = PageController(initialPage: startWithRecent ? 0 : 1);
2022-12-25 12:30:20 +03:00
this.config = config ?? Config();
2022-12-29 08:45:28 +03:00
if (initSelectedMedias != null) {
_selectedFiles = initSelectedMedias.map((e) => e).toList();
}
if (extraRecentMedia != null) {
_extraRecentMedia = extraRecentMedia.map((e) => e).toList();
}
if (selectedFiles.isNotEmpty) {
_pickerMode = true;
}
2023-01-20 09:58:21 +03:00
configurationCompleted = true;
2022-12-25 12:30:20 +03:00
}
2023-01-20 09:58:21 +03:00
late bool startWithRecent;
late bool isRecent;
bool? permissionGranted;
2023-01-20 09:58:21 +03:00
bool configurationCompleted = false;
late Function(List<MediaFile> selectedMedias) onSelect;
2022-12-25 12:30:20 +03:00
Widget Function(String tag, MediaFile media, BuildContext context)?
heroBuilder;
Widget Function(List<MediaFile> medias, BuildContext context)?
2022-12-29 08:45:28 +03:00
multipleMediasBuilder;
2023-01-20 09:58:21 +03:00
GalleryMedia? _media;
GalleryMedia? get media => _media;
List<GalleryAlbum> get galleryAlbums => _media == null ? [] : _media!.albums;
2022-12-25 12:30:20 +03:00
List<MediaFile> _selectedFiles = [];
List<MediaFile>? _extraRecentMedia;
2022-12-25 12:30:20 +03:00
List<MediaFile> get selectedFiles => _selectedFiles;
bool _isInitialized = false;
bool get isInitialized => _isInitialized;
List<MediaFile>? get extraRecentMedia => _extraRecentMedia;
2022-12-25 12:30:20 +03:00
bool _pickerMode = false;
bool get pickerMode => _pickerMode;
2023-01-20 09:58:21 +03:00
late PageController pageController;
late PageController pickerPageController;
GalleryAlbum? selectedAlbum;
void resetBottomSheetView() {
if (permissionGranted == true) {
2023-01-20 09:58:21 +03:00
isRecent = true;
if (selectedAlbum == null) {
pickerPageController.jumpToPage(0);
} else {
pageController.jumpToPage(0);
pickerPageController = PageController();
2023-01-20 09:58:21 +03:00
}
selectedAlbum = null;
update();
}
}
void updateConfig(Config? config) {
this.config = config ?? Config();
}
2022-12-25 12:30:20 +03:00
void updateSelectedFiles(List<MediaFile> media) {
_selectedFiles = media.map((e) => e).toList();
2023-01-21 08:15:28 +03:00
if (selectedFiles.isEmpty) {
_pickerMode = false;
} else {
2022-12-30 05:18:18 +03:00
_pickerMode = true;
2022-12-29 08:45:28 +03:00
}
update();
}
void updateExtraRecentMedia(List<MediaFile> 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();
}
2023-01-20 09:58:21 +03:00
Future<void> changeAlbum(
{required GalleryAlbum album,
required BuildContext context,
required PhoneGalleryController controller,
required bool singleMedia,
required bool isBottomSheet}) async {
2022-12-29 08:45:28 +03:00
_selectedFiles.clear();
2023-01-20 09:58:21 +03:00
selectedAlbum = album;
update();
2022-12-29 08:45:28 +03:00
updatePickerListener();
2023-01-20 09:58:21 +03:00
await pageController.animateToPage(1,
duration: const Duration(milliseconds: 500), curve: Curves.easeIn);
}
Future<void> backToPicker() async {
_selectedFiles.clear();
_pickerMode = false;
pickerPageController = PageController(initialPage: 1);
update();
2023-01-20 09:58:21 +03:00
await pageController.animateToPage(0,
duration: const Duration(milliseconds: 500), curve: Curves.easeIn);
selectedAlbum = null;
update();
2022-12-25 12:30:20 +03:00
}
void unselectMedia(MediaFile file) {
_selectedFiles.removeWhere((element) => element.id == file.id);
2022-12-25 12:30:20 +03:00
if (_selectedFiles.isEmpty) {
_pickerMode = false;
}
update();
2022-12-29 08:45:28 +03:00
updatePickerListener();
2022-12-25 12:30:20 +03:00
}
void selectMedia(MediaFile file) {
if (!_selectedFiles.any((element) => element.id == file.id)) {
2022-12-25 12:30:20 +03:00
_selectedFiles.add(file);
}
if (!_pickerMode) {
_pickerMode = true;
}
update();
2022-12-29 08:45:28 +03:00
updatePickerListener();
2022-12-25 12:30:20 +03:00
}
void switchPickerMode(bool value) {
if (!value) {
2022-12-29 08:45:28 +03:00
_selectedFiles.clear();
2023-01-20 09:58:21 +03:00
updatePickerListener();
2022-12-25 12:30:20 +03:00
}
_pickerMode = value;
update();
2022-12-29 08:45:28 +03:00
}
void updatePickerListener() {
if (GetInstance().isRegistered<PickerListener>()) {
Get.find<PickerListener>().updateController(_selectedFiles);
}
}
static Future<bool> promptPermissionSetting() async {
2023-07-15 16:44:35 +03:00
if (Platform.isAndroid) {
final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
final AndroidDeviceInfo info = await deviceInfoPlugin.androidInfo;
if (info.version.sdkInt >= 33) {
if (await PhoneGalleryController.requestPermission(Permission.photos)) {
return await PhoneGalleryController.requestPermission(
Permission.videos);
} else {
return false;
}
} else {
return await PhoneGalleryController.requestPermission(
Permission.storage);
}
2023-01-20 09:58:21 +03:00
}
2023-07-15 16:44:35 +03:00
bool statusStorage =
await PhoneGalleryController.requestPermission(Permission.storage);
if (statusStorage) {
return await PhoneGalleryController.requestPermission(Permission.photos);
2022-12-29 08:45:28 +03:00
}
return false;
2022-12-25 12:30:20 +03:00
}
2023-07-15 16:44:35 +03:00
static Future<bool> requestPermission(Permission permission) async {
if (await permission.isGranted) {
return true;
} else {
var result = await permission.request();
if (result == PermissionStatus.granted) {
return true;
2023-01-20 09:58:21 +03:00
}
}
2023-07-15 16:44:35 +03:00
return false;
2023-01-20 09:58:21 +03:00
}
2024-02-24 22:33:52 +03:00
Future<void> initializeAlbums({Locale? locale}) async {
_media = await PhoneGalleryController.collectGallery(locale: locale);
2023-01-20 09:58:21 +03:00
if (_media != null) {
if (_extraRecentMedia != null) {
GalleryAlbum? recentTmp = recent;
if (recentTmp != null) {
_extraRecentMedia!.removeWhere((element) =>
recentTmp.files.any((file) => element.id == file.id));
}
}
2023-01-20 09:58:21 +03:00
permissionGranted = true;
_isInitialized = true;
} else {
permissionGranted = false;
2024-02-24 22:33:52 +03:00
permissionListener(locale: locale);
2022-12-29 08:45:28 +03:00
}
update();
}
2024-02-24 22:33:52 +03:00
void permissionListener({Locale? locale}) {
2023-01-20 09:58:21 +03:00
Timer.periodic(const Duration(seconds: 1), (timer) async {
2023-07-15 16:44:35 +03:00
if (await isGranted()) {
2024-02-24 22:33:52 +03:00
initializeAlbums(locale: locale);
2023-01-20 09:58:21 +03:00
timer.cancel();
}
});
}
2023-07-15 16:44:35 +03:00
Future<bool> isGranted() async {
if (Platform.isAndroid) {
final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
final AndroidDeviceInfo info = await deviceInfoPlugin.androidInfo;
if (info.version.sdkInt >= 33) {
if (await Permission.photos.isGranted) {
return await Permission.videos.isGranted;
} else {
return false;
}
} else {
return await Permission.storage.isGranted;
}
}
return (await Permission.storage.isGranted) &&
(await Permission.photos.isGranted);
}
2024-02-24 22:33:52 +03:00
static Future<GalleryMedia?> collectGallery({Locale? locale}) async {
2022-12-29 08:45:28 +03:00
if (await promptPermissionSetting()) {
List<GalleryAlbum> tempGalleryAlbums = [];
List<Album> photoAlbums =
await PhotoGallery.listAlbums(mediumType: MediumType.image);
List<Album> videoAlbums =
await PhotoGallery.listAlbums(mediumType: MediumType.video);
for (var photoAlbum in photoAlbums) {
GalleryAlbum entireGalleryAlbum = GalleryAlbum.album(photoAlbum);
2024-02-24 22:33:52 +03:00
await entireGalleryAlbum.initialize(locale: locale);
2022-12-29 08:45:28 +03:00
entireGalleryAlbum.setType = AlbumType.image;
2023-07-15 16:44:35 +03:00
if (videoAlbums.any((element) => element.id == photoAlbum.id)) {
Album videoAlbum =
videoAlbums.singleWhere((element) => element.id == photoAlbum.id);
GalleryAlbum videoGalleryAlbum = GalleryAlbum.album(videoAlbum);
2024-02-24 22:33:52 +03:00
await videoGalleryAlbum.initialize(locale: locale);
2022-12-29 08:45:28 +03:00
DateTime? lastPhotoDate = entireGalleryAlbum.lastDate;
DateTime? lastVideoDate = videoGalleryAlbum.lastDate;
if (lastPhotoDate == null) {
2022-12-25 12:30:20 +03:00
try {
2022-12-29 08:45:28 +03:00
entireGalleryAlbum.thumbnail =
await videoAlbum.getThumbnail(highQuality: true);
2022-12-25 12:30:20 +03:00
} catch (e) {
2022-12-30 05:18:18 +03:00
if (kDebugMode) {
print(e);
}
2022-12-25 12:30:20 +03:00
}
2022-12-29 08:45:28 +03:00
} else if (lastVideoDate == null) {
} else {
if (lastVideoDate.isAfter(lastPhotoDate)) {
try {
entireGalleryAlbum.thumbnail =
await videoAlbum.getThumbnail(highQuality: true);
} catch (e) {
entireGalleryAlbum.thumbnail = null;
2022-12-30 05:18:18 +03:00
if (kDebugMode) {
print(e);
}
2022-12-29 08:45:28 +03:00
}
}
2022-12-25 12:30:20 +03:00
}
2022-12-29 08:45:28 +03:00
for (var file in videoGalleryAlbum.files) {
2024-02-24 22:33:52 +03:00
entireGalleryAlbum.addFile(file, locale: locale);
2022-12-29 08:45:28 +03:00
}
entireGalleryAlbum.sort();
entireGalleryAlbum.setType = AlbumType.mixed;
videoAlbums.remove(videoAlbum);
2022-12-25 12:30:20 +03:00
}
2022-12-29 08:45:28 +03:00
tempGalleryAlbums.add(entireGalleryAlbum);
}
for (var videoAlbum in videoAlbums) {
GalleryAlbum galleryVideoAlbum = GalleryAlbum.album(videoAlbum);
2024-02-24 22:33:52 +03:00
await galleryVideoAlbum.initialize(locale: locale);
2022-12-29 08:45:28 +03:00
galleryVideoAlbum.setType = AlbumType.video;
tempGalleryAlbums.add(galleryVideoAlbum);
2022-12-25 12:30:20 +03:00
}
2022-12-29 08:45:28 +03:00
return GalleryMedia(tempGalleryAlbums);
} else {
return null;
}
2022-12-25 12:30:20 +03:00
}
GalleryAlbum? get recent {
2023-01-20 09:58:21 +03:00
return galleryAlbums.isNotEmpty
? galleryAlbums.singleWhere((element) => element.album.name == "All")
2022-12-25 12:30:20 +03:00
: 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;
// }
//}
2022-12-25 12:30:20 +03:00
List<Medium> sortAlbumMediaDates(List<Medium> mediumList) {
mediumList.sort((a, b) {
if (a.lastDate == null) {
return 1;
} else if (b.lastDate == null) {
return -1;
} else {
return a.lastDate!.compareTo(b.lastDate!);
}
});
return mediumList;
}
bool isSelectedMedia(MediaFile file) {
2023-01-20 09:58:21 +03:00
return _selectedFiles.any((element) => element.id == file.id);
2022-12-29 08:45:28 +03:00
}
void disposeController() {
2023-01-20 09:58:21 +03:00
_media = null;
2022-12-29 08:45:28 +03:00
_selectedFiles = [];
_isInitialized = false;
Get.delete<PhoneGalleryController>();
update();
2022-12-25 12:30:20 +03:00
}
}