mc_gallery/lib/features/home/views/gallery/gallery_view_model.dart

132 lines
4.8 KiB
Dart
Raw Normal View History

2022-12-23 10:20:46 +00:00
import 'dart:async';
2022-12-20 20:52:24 +00:00
import 'package:flutter/foundation.dart';
2022-12-22 21:29:37 +00:00
import 'package:flutter/widgets.dart';
2022-12-20 20:52:24 +00:00
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import '/features/core/abstracts/base_view_model.dart';
2022-12-25 21:17:59 +00:00
import '/features/core/data/extensions/value_notifier_extensions.dart';
2022-12-20 20:52:24 +00:00
import '/features/core/services/navigation_service.dart';
import '/locator.dart';
2022-12-23 10:20:46 +00:00
import '../../data/enums/search_option.dart';
import '../../data/models/image_model.dart';
import '../../services/image_cache_manager_service.dart';
import '../../services/images_service.dart';
import '../image_carousel/image_carousel_view.dart';
2022-12-20 20:52:24 +00:00
class GalleryViewModel extends BaseViewModel {
GalleryViewModel({
required ImagesService imagesService,
required NavigationService navigationService,
2022-12-21 22:40:39 +00:00
required ImageCacheManagerService imageCacheManagerService,
2022-12-20 20:52:24 +00:00
}) : _imagesService = imagesService,
_navigationService = navigationService,
2022-12-25 21:17:59 +00:00
_imageCacheManagerService = imageCacheManagerService;
2022-12-20 20:52:24 +00:00
final ImagesService _imagesService;
final NavigationService _navigationService;
2022-12-25 00:55:53 +00:00
//todo(mehul): Use to implement pull-to-refresh or an extra widget
2022-12-21 22:40:39 +00:00
final ImageCacheManagerService _imageCacheManagerService;
2022-12-20 20:52:24 +00:00
final ValueNotifier<bool> _isDisplayingPressingPrompt = ValueNotifier(true);
ValueListenable<bool> get isDisplayingPressingPrompt => _isDisplayingPressingPrompt;
2022-12-23 10:20:46 +00:00
final ValueNotifier<bool> _isSearchingNotifier = ValueNotifier(false);
ValueListenable<bool> get isSearchingListenable => _isSearchingNotifier;
final ValueNotifier<SearchOption> _searchOptionNotifier = ValueNotifier(SearchOption.web);
ValueListenable<SearchOption> get searchOptionListenable => _searchOptionNotifier;
final ValueNotifier<List<ImageModel>> _imageSearchResultsNotifier = ValueNotifier([]);
ValueListenable<List<ImageModel>> get imageSearchResultsListenable => _imageSearchResultsNotifier;
2022-12-25 00:55:53 +00:00
final ValueNotifier<bool> _isViewingFavouriteNotifier = ValueNotifier(false);
ValueListenable<bool> get isViewingFavouriteListenable => _isViewingFavouriteNotifier;
2022-12-20 20:52:24 +00:00
@override
2023-01-01 12:04:22 +00:00
Future<void> initialise(bool Function() mounted, [Object? arguments]) async {
2022-12-20 20:52:24 +00:00
super.initialise(mounted, arguments);
}
@override
Future<void> dispose() async {
super.dispose();
}
2022-12-23 10:20:46 +00:00
Future<void> onSearchTermUpdate(String searchTerm) async {
// If empty-string (from backspacing) -> reset state.
if (searchTerm.isEmpty) {
_imageSearchResultsNotifier.value = [];
2022-12-25 21:17:59 +00:00
log.info('Clearing results on search string removal');
2022-12-23 10:20:46 +00:00
return;
}
// Detached call to prevent UI blocking
unawaited(
_imagesService
.searchImages(
imageNamePart: searchTerm,
searchOption: searchOptionListenable.value,
)
.then(
(final fetchedImageModels) => _imageSearchResultsNotifier.value = fetchedImageModels),
);
2022-12-23 10:20:46 +00:00
// Force-update to trigger listening to `lastQueryResultDone()`.
_imageSearchResultsNotifier.notifyListeners();
}
void searchPressed() {
// If transitioning from 'Searching', clear previous results immediately
if (_isSearchingNotifier.value) {
_imageSearchResultsNotifier.value = [];
2022-12-25 21:17:59 +00:00
log.info('Clearing of results on view mode change');
}
2022-12-23 10:20:46 +00:00
2022-12-25 00:55:53 +00:00
_isSearchingNotifier.flipValue();
2022-12-23 10:20:46 +00:00
}
Future<void> get lastQueryResultDone => _imagesService.lastQueryIsCompleted;
void onSearchOptionChanged(SearchOption? option) {
_searchOptionNotifier.value = option!;
2022-12-25 21:17:59 +00:00
log.info('Switched over to $option search');
_imageSearchResultsNotifier.value = [];
2022-12-25 21:17:59 +00:00
log.info('Cleared resultsw from view');
2022-12-25 00:55:53 +00:00
//todo(mehul): Either redo search or force user to type in new (trigger) by clearing field
}
void onFavouriteViewChange(bool newValue) => _isViewingFavouriteNotifier.value = newValue;
void updateImageFavouriteStatus({
required ImageModel imageModel,
required bool newFavouriteStatus,
}) {
_imagesService.updateImageFavouriteStatus(
imageModel: imageModel,
newFavouriteStatus: newFavouriteStatus,
);
}
2022-12-23 10:20:46 +00:00
2022-12-25 00:55:53 +00:00
Iterable<ImageModel> get favouriteImageModels =>
imageModels.where((final imageModel) => imageModel.isFavourite);
2022-12-20 20:52:24 +00:00
void onPromptPressed() => _isDisplayingPressingPrompt.value = false;
Iterable<ImageModel> get imageModels => _imagesService.imageModels;
2022-12-23 10:20:46 +00:00
Future<void> get initImageFetchIsDone => _imagesService.initAwaiter;
double? downloadProgressValue({required DownloadProgress progress}) =>
progress.totalSize != null ? progress.downloaded / progress.totalSize! : null;
2022-12-20 20:52:24 +00:00
void pushImageCarouselView(BuildContext context, {required ImageModel imageModel}) =>
_navigationService.pushImageCarouselView(
context,
imageCarouselViewArguments: ImageCarouselViewArguments(
imageIndexKey: imageModel.imageIndex,
),
);
static GalleryViewModel get locate => Locator.locate();
}