Add support for GroupType.none
This commit is contained in:
@@ -14,6 +14,9 @@ import "package:photos/ui/viewer/gallery/component/group/type.dart";
|
||||
import "package:photos/ui/viewer/gallery/scrollbar/custom_scroll_bar_2.dart";
|
||||
import "package:uuid/uuid.dart";
|
||||
|
||||
/// In order to make the gallery performant when GroupTypes do not show group
|
||||
/// headers, groups are still created here but with the group header replaced by
|
||||
/// the grid's main axis spacing.
|
||||
class GalleryGroups {
|
||||
final List<EnteFile> allFiles;
|
||||
final GroupType groupType;
|
||||
@@ -26,7 +29,7 @@ class GalleryGroups {
|
||||
//TODO: Add support for sort order
|
||||
final bool sortOrderAsc;
|
||||
final double widthAvailable;
|
||||
final double headerExtent;
|
||||
final double groupHeaderExtent;
|
||||
GalleryGroups({
|
||||
required this.allFiles,
|
||||
required this.groupType,
|
||||
@@ -34,11 +37,20 @@ class GalleryGroups {
|
||||
required this.selectedFiles,
|
||||
required this.tagPrefix,
|
||||
this.sortOrderAsc = true,
|
||||
required this.headerExtent,
|
||||
|
||||
/// Should be GroupGallery.spacing if GroupType.showGroupHeader() is false.
|
||||
required this.groupHeaderExtent,
|
||||
required this.showSelectAllByDefault,
|
||||
this.limitSelectionToOne = false,
|
||||
}) {
|
||||
init();
|
||||
if (!groupType.showGroupHeader()) {
|
||||
assert(
|
||||
groupHeaderExtent == spacing,
|
||||
'''groupHeaderExtent should be equal to spacing when group header is not
|
||||
shown since the header is just replaced by the grid's main axis spacing''',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static const double spacing = 2.0;
|
||||
@@ -67,8 +79,8 @@ class GalleryGroups {
|
||||
List<ScrollbarDivision> get scrollbarDivisions => _scrollbarDivisions;
|
||||
|
||||
void init() {
|
||||
_buildGroups();
|
||||
crossAxisCount = localSettings.getPhotoGridSize();
|
||||
_buildGroups();
|
||||
_groupLayouts = _computeGroupLayouts();
|
||||
assert(groupIDs.length == _groupIdToFilesMap.length);
|
||||
assert(groupIDs.length == _groupIdToHeaderDataMap.length);
|
||||
@@ -83,6 +95,7 @@ class GalleryGroups {
|
||||
|
||||
List<FixedExtentSectionLayout> _computeGroupLayouts() {
|
||||
final stopwatch = Stopwatch()..start();
|
||||
final showGroupHeader = groupType.showGroupHeader();
|
||||
int currentIndex = 0;
|
||||
double currentOffset = 0.0;
|
||||
final tileHeight =
|
||||
@@ -100,7 +113,7 @@ class GalleryGroups {
|
||||
final maxOffset = minOffset +
|
||||
(numberOfGridRows * tileHeight) +
|
||||
(numberOfGridRows - 1) * spacing +
|
||||
headerExtent;
|
||||
groupHeaderExtent;
|
||||
final bodyFirstIndex = firstIndex + 1;
|
||||
|
||||
groupLayouts.add(
|
||||
@@ -109,20 +122,24 @@ class GalleryGroups {
|
||||
lastIndex: lastIndex,
|
||||
minOffset: minOffset,
|
||||
maxOffset: maxOffset,
|
||||
headerExtent: headerExtent,
|
||||
headerExtent: groupHeaderExtent,
|
||||
tileHeight: tileHeight,
|
||||
spacing: spacing,
|
||||
builder: (context, rowIndex) {
|
||||
if (rowIndex == firstIndex) {
|
||||
return GroupHeaderWidget(
|
||||
title: _groupIdToHeaderDataMap[groupID]!
|
||||
.groupType
|
||||
.getTitle(context, groupIDToFilesMap[groupID]!.first),
|
||||
gridSize: crossAxisCount,
|
||||
filesInGroup: groupIDToFilesMap[groupID]!,
|
||||
selectedFiles: selectedFiles,
|
||||
showSelectAllByDefault: showSelectAllByDefault,
|
||||
);
|
||||
if (showGroupHeader) {
|
||||
return GroupHeaderWidget(
|
||||
title: _groupIdToHeaderDataMap[groupID]!
|
||||
.groupType
|
||||
.getTitle(context, groupIDToFilesMap[groupID]!.first),
|
||||
gridSize: crossAxisCount,
|
||||
filesInGroup: groupIDToFilesMap[groupID]!,
|
||||
selectedFiles: selectedFiles,
|
||||
showSelectAllByDefault: showSelectAllByDefault,
|
||||
);
|
||||
} else {
|
||||
return const SizedBox(height: spacing);
|
||||
}
|
||||
} else {
|
||||
final gridRowChildren = <Widget>[];
|
||||
final firstIndexOfRowWrtFilesInGroup =
|
||||
@@ -208,31 +225,47 @@ class GalleryGroups {
|
||||
// TODO: compute this in isolate
|
||||
void _buildGroups() {
|
||||
final stopwatch = Stopwatch()..start();
|
||||
final years = <int>{};
|
||||
|
||||
final yearsInGroups = <int>{}; //Only relevant for time grouping
|
||||
List<EnteFile> groupFiles = [];
|
||||
for (int index = 0; index < allFiles.length; index++) {
|
||||
if (index > 0 &&
|
||||
!groupType.areFromSameGroup(allFiles[index - 1], allFiles[index])) {
|
||||
_createNewGroup(groupFiles, years);
|
||||
groupFiles = [];
|
||||
final allFilesLength = allFiles.length;
|
||||
|
||||
if (groupType.showGroupHeader()) {
|
||||
for (int index = 0; index < allFilesLength; index++) {
|
||||
if (index > 0 &&
|
||||
!groupType.areFromSameGroup(allFiles[index - 1], allFiles[index])) {
|
||||
_createNewGroup(groupFiles, yearsInGroups);
|
||||
groupFiles = [];
|
||||
}
|
||||
groupFiles.add(allFiles[index]);
|
||||
}
|
||||
if (groupFiles.isNotEmpty) {
|
||||
_createNewGroup(groupFiles, yearsInGroups);
|
||||
}
|
||||
} else {
|
||||
// Split allFiles into groups of max length 10 * crossAxisCount for
|
||||
// better performance since SectionedSliverList is used.
|
||||
for (int i = 0; i < allFiles.length; i += 10 * crossAxisCount) {
|
||||
final end = (i + 10 * crossAxisCount < allFiles.length)
|
||||
? i + 10 * crossAxisCount
|
||||
: allFiles.length;
|
||||
final subGroup = allFiles.sublist(i, end);
|
||||
_createNewGroup(subGroup, yearsInGroups);
|
||||
}
|
||||
groupFiles.add(allFiles[index]);
|
||||
}
|
||||
if (groupFiles.isNotEmpty) {
|
||||
_createNewGroup(groupFiles, years);
|
||||
}
|
||||
|
||||
_logger.info(
|
||||
"Built ${_groupIds.length} groups in ${stopwatch.elapsedMilliseconds} ms",
|
||||
"Built ${_groupIds.length} groups for group type ${groupType.name} in ${stopwatch.elapsedMilliseconds} ms",
|
||||
);
|
||||
print(
|
||||
"Built ${_groupIds.length} groups in ${stopwatch.elapsedMilliseconds} ms",
|
||||
"Built ${_groupIds.length} groups for group type ${groupType.name} in ${stopwatch.elapsedMilliseconds} ms",
|
||||
);
|
||||
stopwatch.stop();
|
||||
}
|
||||
|
||||
void _createNewGroup(
|
||||
List<EnteFile> groupFiles,
|
||||
Set<int> years,
|
||||
Set<int> yearsInGroups,
|
||||
) {
|
||||
final uuid = _uuid.v1();
|
||||
_groupIds.add(uuid);
|
||||
@@ -241,17 +274,20 @@ class GalleryGroups {
|
||||
groupType: groupType,
|
||||
);
|
||||
|
||||
final yearOfGroup = DateTime.fromMicrosecondsSinceEpoch(
|
||||
groupFiles.first.creationTime!,
|
||||
).year;
|
||||
if (!years.contains(yearOfGroup)) {
|
||||
years.add(yearOfGroup);
|
||||
_scrollbarDivisions.add(
|
||||
ScrollbarDivision(
|
||||
groupID: uuid,
|
||||
title: yearOfGroup.toString(),
|
||||
),
|
||||
);
|
||||
// For scrollbar divisions
|
||||
if (groupType.timeGrouping()) {
|
||||
final yearOfGroup = DateTime.fromMicrosecondsSinceEpoch(
|
||||
groupFiles.first.creationTime!,
|
||||
).year;
|
||||
if (!yearsInGroups.contains(yearOfGroup)) {
|
||||
yearsInGroups.add(yearOfGroup);
|
||||
_scrollbarDivisions.add(
|
||||
ScrollbarDivision(
|
||||
groupID: uuid,
|
||||
title: yearOfGroup.toString(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,12 +39,9 @@ extension GroupTypeExtension on GroupType {
|
||||
this == GroupType.year;
|
||||
}
|
||||
|
||||
bool showGroupHeader() {
|
||||
if (this == GroupType.size || this == GroupType.none) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool showGroupHeader() => timeGrouping();
|
||||
|
||||
bool showScrollbarDivisions() => timeGrouping();
|
||||
|
||||
String getTitle(
|
||||
BuildContext context,
|
||||
|
||||
@@ -127,9 +127,9 @@ class GalleryState extends State<Gallery> {
|
||||
final _stackKey = GlobalKey();
|
||||
final _headerKey = GlobalKey();
|
||||
final _headerHeightNotifier = ValueNotifier<double?>(null);
|
||||
|
||||
final miscUtil = MiscUtil();
|
||||
final scrollBarInUseNotifier = ValueNotifier<bool>(false);
|
||||
late GroupType _groupType;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -139,6 +139,7 @@ class GalleryState extends State<Gallery> {
|
||||
"Gallery_${widget.tagPrefix}${kDebugMode ? "_" + widget.albumName! : ""}_x";
|
||||
_logger = Logger(_logTag);
|
||||
_logger.info("init Gallery");
|
||||
_setGroupType();
|
||||
_debouncer = Debouncer(
|
||||
widget.reloadDebounceTime,
|
||||
executionInterval: widget.reloadDebounceExecutionInterval,
|
||||
@@ -216,20 +217,24 @@ class GalleryState extends State<Gallery> {
|
||||
}
|
||||
});
|
||||
|
||||
getIntrinsicSizeOfWidget(
|
||||
GroupHeaderWidget(
|
||||
title: "Dummy title",
|
||||
gridSize: localSettings.getPhotoGridSize(),
|
||||
filesInGroup: const [],
|
||||
selectedFiles: null,
|
||||
showSelectAllByDefault: false,
|
||||
),
|
||||
context,
|
||||
).then((size) {
|
||||
setState(() {
|
||||
groupHeaderExtent = size.height;
|
||||
if (_groupType.showGroupHeader()) {
|
||||
getIntrinsicSizeOfWidget(
|
||||
GroupHeaderWidget(
|
||||
title: "Dummy title",
|
||||
gridSize: localSettings.getPhotoGridSize(),
|
||||
filesInGroup: const [],
|
||||
selectedFiles: null,
|
||||
showSelectAllByDefault: false,
|
||||
),
|
||||
context,
|
||||
).then((size) {
|
||||
setState(() {
|
||||
groupHeaderExtent = size.height;
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
groupHeaderExtent = GalleryGroups.spacing;
|
||||
}
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
try {
|
||||
@@ -249,6 +254,21 @@ class GalleryState extends State<Gallery> {
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant Gallery oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (oldWidget.groupType != widget.groupType) {
|
||||
_setGroupType();
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _setGroupType() {
|
||||
_groupType = widget.enableFileGrouping ? widget.groupType : GroupType.none;
|
||||
}
|
||||
|
||||
void _setFilesAndReload(List<EnteFile> files) {
|
||||
final hasReloaded = _onFilesLoaded(files);
|
||||
if (!hasReloaded && mounted) {
|
||||
@@ -346,7 +366,7 @@ class GalleryState extends State<Gallery> {
|
||||
_allGalleryFiles = files;
|
||||
|
||||
final updatedGroupedFiles =
|
||||
widget.enableFileGrouping && widget.groupType.timeGrouping()
|
||||
widget.enableFileGrouping && _groupType.timeGrouping()
|
||||
? _groupBasedOnTime(files)
|
||||
: _genericGroupForPerf(files);
|
||||
if (currentGroupedFiles.length != updatedGroupedFiles.length ||
|
||||
@@ -427,11 +447,11 @@ class GalleryState extends State<Gallery> {
|
||||
|
||||
final galleryGroups = GalleryGroups(
|
||||
allFiles: _allGalleryFiles,
|
||||
groupType: widget.groupType,
|
||||
groupType: _groupType,
|
||||
widthAvailable: MediaQuery.sizeOf(context).width,
|
||||
selectedFiles: widget.selectedFiles,
|
||||
tagPrefix: widget.tagPrefix,
|
||||
headerExtent: groupHeaderExtent!,
|
||||
groupHeaderExtent: groupHeaderExtent!,
|
||||
showSelectAllByDefault: widget.showSelectAllByDefault,
|
||||
);
|
||||
GalleryFilesState.of(context).setGalleryFiles = _allGalleryFiles;
|
||||
@@ -441,7 +461,7 @@ class GalleryState extends State<Gallery> {
|
||||
return GalleryContextState(
|
||||
sortOrderAsc: _sortOrderAsc,
|
||||
inSelectionMode: widget.inSelectionMode,
|
||||
type: widget.groupType,
|
||||
type: _groupType,
|
||||
// Replace this with the new gallery and use `_allGalleryFiles`
|
||||
// child: MultipleGroupsGalleryView(
|
||||
// groupedFiles: currentGroupedFiles,
|
||||
@@ -512,14 +532,16 @@ class GalleryState extends State<Gallery> {
|
||||
),
|
||||
],
|
||||
),
|
||||
PinnedGroupHeader(
|
||||
scrollController: _scrollController,
|
||||
galleryGroups: galleryGroups,
|
||||
headerHeightNotifier: _headerHeightNotifier,
|
||||
selectedFiles: widget.selectedFiles,
|
||||
showSelectAllByDefault: widget.showSelectAllByDefault,
|
||||
scrollbarInUseNotifier: scrollBarInUseNotifier,
|
||||
),
|
||||
galleryGroups.groupType.showGroupHeader()
|
||||
? PinnedGroupHeader(
|
||||
scrollController: _scrollController,
|
||||
galleryGroups: galleryGroups,
|
||||
headerHeightNotifier: _headerHeightNotifier,
|
||||
selectedFiles: widget.selectedFiles,
|
||||
showSelectAllByDefault: widget.showSelectAllByDefault,
|
||||
scrollbarInUseNotifier: scrollBarInUseNotifier,
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -529,7 +551,7 @@ class GalleryState extends State<Gallery> {
|
||||
|
||||
// create groups of 200 files for performance
|
||||
List<List<EnteFile>> _genericGroupForPerf(List<EnteFile> files) {
|
||||
if (widget.groupType == GroupType.size) {
|
||||
if (_groupType == GroupType.size) {
|
||||
// sort files by fileSize on the bases of _sortOrderAsc
|
||||
files.sort((a, b) {
|
||||
if (_sortOrderAsc) {
|
||||
@@ -542,7 +564,7 @@ class GalleryState extends State<Gallery> {
|
||||
// todo:(neeraj) Stick to default group behaviour for magicSearch and editLocationGallery
|
||||
// In case of Magic search, we need to hide the scrollbar title (can be done
|
||||
// by specifying none as groupType)
|
||||
if (widget.groupType != GroupType.size) {
|
||||
if (_groupType != GroupType.size) {
|
||||
return [files];
|
||||
}
|
||||
|
||||
@@ -770,7 +792,7 @@ class _PinnedGroupHeaderState extends State<PinnedGroupHeader> {
|
||||
.first,
|
||||
),
|
||||
gridSize: localSettings.getPhotoGridSize(),
|
||||
height: widget.galleryGroups.headerExtent,
|
||||
height: widget.galleryGroups.groupHeaderExtent,
|
||||
filesInGroup: widget
|
||||
.galleryGroups.groupIDToFilesMap[currentGroupId!]!,
|
||||
selectedFiles: widget.selectedFiles,
|
||||
|
||||
@@ -3,6 +3,7 @@ import "package:flutter/material.dart";
|
||||
import "package:logging/logging.dart";
|
||||
import "package:photos/models/gallery/gallery_sections.dart";
|
||||
import "package:photos/theme/ente_theme.dart";
|
||||
import "package:photos/ui/viewer/gallery/component/group/type.dart";
|
||||
import "package:photos/ui/viewer/gallery/scrollbar/scroll_bar_with_use_notifier.dart";
|
||||
import "package:photos/utils/misc_util.dart";
|
||||
import "package:photos/utils/widget_util.dart";
|
||||
@@ -81,8 +82,9 @@ class _CustomScrollBar2State extends State<CustomScrollBar2> {
|
||||
|
||||
void _init() {
|
||||
_logger.info("Initializing CustomScrollBar2");
|
||||
if (widget.galleryGroups.groupLayouts.last.maxOffset >
|
||||
widget.heighOfViewport * 5) {
|
||||
if (widget.galleryGroups.groupType.showScrollbarDivisions() &&
|
||||
widget.galleryGroups.groupLayouts.last.maxOffset >
|
||||
widget.heighOfViewport * 5) {
|
||||
_showScrollbarDivisions = true;
|
||||
} else {
|
||||
_showScrollbarDivisions = false;
|
||||
|
||||
Reference in New Issue
Block a user