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

132 lines
4.8 KiB
Dart

import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import '/features/core/abstracts/base_view_model.dart';
import '/features/core/data/extensions/value_notifier_extensions.dart';
import '/features/core/services/navigation_service.dart';
import '/locator.dart';
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';
class GalleryViewModel extends BaseViewModel {
GalleryViewModel({
required ImagesService imagesService,
required NavigationService navigationService,
required ImageCacheManagerService imageCacheManagerService,
}) : _imagesService = imagesService,
_navigationService = navigationService,
_imageCacheManagerService = imageCacheManagerService;
final ImagesService _imagesService;
final NavigationService _navigationService;
//todo(mehul): Use to implement pull-to-refresh or an extra widget
final ImageCacheManagerService _imageCacheManagerService;
final ValueNotifier<bool> _isDisplayingPressingPrompt = ValueNotifier(true);
ValueListenable<bool> get isDisplayingPressingPrompt => _isDisplayingPressingPrompt;
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;
final ValueNotifier<bool> _isViewingFavouriteNotifier = ValueNotifier(false);
ValueListenable<bool> get isViewingFavouriteListenable => _isViewingFavouriteNotifier;
@override
Future<void> initialise(bool Function() mounted, [Object? arguments]) async {
super.initialise(mounted, arguments);
}
@override
Future<void> dispose() async {
super.dispose();
}
Future<void> onSearchTermUpdate(String searchTerm) async {
// If empty-string (from backspacing) -> reset state.
if (searchTerm.isEmpty) {
_imageSearchResultsNotifier.value = [];
log.info('Clearing results on search string removal');
return;
}
// Detached call to prevent UI blocking
unawaited(
_imagesService
.searchImages(
imageNamePart: searchTerm,
searchOption: searchOptionListenable.value,
)
.then(
(final fetchedImageModels) => _imageSearchResultsNotifier.value = fetchedImageModels),
);
// Force-update to trigger listening to `lastQueryResultDone()`.
_imageSearchResultsNotifier.notifyListeners();
}
void searchPressed() {
// If transitioning from 'Searching', clear previous results immediately
if (_isSearchingNotifier.value) {
_imageSearchResultsNotifier.value = [];
log.info('Clearing of results on view mode change');
}
_isSearchingNotifier.flipValue();
}
Future<void> get lastQueryResultDone => _imagesService.lastQueryIsCompleted;
void onSearchOptionChanged(SearchOption? option) {
_searchOptionNotifier.value = option!;
log.info('Switched over to $option search');
_imageSearchResultsNotifier.value = [];
log.info('Cleared resultsw from view');
//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,
);
}
Iterable<ImageModel> get favouriteImageModels =>
imageModels.where((final imageModel) => imageModel.isFavourite);
void onPromptPressed() => _isDisplayingPressingPrompt.value = false;
Iterable<ImageModel> get imageModels => _imagesService.imageModels;
Future<void> get initImageFetchIsDone => _imagesService.initAwaiter;
double? downloadProgressValue({required DownloadProgress progress}) =>
progress.totalSize != null ? progress.downloaded / progress.totalSize! : null;
void pushImageCarouselView(BuildContext context, {required ImageModel imageModel}) =>
_navigationService.pushImageCarouselView(
context,
imageCarouselViewArguments: ImageCarouselViewArguments(
imageIndexKey: imageModel.imageIndex,
),
);
static GalleryViewModel get locate => Locator.locate();
}