mirror of https://github.com/immich-app/immich.git
feat(mobile): lazy loading of assets (#2413)
parent
93863b0629
commit
0dde76bbbc
@ -1,134 +0,0 @@
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
||||||
import 'package:immich_mobile/modules/album/models/asset_selection_state.model.dart';
|
|
||||||
import 'package:immich_mobile/shared/models/asset.dart';
|
|
||||||
|
|
||||||
class AssetSelectionNotifier extends StateNotifier<AssetSelectionState> {
|
|
||||||
AssetSelectionNotifier()
|
|
||||||
: super(
|
|
||||||
AssetSelectionState(
|
|
||||||
selectedNewAssetsForAlbum: {},
|
|
||||||
selectedMonths: {},
|
|
||||||
selectedAdditionalAssetsForAlbum: {},
|
|
||||||
selectedAssetsInAlbumViewer: {},
|
|
||||||
isAlbumExist: false,
|
|
||||||
isMultiselectEnable: false,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
void setIsAlbumExist(bool isAlbumExist) {
|
|
||||||
state = state.copyWith(isAlbumExist: isAlbumExist);
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeAssetsInMonth(
|
|
||||||
String removedMonth,
|
|
||||||
List<Asset> assetsInMonth,
|
|
||||||
) {
|
|
||||||
Set<Asset> currentAssetList = state.selectedNewAssetsForAlbum;
|
|
||||||
Set<String> currentMonthList = state.selectedMonths;
|
|
||||||
|
|
||||||
currentMonthList
|
|
||||||
.removeWhere((selectedMonth) => selectedMonth == removedMonth);
|
|
||||||
|
|
||||||
for (Asset asset in assetsInMonth) {
|
|
||||||
currentAssetList.removeWhere((e) => e.id == asset.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
state = state.copyWith(
|
|
||||||
selectedNewAssetsForAlbum: currentAssetList,
|
|
||||||
selectedMonths: currentMonthList,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addAdditionalAssets(List<Asset> assets) {
|
|
||||||
state = state.copyWith(
|
|
||||||
selectedAdditionalAssetsForAlbum: {
|
|
||||||
...state.selectedAdditionalAssetsForAlbum,
|
|
||||||
...assets
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addAllAssetsInMonth(String month, List<Asset> assetsInMonth) {
|
|
||||||
state = state.copyWith(
|
|
||||||
selectedMonths: {...state.selectedMonths, month},
|
|
||||||
selectedNewAssetsForAlbum: {
|
|
||||||
...state.selectedNewAssetsForAlbum,
|
|
||||||
...assetsInMonth
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addNewAssets(Iterable<Asset> assets) {
|
|
||||||
state = state.copyWith(
|
|
||||||
selectedNewAssetsForAlbum: {
|
|
||||||
...state.selectedNewAssetsForAlbum,
|
|
||||||
...assets
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeSelectedNewAssets(List<Asset> assets) {
|
|
||||||
Set<Asset> currentList = state.selectedNewAssetsForAlbum;
|
|
||||||
|
|
||||||
for (Asset asset in assets) {
|
|
||||||
currentList.removeWhere((e) => e.id == asset.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
state = state.copyWith(selectedNewAssetsForAlbum: currentList);
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeSelectedAdditionalAssets(List<Asset> assets) {
|
|
||||||
Set<Asset> currentList = state.selectedAdditionalAssetsForAlbum;
|
|
||||||
|
|
||||||
for (Asset asset in assets) {
|
|
||||||
currentList.removeWhere((e) => e.id == asset.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
state = state.copyWith(selectedAdditionalAssetsForAlbum: currentList);
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeAll() {
|
|
||||||
state = state.copyWith(
|
|
||||||
selectedNewAssetsForAlbum: {},
|
|
||||||
selectedMonths: {},
|
|
||||||
selectedAdditionalAssetsForAlbum: {},
|
|
||||||
selectedAssetsInAlbumViewer: {},
|
|
||||||
isAlbumExist: false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void enableMultiselection() {
|
|
||||||
state = state.copyWith(isMultiselectEnable: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void disableMultiselection() {
|
|
||||||
state = state.copyWith(
|
|
||||||
isMultiselectEnable: false,
|
|
||||||
selectedAssetsInAlbumViewer: {},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addAssetsInAlbumViewer(List<Asset> assets) {
|
|
||||||
state = state.copyWith(
|
|
||||||
selectedAssetsInAlbumViewer: {
|
|
||||||
...state.selectedAssetsInAlbumViewer,
|
|
||||||
...assets
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeAssetsInAlbumViewer(List<Asset> assets) {
|
|
||||||
Set<Asset> currentList = state.selectedAssetsInAlbumViewer;
|
|
||||||
|
|
||||||
for (Asset asset in assets) {
|
|
||||||
currentList.removeWhere((e) => e.id == asset.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
state = state.copyWith(selectedAssetsInAlbumViewer: currentList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final assetSelectionProvider =
|
|
||||||
StateNotifierProvider<AssetSelectionNotifier, AssetSelectionState>((ref) {
|
|
||||||
return AssetSelectionNotifier();
|
|
||||||
});
|
|
||||||
@ -1,163 +0,0 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
||||||
import 'package:immich_mobile/modules/favorite/providers/favorite_provider.dart';
|
|
||||||
import 'package:immich_mobile/modules/album/providers/asset_selection.provider.dart';
|
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
|
||||||
import 'package:immich_mobile/shared/models/asset.dart';
|
|
||||||
import 'package:immich_mobile/shared/ui/immich_image.dart';
|
|
||||||
import 'package:immich_mobile/utils/storage_indicator.dart';
|
|
||||||
|
|
||||||
class AlbumViewerThumbnail extends HookConsumerWidget {
|
|
||||||
final Asset asset;
|
|
||||||
final List<Asset> assetList;
|
|
||||||
final bool showStorageIndicator;
|
|
||||||
|
|
||||||
const AlbumViewerThumbnail({
|
|
||||||
Key? key,
|
|
||||||
required this.asset,
|
|
||||||
required this.assetList,
|
|
||||||
this.showStorageIndicator = true,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
|
||||||
final selectedAssetsInAlbumViewer =
|
|
||||||
ref.watch(assetSelectionProvider).selectedAssetsInAlbumViewer;
|
|
||||||
final isMultiSelectionEnable =
|
|
||||||
ref.watch(assetSelectionProvider).isMultiselectEnable;
|
|
||||||
final isFavorite = ref.watch(favoriteProvider).contains(asset.id);
|
|
||||||
|
|
||||||
viewAsset() {
|
|
||||||
AutoRouter.of(context).push(
|
|
||||||
GalleryViewerRoute(
|
|
||||||
asset: asset,
|
|
||||||
assetList: assetList,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
BoxBorder drawBorderColor() {
|
|
||||||
if (selectedAssetsInAlbumViewer.contains(asset)) {
|
|
||||||
return Border.all(
|
|
||||||
color: Theme.of(context).primaryColorLight,
|
|
||||||
width: 10,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return const Border();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enableMultiSelection() {
|
|
||||||
ref.watch(assetSelectionProvider.notifier).enableMultiselection();
|
|
||||||
ref
|
|
||||||
.watch(assetSelectionProvider.notifier)
|
|
||||||
.addAssetsInAlbumViewer([asset]);
|
|
||||||
}
|
|
||||||
|
|
||||||
disableMultiSelection() {
|
|
||||||
ref.watch(assetSelectionProvider.notifier).disableMultiselection();
|
|
||||||
}
|
|
||||||
|
|
||||||
buildVideoLabel() {
|
|
||||||
return Positioned(
|
|
||||||
top: 5,
|
|
||||||
right: 5,
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
asset.duration.toString().substring(0, 7),
|
|
||||||
style: const TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 10,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const Icon(
|
|
||||||
Icons.play_circle_outline_rounded,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
buildAssetStoreLocationIcon() {
|
|
||||||
return Positioned(
|
|
||||||
right: 10,
|
|
||||||
bottom: 5,
|
|
||||||
child: Icon(
|
|
||||||
storageIcon(asset),
|
|
||||||
color: Colors.white,
|
|
||||||
size: 18,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
buildAssetFavoriteIcon() {
|
|
||||||
return const Positioned(
|
|
||||||
left: 10,
|
|
||||||
bottom: 5,
|
|
||||||
child: Icon(
|
|
||||||
Icons.favorite,
|
|
||||||
color: Colors.white,
|
|
||||||
size: 18,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
buildAssetSelectionIcon() {
|
|
||||||
bool isSelected = selectedAssetsInAlbumViewer.contains(asset);
|
|
||||||
|
|
||||||
return Positioned(
|
|
||||||
left: 10,
|
|
||||||
top: 5,
|
|
||||||
child: isSelected
|
|
||||||
? Icon(
|
|
||||||
Icons.check_circle_rounded,
|
|
||||||
color: Theme.of(context).primaryColor,
|
|
||||||
)
|
|
||||||
: const Icon(
|
|
||||||
Icons.check_circle_outline_rounded,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
buildThumbnailImage() {
|
|
||||||
return Container(
|
|
||||||
decoration: BoxDecoration(border: drawBorderColor()),
|
|
||||||
child: ImmichImage(asset, width: 300, height: 300),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSelectionGesture() {
|
|
||||||
if (selectedAssetsInAlbumViewer.contains(asset)) {
|
|
||||||
ref
|
|
||||||
.watch(assetSelectionProvider.notifier)
|
|
||||||
.removeAssetsInAlbumViewer([asset]);
|
|
||||||
|
|
||||||
if (selectedAssetsInAlbumViewer.isEmpty) {
|
|
||||||
disableMultiSelection();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ref
|
|
||||||
.watch(assetSelectionProvider.notifier)
|
|
||||||
.addAssetsInAlbumViewer([asset]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: isMultiSelectionEnable ? handleSelectionGesture : viewAsset,
|
|
||||||
onLongPress: enableMultiSelection,
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
buildThumbnailImage(),
|
|
||||||
if (isFavorite) buildAssetFavoriteIcon(),
|
|
||||||
if (showStorageIndicator) buildAssetStoreLocationIcon(),
|
|
||||||
if (!asset.isImage) buildVideoLabel(),
|
|
||||||
if (isMultiSelectionEnable) buildAssetSelectionIcon(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
||||||
import 'package:immich_mobile/modules/album/ui/selection_thumbnail_image.dart';
|
|
||||||
import 'package:immich_mobile/shared/models/asset.dart';
|
|
||||||
|
|
||||||
class AssetGridByMonth extends HookConsumerWidget {
|
|
||||||
final List<Asset> assetGroup;
|
|
||||||
const AssetGridByMonth({Key? key, required this.assetGroup})
|
|
||||||
: super(key: key);
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
|
||||||
return SliverGrid(
|
|
||||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
|
||||||
crossAxisCount: 4,
|
|
||||||
crossAxisSpacing: 5.0,
|
|
||||||
mainAxisSpacing: 5,
|
|
||||||
),
|
|
||||||
delegate: SliverChildBuilderDelegate(
|
|
||||||
(BuildContext context, int index) {
|
|
||||||
return SelectionThumbnailImage(asset: assetGroup[index]);
|
|
||||||
},
|
|
||||||
childCount: assetGroup.length,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,117 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
||||||
import 'package:immich_mobile/modules/album/providers/asset_selection.provider.dart';
|
|
||||||
import 'package:immich_mobile/shared/models/asset.dart';
|
|
||||||
|
|
||||||
class MonthGroupTitle extends HookConsumerWidget {
|
|
||||||
final String month;
|
|
||||||
final List<Asset> assetGroup;
|
|
||||||
|
|
||||||
const MonthGroupTitle({
|
|
||||||
Key? key,
|
|
||||||
required this.month,
|
|
||||||
required this.assetGroup,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
|
||||||
final selectedDateGroup = ref.watch(assetSelectionProvider).selectedMonths;
|
|
||||||
final selectedAssets =
|
|
||||||
ref.watch(assetSelectionProvider).selectedNewAssetsForAlbum;
|
|
||||||
final isAlbumExist = ref.watch(assetSelectionProvider).isAlbumExist;
|
|
||||||
|
|
||||||
handleTitleIconClick() {
|
|
||||||
HapticFeedback.heavyImpact();
|
|
||||||
|
|
||||||
if (isAlbumExist) {
|
|
||||||
if (selectedDateGroup.contains(month)) {
|
|
||||||
ref
|
|
||||||
.watch(assetSelectionProvider.notifier)
|
|
||||||
.removeAssetsInMonth(month, []);
|
|
||||||
ref
|
|
||||||
.watch(assetSelectionProvider.notifier)
|
|
||||||
.removeSelectedAdditionalAssets(assetGroup);
|
|
||||||
} else {
|
|
||||||
ref
|
|
||||||
.watch(assetSelectionProvider.notifier)
|
|
||||||
.addAllAssetsInMonth(month, []);
|
|
||||||
|
|
||||||
// Deep clone assetGroup
|
|
||||||
var assetGroupWithNewItems = [...assetGroup];
|
|
||||||
|
|
||||||
for (var selectedAsset in selectedAssets) {
|
|
||||||
assetGroupWithNewItems.removeWhere((a) => a.id == selectedAsset.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
ref
|
|
||||||
.watch(assetSelectionProvider.notifier)
|
|
||||||
.addAdditionalAssets(assetGroupWithNewItems);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (selectedDateGroup.contains(month)) {
|
|
||||||
ref
|
|
||||||
.watch(assetSelectionProvider.notifier)
|
|
||||||
.removeAssetsInMonth(month, assetGroup);
|
|
||||||
} else {
|
|
||||||
ref
|
|
||||||
.watch(assetSelectionProvider.notifier)
|
|
||||||
.addAllAssetsInMonth(month, assetGroup);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getSimplifiedMonth() {
|
|
||||||
var monthAndYear = month.split(',');
|
|
||||||
var yearText = monthAndYear[1].trim();
|
|
||||||
var monthText = monthAndYear[0].trim();
|
|
||||||
var currentYear = DateTime.now().year.toString();
|
|
||||||
|
|
||||||
if (yearText == currentYear) {
|
|
||||||
return monthText;
|
|
||||||
} else {
|
|
||||||
return month;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return SliverToBoxAdapter(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
top: 29.0,
|
|
||||||
bottom: 29.0,
|
|
||||||
left: 14.0,
|
|
||||||
right: 8.0,
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
GestureDetector(
|
|
||||||
onTap: handleTitleIconClick,
|
|
||||||
child: selectedDateGroup.contains(month)
|
|
||||||
? Icon(
|
|
||||||
Icons.check_circle_rounded,
|
|
||||||
color: Theme.of(context).primaryColor,
|
|
||||||
)
|
|
||||||
: const Icon(
|
|
||||||
Icons.circle_outlined,
|
|
||||||
color: Colors.grey,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
GestureDetector(
|
|
||||||
onTap: handleTitleIconClick,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 8.0),
|
|
||||||
child: Text(
|
|
||||||
getSimplifiedMonth(),
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 24,
|
|
||||||
color: Theme.of(context).primaryColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,141 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
||||||
import 'package:immich_mobile/modules/album/providers/asset_selection.provider.dart';
|
|
||||||
import 'package:immich_mobile/shared/models/asset.dart';
|
|
||||||
import 'package:immich_mobile/shared/ui/immich_image.dart';
|
|
||||||
|
|
||||||
class SelectionThumbnailImage extends HookConsumerWidget {
|
|
||||||
final Asset asset;
|
|
||||||
|
|
||||||
const SelectionThumbnailImage({Key? key, required this.asset})
|
|
||||||
: super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
|
||||||
var selectedAsset =
|
|
||||||
ref.watch(assetSelectionProvider).selectedNewAssetsForAlbum;
|
|
||||||
var newAssetsForAlbum =
|
|
||||||
ref.watch(assetSelectionProvider).selectedAdditionalAssetsForAlbum;
|
|
||||||
var isAlbumExist = ref.watch(assetSelectionProvider).isAlbumExist;
|
|
||||||
|
|
||||||
Widget buildSelectionIcon(Asset asset) {
|
|
||||||
var isSelected = selectedAsset.map((item) => item.id).contains(asset.id);
|
|
||||||
var isNewlySelected =
|
|
||||||
newAssetsForAlbum.map((item) => item.id).contains(asset.id);
|
|
||||||
|
|
||||||
if (isSelected && !isAlbumExist) {
|
|
||||||
return Icon(
|
|
||||||
Icons.check_circle,
|
|
||||||
color: Theme.of(context).primaryColor,
|
|
||||||
);
|
|
||||||
} else if (isSelected && isAlbumExist) {
|
|
||||||
return const Icon(
|
|
||||||
Icons.check_circle,
|
|
||||||
color: Color.fromARGB(255, 233, 233, 233),
|
|
||||||
);
|
|
||||||
} else if (isNewlySelected && isAlbumExist) {
|
|
||||||
return Icon(
|
|
||||||
Icons.check_circle,
|
|
||||||
color: Theme.of(context).primaryColor,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return const Icon(
|
|
||||||
Icons.circle_outlined,
|
|
||||||
color: Colors.white,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BoxBorder drawBorderColor() {
|
|
||||||
var isSelected = selectedAsset.map((item) => item.id).contains(asset.id);
|
|
||||||
var isNewlySelected =
|
|
||||||
newAssetsForAlbum.map((item) => item.id).contains(asset.id);
|
|
||||||
|
|
||||||
if (isSelected && !isAlbumExist) {
|
|
||||||
return Border.all(
|
|
||||||
color: Theme.of(context).primaryColorLight,
|
|
||||||
width: 10,
|
|
||||||
);
|
|
||||||
} else if (isSelected && isAlbumExist) {
|
|
||||||
return Border.all(
|
|
||||||
color: const Color.fromARGB(255, 190, 190, 190),
|
|
||||||
width: 10,
|
|
||||||
);
|
|
||||||
} else if (isNewlySelected && isAlbumExist) {
|
|
||||||
return Border.all(
|
|
||||||
color: Theme.of(context).primaryColorLight,
|
|
||||||
width: 10,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return const Border();
|
|
||||||
}
|
|
||||||
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
var isSelected =
|
|
||||||
selectedAsset.map((item) => item.id).contains(asset.id);
|
|
||||||
var isNewlySelected =
|
|
||||||
newAssetsForAlbum.map((item) => item.id).contains(asset.id);
|
|
||||||
|
|
||||||
if (isAlbumExist) {
|
|
||||||
// Operation for existing album
|
|
||||||
if (!isSelected) {
|
|
||||||
if (isNewlySelected) {
|
|
||||||
ref
|
|
||||||
.watch(assetSelectionProvider.notifier)
|
|
||||||
.removeSelectedAdditionalAssets([asset]);
|
|
||||||
} else {
|
|
||||||
ref
|
|
||||||
.watch(assetSelectionProvider.notifier)
|
|
||||||
.addAdditionalAssets([asset]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Operation for new album
|
|
||||||
if (isSelected) {
|
|
||||||
ref
|
|
||||||
.watch(assetSelectionProvider.notifier)
|
|
||||||
.removeSelectedNewAssets([asset]);
|
|
||||||
} else {
|
|
||||||
ref.watch(assetSelectionProvider.notifier).addNewAssets([asset]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
decoration: BoxDecoration(border: drawBorderColor()),
|
|
||||||
child: ImmichImage(asset, width: 150, height: 150),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(3.0),
|
|
||||||
child: Align(
|
|
||||||
alignment: Alignment.topLeft,
|
|
||||||
child: buildSelectionIcon(asset),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (!asset.isImage)
|
|
||||||
Positioned(
|
|
||||||
bottom: 5,
|
|
||||||
right: 5,
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
asset.duration.toString().substring(0, 7),
|
|
||||||
style: const TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 10,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const Icon(
|
|
||||||
Icons.play_circle_outline_rounded,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,55 +1,25 @@
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/modules/home/ui/asset_grid/asset_grid_data_structure.dart';
|
||||||
|
import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart';
|
||||||
|
import 'package:immich_mobile/modules/settings/services/app_settings.service.dart';
|
||||||
import 'package:immich_mobile/shared/models/asset.dart';
|
import 'package:immich_mobile/shared/models/asset.dart';
|
||||||
import 'package:immich_mobile/shared/providers/asset.provider.dart';
|
import 'package:immich_mobile/shared/models/store.dart';
|
||||||
import 'package:immich_mobile/shared/providers/db.provider.dart';
|
import 'package:immich_mobile/shared/providers/db.provider.dart';
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
|
|
||||||
class ArchiveSelectionNotifier extends StateNotifier<Set<int>> {
|
final archiveProvider = StreamProvider<RenderList>((ref) async* {
|
||||||
ArchiveSelectionNotifier(this.db, this.assetNotifier) : super({}) {
|
final query = ref
|
||||||
state = db.assets
|
.watch(dbProvider)
|
||||||
|
.assets
|
||||||
.filter()
|
.filter()
|
||||||
|
.ownerIdEqualTo(Store.get(StoreKey.currentUser).isarId)
|
||||||
.isArchivedEqualTo(true)
|
.isArchivedEqualTo(true)
|
||||||
.findAllSync()
|
.sortByFileCreatedAt();
|
||||||
.map((e) => e.id)
|
final settings = ref.watch(appSettingsServiceProvider);
|
||||||
.toSet();
|
final groupBy =
|
||||||
|
GroupAssetsBy.values[settings.getSetting(AppSettingsEnum.groupAssetsBy)];
|
||||||
|
yield await RenderList.fromQuery(query, groupBy);
|
||||||
|
await for (final _ in query.watchLazy()) {
|
||||||
|
yield await RenderList.fromQuery(query, groupBy);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Isar db;
|
|
||||||
final AssetNotifier assetNotifier;
|
|
||||||
|
|
||||||
void _setArchiveForAssetId(int id, bool archive) {
|
|
||||||
if (!archive) {
|
|
||||||
state = state.difference({id});
|
|
||||||
} else {
|
|
||||||
state = state.union({id});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _isArchive(int id) {
|
|
||||||
return state.contains(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> toggleArchive(Asset asset) async {
|
|
||||||
if (asset.storage == AssetState.local) return;
|
|
||||||
|
|
||||||
_setArchiveForAssetId(asset.id, !_isArchive(asset.id));
|
|
||||||
|
|
||||||
await assetNotifier.toggleArchive(
|
|
||||||
[asset],
|
|
||||||
state.contains(asset.id),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> addToArchives(Iterable<Asset> assets) {
|
|
||||||
state = state.union(assets.map((a) => a.id).toSet());
|
|
||||||
return assetNotifier.toggleArchive(assets, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final archiveProvider =
|
|
||||||
StateNotifierProvider<ArchiveSelectionNotifier, Set<int>>((ref) {
|
|
||||||
return ArchiveSelectionNotifier(
|
|
||||||
ref.watch(dbProvider),
|
|
||||||
ref.watch(assetProvider.notifier),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,6 +0,0 @@
|
|||||||
class RequestDownloadAssetInfo {
|
|
||||||
final String assetId;
|
|
||||||
final String deviceId;
|
|
||||||
|
|
||||||
RequestDownloadAssetInfo(this.assetId, this.deviceId);
|
|
||||||
}
|
|
||||||
@ -1,68 +1,25 @@
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/modules/home/ui/asset_grid/asset_grid_data_structure.dart';
|
||||||
|
import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart';
|
||||||
|
import 'package:immich_mobile/modules/settings/services/app_settings.service.dart';
|
||||||
import 'package:immich_mobile/shared/models/asset.dart';
|
import 'package:immich_mobile/shared/models/asset.dart';
|
||||||
import 'package:immich_mobile/shared/providers/asset.provider.dart';
|
import 'package:immich_mobile/shared/models/store.dart';
|
||||||
|
import 'package:immich_mobile/shared/providers/db.provider.dart';
|
||||||
class FavoriteSelectionNotifier extends StateNotifier<Set<int>> {
|
import 'package:isar/isar.dart';
|
||||||
FavoriteSelectionNotifier(this.assetsState, this.assetNotifier) : super({}) {
|
|
||||||
state = assetsState.allAssets
|
final favoriteAssetsProvider = StreamProvider<RenderList>((ref) async* {
|
||||||
.where((asset) => asset.isFavorite)
|
final query = ref
|
||||||
.map((asset) => asset.id)
|
.watch(dbProvider)
|
||||||
.toSet();
|
.assets
|
||||||
}
|
.filter()
|
||||||
|
.ownerIdEqualTo(Store.get(StoreKey.currentUser).isarId)
|
||||||
final AssetsState assetsState;
|
.isFavoriteEqualTo(true)
|
||||||
final AssetNotifier assetNotifier;
|
.sortByFileCreatedAt();
|
||||||
|
final settings = ref.watch(appSettingsServiceProvider);
|
||||||
void _setFavoriteForAssetId(int id, bool favorite) {
|
final groupBy =
|
||||||
if (!favorite) {
|
GroupAssetsBy.values[settings.getSetting(AppSettingsEnum.groupAssetsBy)];
|
||||||
state = state.difference({id});
|
yield await RenderList.fromQuery(query, groupBy);
|
||||||
} else {
|
await for (final _ in query.watchLazy()) {
|
||||||
state = state.union({id});
|
yield await RenderList.fromQuery(query, groupBy);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _isFavorite(int id) {
|
|
||||||
return state.contains(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> toggleFavorite(Asset asset) async {
|
|
||||||
// TODO support local favorite assets
|
|
||||||
if (asset.storage == AssetState.local) return;
|
|
||||||
_setFavoriteForAssetId(asset.id, !_isFavorite(asset.id));
|
|
||||||
|
|
||||||
await assetNotifier.toggleFavorite(
|
|
||||||
asset,
|
|
||||||
state.contains(asset.id),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> addToFavorites(Iterable<Asset> assets) {
|
|
||||||
state = state.union(assets.map((a) => a.id).toSet());
|
|
||||||
final futures = assets.map(
|
|
||||||
(a) => assetNotifier.toggleFavorite(
|
|
||||||
a,
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
return Future.wait(futures);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final favoriteProvider =
|
|
||||||
StateNotifierProvider<FavoriteSelectionNotifier, Set<int>>((ref) {
|
|
||||||
return FavoriteSelectionNotifier(
|
|
||||||
ref.watch(assetProvider),
|
|
||||||
ref.watch(assetProvider.notifier),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
final favoriteAssetProvider = StateProvider((ref) {
|
|
||||||
final favorites = ref.watch(favoriteProvider);
|
|
||||||
|
|
||||||
return ref
|
|
||||||
.watch(assetProvider)
|
|
||||||
.allAssets
|
|
||||||
.where((element) => favorites.contains(element.id))
|
|
||||||
.toList();
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,36 +0,0 @@
|
|||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
|
||||||
import 'package:immich_mobile/shared/models/asset.dart';
|
|
||||||
import 'package:immich_mobile/shared/ui/immich_image.dart';
|
|
||||||
|
|
||||||
class FavoriteImage extends HookConsumerWidget {
|
|
||||||
final Asset asset;
|
|
||||||
final List<Asset> assets;
|
|
||||||
|
|
||||||
const FavoriteImage(this.asset, this.assets, {super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
|
||||||
void viewAsset() {
|
|
||||||
AutoRouter.of(context).push(
|
|
||||||
GalleryViewerRoute(
|
|
||||||
asset: asset,
|
|
||||||
assetList: assets,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: viewAsset,
|
|
||||||
child: ImmichImage(
|
|
||||||
asset,
|
|
||||||
width: 300,
|
|
||||||
height: 300,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,112 +0,0 @@
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
||||||
import 'package:immich_mobile/modules/favorite/providers/favorite_provider.dart';
|
|
||||||
import 'package:immich_mobile/shared/models/asset.dart';
|
|
||||||
import 'package:immich_mobile/shared/providers/asset.provider.dart';
|
|
||||||
import 'package:mockito/annotations.dart';
|
|
||||||
import 'package:mockito/mockito.dart';
|
|
||||||
|
|
||||||
@GenerateNiceMocks([
|
|
||||||
MockSpec<AssetsState>(),
|
|
||||||
MockSpec<AssetNotifier>(),
|
|
||||||
])
|
|
||||||
import 'favorite_provider_test.mocks.dart';
|
|
||||||
|
|
||||||
Asset _getTestAsset(int id, bool favorite) {
|
|
||||||
final Asset a = Asset(
|
|
||||||
remoteId: id.toString(),
|
|
||||||
localId: id.toString(),
|
|
||||||
deviceId: 1,
|
|
||||||
ownerId: 1,
|
|
||||||
fileCreatedAt: DateTime.now(),
|
|
||||||
fileModifiedAt: DateTime.now(),
|
|
||||||
updatedAt: DateTime.now(),
|
|
||||||
isLocal: false,
|
|
||||||
durationInSeconds: 0,
|
|
||||||
type: AssetType.image,
|
|
||||||
fileName: '',
|
|
||||||
isFavorite: favorite,
|
|
||||||
isArchived: false,
|
|
||||||
);
|
|
||||||
a.id = id;
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
group("Test favoriteProvider", () {
|
|
||||||
late MockAssetsState assetsState;
|
|
||||||
late MockAssetNotifier assetNotifier;
|
|
||||||
late ProviderContainer container;
|
|
||||||
late StateNotifierProvider<FavoriteSelectionNotifier, Set<int>>
|
|
||||||
testFavoritesProvider;
|
|
||||||
|
|
||||||
setUp(
|
|
||||||
() {
|
|
||||||
assetsState = MockAssetsState();
|
|
||||||
assetNotifier = MockAssetNotifier();
|
|
||||||
container = ProviderContainer();
|
|
||||||
|
|
||||||
testFavoritesProvider =
|
|
||||||
StateNotifierProvider<FavoriteSelectionNotifier, Set<int>>((ref) {
|
|
||||||
return FavoriteSelectionNotifier(
|
|
||||||
assetsState,
|
|
||||||
assetNotifier,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
test("Empty favorites provider", () {
|
|
||||||
when(assetsState.allAssets).thenReturn([]);
|
|
||||||
expect(<int>{}, container.read(testFavoritesProvider));
|
|
||||||
});
|
|
||||||
|
|
||||||
test("Non-empty favorites provider", () {
|
|
||||||
when(assetsState.allAssets).thenReturn([
|
|
||||||
_getTestAsset(1, false),
|
|
||||||
_getTestAsset(2, true),
|
|
||||||
_getTestAsset(3, false),
|
|
||||||
_getTestAsset(4, false),
|
|
||||||
_getTestAsset(5, true),
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(<int>{2, 5}, container.read(testFavoritesProvider));
|
|
||||||
});
|
|
||||||
|
|
||||||
test("Toggle favorite", () {
|
|
||||||
when(assetNotifier.toggleFavorite(null, false))
|
|
||||||
.thenAnswer((_) async => false);
|
|
||||||
|
|
||||||
final testAsset1 = _getTestAsset(1, false);
|
|
||||||
final testAsset2 = _getTestAsset(2, true);
|
|
||||||
|
|
||||||
when(assetsState.allAssets).thenReturn([testAsset1, testAsset2]);
|
|
||||||
|
|
||||||
expect(<int>{2}, container.read(testFavoritesProvider));
|
|
||||||
|
|
||||||
container.read(testFavoritesProvider.notifier).toggleFavorite(testAsset2);
|
|
||||||
expect(<int>{}, container.read(testFavoritesProvider));
|
|
||||||
|
|
||||||
container.read(testFavoritesProvider.notifier).toggleFavorite(testAsset1);
|
|
||||||
expect(<int>{1}, container.read(testFavoritesProvider));
|
|
||||||
});
|
|
||||||
|
|
||||||
test("Add favorites", () {
|
|
||||||
when(assetNotifier.toggleFavorite(null, false))
|
|
||||||
.thenAnswer((_) async => false);
|
|
||||||
|
|
||||||
when(assetsState.allAssets).thenReturn([]);
|
|
||||||
|
|
||||||
expect(<int>{}, container.read(testFavoritesProvider));
|
|
||||||
|
|
||||||
container.read(testFavoritesProvider.notifier).addToFavorites(
|
|
||||||
[
|
|
||||||
_getTestAsset(1, false),
|
|
||||||
_getTestAsset(2, false),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(<int>{1, 2}, container.read(testFavoritesProvider));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@ -1,298 +0,0 @@
|
|||||||
// Mocks generated by Mockito 5.3.2 from annotations
|
|
||||||
// in immich_mobile/test/favorite_provider_test.dart.
|
|
||||||
// Do not manually edit this file.
|
|
||||||
|
|
||||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
|
||||||
import 'dart:async' as _i5;
|
|
||||||
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart' as _i7;
|
|
||||||
import 'package:immich_mobile/modules/home/ui/asset_grid/asset_grid_data_structure.dart'
|
|
||||||
as _i6;
|
|
||||||
import 'package:immich_mobile/shared/models/asset.dart' as _i4;
|
|
||||||
import 'package:immich_mobile/shared/providers/asset.provider.dart' as _i2;
|
|
||||||
import 'package:logging/logging.dart' as _i3;
|
|
||||||
import 'package:mockito/mockito.dart' as _i1;
|
|
||||||
import 'package:state_notifier/state_notifier.dart' as _i8;
|
|
||||||
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
// ignore_for_file: avoid_redundant_argument_values
|
|
||||||
// ignore_for_file: avoid_setters_without_getters
|
|
||||||
// ignore_for_file: comment_references
|
|
||||||
// ignore_for_file: implementation_imports
|
|
||||||
// ignore_for_file: invalid_use_of_visible_for_testing_member
|
|
||||||
// ignore_for_file: prefer_const_constructors
|
|
||||||
// ignore_for_file: unnecessary_parenthesis
|
|
||||||
// ignore_for_file: camel_case_types
|
|
||||||
// ignore_for_file: subtype_of_sealed_class
|
|
||||||
|
|
||||||
class _FakeAssetsState_0 extends _i1.SmartFake implements _i2.AssetsState {
|
|
||||||
_FakeAssetsState_0(
|
|
||||||
Object parent,
|
|
||||||
Invocation parentInvocation,
|
|
||||||
) : super(
|
|
||||||
parent,
|
|
||||||
parentInvocation,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
class _FakeLogger_1 extends _i1.SmartFake implements _i3.Logger {
|
|
||||||
_FakeLogger_1(
|
|
||||||
Object parent,
|
|
||||||
Invocation parentInvocation,
|
|
||||||
) : super(
|
|
||||||
parent,
|
|
||||||
parentInvocation,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A class which mocks [AssetsState].
|
|
||||||
///
|
|
||||||
/// See the documentation for Mockito's code generation for more information.
|
|
||||||
class MockAssetsState extends _i1.Mock implements _i2.AssetsState {
|
|
||||||
@override
|
|
||||||
List<_i4.Asset> get allAssets => (super.noSuchMethod(
|
|
||||||
Invocation.getter(#allAssets),
|
|
||||||
returnValue: <_i4.Asset>[],
|
|
||||||
returnValueForMissingStub: <_i4.Asset>[],
|
|
||||||
) as List<_i4.Asset>);
|
|
||||||
@override
|
|
||||||
_i5.Future<_i2.AssetsState> withRenderDataStructure(
|
|
||||||
_i6.AssetGridLayoutParameters? layout) =>
|
|
||||||
(super.noSuchMethod(
|
|
||||||
Invocation.method(
|
|
||||||
#withRenderDataStructure,
|
|
||||||
[layout],
|
|
||||||
),
|
|
||||||
returnValue: _i5.Future<_i2.AssetsState>.value(_FakeAssetsState_0(
|
|
||||||
this,
|
|
||||||
Invocation.method(
|
|
||||||
#withRenderDataStructure,
|
|
||||||
[layout],
|
|
||||||
),
|
|
||||||
)),
|
|
||||||
returnValueForMissingStub:
|
|
||||||
_i5.Future<_i2.AssetsState>.value(_FakeAssetsState_0(
|
|
||||||
this,
|
|
||||||
Invocation.method(
|
|
||||||
#withRenderDataStructure,
|
|
||||||
[layout],
|
|
||||||
),
|
|
||||||
)),
|
|
||||||
) as _i5.Future<_i2.AssetsState>);
|
|
||||||
@override
|
|
||||||
_i2.AssetsState withAdditionalAssets(List<_i4.Asset>? toAdd) =>
|
|
||||||
(super.noSuchMethod(
|
|
||||||
Invocation.method(
|
|
||||||
#withAdditionalAssets,
|
|
||||||
[toAdd],
|
|
||||||
),
|
|
||||||
returnValue: _FakeAssetsState_0(
|
|
||||||
this,
|
|
||||||
Invocation.method(
|
|
||||||
#withAdditionalAssets,
|
|
||||||
[toAdd],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
returnValueForMissingStub: _FakeAssetsState_0(
|
|
||||||
this,
|
|
||||||
Invocation.method(
|
|
||||||
#withAdditionalAssets,
|
|
||||||
[toAdd],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
) as _i2.AssetsState);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A class which mocks [AssetNotifier].
|
|
||||||
///
|
|
||||||
/// See the documentation for Mockito's code generation for more information.
|
|
||||||
class MockAssetNotifier extends _i1.Mock implements _i2.AssetNotifier {
|
|
||||||
@override
|
|
||||||
_i3.Logger get log => (super.noSuchMethod(
|
|
||||||
Invocation.getter(#log),
|
|
||||||
returnValue: _FakeLogger_1(
|
|
||||||
this,
|
|
||||||
Invocation.getter(#log),
|
|
||||||
),
|
|
||||||
returnValueForMissingStub: _FakeLogger_1(
|
|
||||||
this,
|
|
||||||
Invocation.getter(#log),
|
|
||||||
),
|
|
||||||
) as _i3.Logger);
|
|
||||||
@override
|
|
||||||
set onError(_i7.ErrorListener? _onError) => super.noSuchMethod(
|
|
||||||
Invocation.setter(
|
|
||||||
#onError,
|
|
||||||
_onError,
|
|
||||||
),
|
|
||||||
returnValueForMissingStub: null,
|
|
||||||
);
|
|
||||||
@override
|
|
||||||
bool get mounted => (super.noSuchMethod(
|
|
||||||
Invocation.getter(#mounted),
|
|
||||||
returnValue: false,
|
|
||||||
returnValueForMissingStub: false,
|
|
||||||
) as bool);
|
|
||||||
@override
|
|
||||||
_i5.Stream<_i2.AssetsState> get stream => (super.noSuchMethod(
|
|
||||||
Invocation.getter(#stream),
|
|
||||||
returnValue: _i5.Stream<_i2.AssetsState>.empty(),
|
|
||||||
returnValueForMissingStub: _i5.Stream<_i2.AssetsState>.empty(),
|
|
||||||
) as _i5.Stream<_i2.AssetsState>);
|
|
||||||
@override
|
|
||||||
_i2.AssetsState get state => (super.noSuchMethod(
|
|
||||||
Invocation.getter(#state),
|
|
||||||
returnValue: _FakeAssetsState_0(
|
|
||||||
this,
|
|
||||||
Invocation.getter(#state),
|
|
||||||
),
|
|
||||||
returnValueForMissingStub: _FakeAssetsState_0(
|
|
||||||
this,
|
|
||||||
Invocation.getter(#state),
|
|
||||||
),
|
|
||||||
) as _i2.AssetsState);
|
|
||||||
@override
|
|
||||||
set state(_i2.AssetsState? value) => super.noSuchMethod(
|
|
||||||
Invocation.setter(
|
|
||||||
#state,
|
|
||||||
value,
|
|
||||||
),
|
|
||||||
returnValueForMissingStub: null,
|
|
||||||
);
|
|
||||||
@override
|
|
||||||
_i2.AssetsState get debugState => (super.noSuchMethod(
|
|
||||||
Invocation.getter(#debugState),
|
|
||||||
returnValue: _FakeAssetsState_0(
|
|
||||||
this,
|
|
||||||
Invocation.getter(#debugState),
|
|
||||||
),
|
|
||||||
returnValueForMissingStub: _FakeAssetsState_0(
|
|
||||||
this,
|
|
||||||
Invocation.getter(#debugState),
|
|
||||||
),
|
|
||||||
) as _i2.AssetsState);
|
|
||||||
@override
|
|
||||||
bool get hasListeners => (super.noSuchMethod(
|
|
||||||
Invocation.getter(#hasListeners),
|
|
||||||
returnValue: false,
|
|
||||||
returnValueForMissingStub: false,
|
|
||||||
) as bool);
|
|
||||||
@override
|
|
||||||
_i5.Future<void> rebuildAssetGridDataStructure() => (super.noSuchMethod(
|
|
||||||
Invocation.method(
|
|
||||||
#rebuildAssetGridDataStructure,
|
|
||||||
[],
|
|
||||||
),
|
|
||||||
returnValue: _i5.Future<void>.value(),
|
|
||||||
returnValueForMissingStub: _i5.Future<void>.value(),
|
|
||||||
) as _i5.Future<void>);
|
|
||||||
@override
|
|
||||||
_i5.Future<void> getAllAsset({bool? clear = false}) => (super.noSuchMethod(
|
|
||||||
Invocation.method(
|
|
||||||
#getAllAsset,
|
|
||||||
[],
|
|
||||||
{#clear: clear},
|
|
||||||
),
|
|
||||||
returnValue: _i5.Future<void>.value(),
|
|
||||||
returnValueForMissingStub: _i5.Future<void>.value(),
|
|
||||||
) as _i5.Future<void>);
|
|
||||||
@override
|
|
||||||
_i5.Future<void> clearAllAsset() => (super.noSuchMethod(
|
|
||||||
Invocation.method(
|
|
||||||
#clearAllAsset,
|
|
||||||
[],
|
|
||||||
),
|
|
||||||
returnValue: _i5.Future<void>.value(),
|
|
||||||
returnValueForMissingStub: _i5.Future<void>.value(),
|
|
||||||
) as _i5.Future<void>);
|
|
||||||
@override
|
|
||||||
_i5.Future<void> onNewAssetUploaded(_i4.Asset? newAsset) =>
|
|
||||||
(super.noSuchMethod(
|
|
||||||
Invocation.method(
|
|
||||||
#onNewAssetUploaded,
|
|
||||||
[newAsset],
|
|
||||||
),
|
|
||||||
returnValue: _i5.Future<void>.value(),
|
|
||||||
returnValueForMissingStub: _i5.Future<void>.value(),
|
|
||||||
) as _i5.Future<void>);
|
|
||||||
@override
|
|
||||||
_i5.Future<void> deleteAssets(Set<_i4.Asset>? deleteAssets) =>
|
|
||||||
(super.noSuchMethod(
|
|
||||||
Invocation.method(
|
|
||||||
#deleteAssets,
|
|
||||||
[deleteAssets],
|
|
||||||
),
|
|
||||||
returnValue: _i5.Future<void>.value(),
|
|
||||||
returnValueForMissingStub: _i5.Future<void>.value(),
|
|
||||||
) as _i5.Future<void>);
|
|
||||||
@override
|
|
||||||
_i5.Future<bool> toggleFavorite(
|
|
||||||
_i4.Asset? asset,
|
|
||||||
bool? status,
|
|
||||||
) =>
|
|
||||||
(super.noSuchMethod(
|
|
||||||
Invocation.method(
|
|
||||||
#toggleFavorite,
|
|
||||||
[
|
|
||||||
asset,
|
|
||||||
status,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
returnValue: _i5.Future<bool>.value(false),
|
|
||||||
returnValueForMissingStub: _i5.Future<bool>.value(false),
|
|
||||||
) as _i5.Future<bool>);
|
|
||||||
@override
|
|
||||||
_i5.Future<void> toggleArchive(
|
|
||||||
Iterable<_i4.Asset>? assets,
|
|
||||||
bool? status,
|
|
||||||
) =>
|
|
||||||
(super.noSuchMethod(
|
|
||||||
Invocation.method(
|
|
||||||
#toggleArchive,
|
|
||||||
[
|
|
||||||
assets,
|
|
||||||
status,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
returnValue: _i5.Future<void>.value(),
|
|
||||||
returnValueForMissingStub: _i5.Future<void>.value(),
|
|
||||||
) as _i5.Future<void>);
|
|
||||||
@override
|
|
||||||
bool updateShouldNotify(
|
|
||||||
_i2.AssetsState? old,
|
|
||||||
_i2.AssetsState? current,
|
|
||||||
) =>
|
|
||||||
(super.noSuchMethod(
|
|
||||||
Invocation.method(
|
|
||||||
#updateShouldNotify,
|
|
||||||
[
|
|
||||||
old,
|
|
||||||
current,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
returnValue: false,
|
|
||||||
returnValueForMissingStub: false,
|
|
||||||
) as bool);
|
|
||||||
@override
|
|
||||||
_i7.RemoveListener addListener(
|
|
||||||
_i8.Listener<_i2.AssetsState>? listener, {
|
|
||||||
bool? fireImmediately = true,
|
|
||||||
}) =>
|
|
||||||
(super.noSuchMethod(
|
|
||||||
Invocation.method(
|
|
||||||
#addListener,
|
|
||||||
[listener],
|
|
||||||
{#fireImmediately: fireImmediately},
|
|
||||||
),
|
|
||||||
returnValue: () {},
|
|
||||||
returnValueForMissingStub: () {},
|
|
||||||
) as _i7.RemoveListener);
|
|
||||||
@override
|
|
||||||
void dispose() => super.noSuchMethod(
|
|
||||||
Invocation.method(
|
|
||||||
#dispose,
|
|
||||||
[],
|
|
||||||
),
|
|
||||||
returnValueForMissingStub: null,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue