153 lines
5 KiB
Dart
153 lines
5 KiB
Dart
import "package:flutter/material.dart";
|
|
import "package:intl/intl.dart";
|
|
import "package:logging/logging.dart";
|
|
import "package:photos/core/event_bus.dart";
|
|
import "package:photos/ente_theme_data.dart";
|
|
import "package:photos/events/files_updated_event.dart";
|
|
import "package:photos/models/file.dart";
|
|
import "package:photos/models/selected_files.dart";
|
|
import "package:photos/ui/common/loading_widget.dart";
|
|
import "package:photos/ui/huge_listview/huge_listview.dart";
|
|
import 'package:photos/ui/viewer/gallery/component/group/lazy_group_gallery.dart';
|
|
import "package:photos/ui/viewer/gallery/gallery.dart";
|
|
import "package:photos/utils/local_settings.dart";
|
|
import "package:scrollable_positioned_list/scrollable_positioned_list.dart";
|
|
|
|
/*
|
|
MultipleGroupsGalleryView is a widget that displays a list of grouped/collated
|
|
files when grouping is enabled.
|
|
For each group, it displays a header and use LazyGroupGallery to display a
|
|
particular group of files.
|
|
If a group has more than 400 files, LazyGroupGallery internally divides the
|
|
group into multiple grid views during rendering.
|
|
*/
|
|
class MultipleGroupsGalleryView extends StatelessWidget {
|
|
final GlobalKey<HugeListViewState<dynamic>> hugeListViewKey;
|
|
final ItemScrollController itemScroller;
|
|
final List<List<File>> groupedFiles;
|
|
final bool disableScroll;
|
|
final Widget? header;
|
|
final Widget? footer;
|
|
final Widget emptyState;
|
|
final GalleryLoader asyncLoader;
|
|
final Stream<FilesUpdatedEvent>? reloadEvent;
|
|
final Set<EventType> removalEventTypes;
|
|
final String tagPrefix;
|
|
final double scrollBottomSafeArea;
|
|
final bool limitSelectionToOne;
|
|
final SelectedFiles? selectedFiles;
|
|
final bool enableFileGrouping;
|
|
final String logTag;
|
|
final Logger logger;
|
|
final bool showSelectAllByDefault;
|
|
final bool isScrollablePositionedList;
|
|
|
|
const MultipleGroupsGalleryView({
|
|
required this.hugeListViewKey,
|
|
required this.itemScroller,
|
|
required this.groupedFiles,
|
|
required this.disableScroll,
|
|
this.header,
|
|
this.footer,
|
|
required this.emptyState,
|
|
required this.asyncLoader,
|
|
this.reloadEvent,
|
|
required this.removalEventTypes,
|
|
required this.tagPrefix,
|
|
required this.scrollBottomSafeArea,
|
|
required this.limitSelectionToOne,
|
|
this.selectedFiles,
|
|
required this.enableFileGrouping,
|
|
required this.logTag,
|
|
required this.logger,
|
|
required this.showSelectAllByDefault,
|
|
required this.isScrollablePositionedList,
|
|
super.key,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return HugeListView<List<File>>(
|
|
key: hugeListViewKey,
|
|
controller: itemScroller,
|
|
startIndex: 0,
|
|
totalCount: groupedFiles.length,
|
|
isDraggableScrollbarEnabled: groupedFiles.length > 10,
|
|
disableScroll: disableScroll,
|
|
isScrollablePositionedList: isScrollablePositionedList,
|
|
waitBuilder: (_) {
|
|
return const EnteLoadingWidget();
|
|
},
|
|
emptyResultBuilder: (_) {
|
|
final List<Widget> children = [];
|
|
if (header != null) {
|
|
children.add(header!);
|
|
}
|
|
children.add(
|
|
Expanded(
|
|
child: emptyState,
|
|
),
|
|
);
|
|
if (footer != null) {
|
|
children.add(footer!);
|
|
}
|
|
return Column(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: children,
|
|
);
|
|
},
|
|
itemBuilder: (context, index) {
|
|
Widget gallery;
|
|
gallery = LazyGroupGallery(
|
|
groupedFiles[index],
|
|
index,
|
|
reloadEvent,
|
|
removalEventTypes,
|
|
asyncLoader,
|
|
selectedFiles,
|
|
tagPrefix,
|
|
Bus.instance
|
|
.on<GalleryIndexUpdatedEvent>()
|
|
.where((event) => event.tag == tagPrefix)
|
|
.map((event) => event.index),
|
|
enableFileGrouping,
|
|
showSelectAllByDefault,
|
|
logTag: logTag,
|
|
photoGridSize: LocalSettings.instance.getPhotoGridSize(),
|
|
limitSelectionToOne: limitSelectionToOne,
|
|
);
|
|
if (header != null && index == 0) {
|
|
gallery = Column(children: [header!, gallery]);
|
|
}
|
|
if (footer != null && index == groupedFiles.length - 1) {
|
|
gallery = Column(children: [gallery, footer!]);
|
|
}
|
|
return gallery;
|
|
},
|
|
labelTextBuilder: (int index) {
|
|
try {
|
|
return DateFormat.yMMM(Localizations.localeOf(context).languageCode)
|
|
.format(
|
|
DateTime.fromMicrosecondsSinceEpoch(
|
|
groupedFiles[index][0].creationTime!,
|
|
),
|
|
);
|
|
} catch (e) {
|
|
logger.severe("label text builder failed", e);
|
|
return "";
|
|
}
|
|
},
|
|
thumbBackgroundColor:
|
|
Theme.of(context).colorScheme.galleryThumbBackgroundColor,
|
|
thumbDrawColor: Theme.of(context).colorScheme.galleryThumbDrawColor,
|
|
thumbPadding: header != null
|
|
? const EdgeInsets.only(top: 60)
|
|
: const EdgeInsets.all(0),
|
|
bottomSafeArea: scrollBottomSafeArea,
|
|
firstShown: (int firstIndex) {
|
|
Bus.instance.fire(GalleryIndexUpdatedEvent(tagPrefix, firstIndex));
|
|
},
|
|
);
|
|
}
|
|
}
|