This commit is contained in:
Neeraj Gupta 2024-05-27 12:37:31 +00:00 committed by GitHub
commit 283315b683
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 113 additions and 10 deletions

View file

@ -5,9 +5,11 @@ import 'package:flutter/material.dart';
import 'package:photos/ente_theme_data.dart';
import "package:photos/generated/l10n.dart";
import "package:photos/models/api/collection/user.dart";
import "package:photos/models/file/file.dart";
import 'package:photos/models/file/trash_file.dart';
import 'package:photos/theme/colors.dart';
import 'package:photos/ui/sharing/user_avator_widget.dart';
import "package:photos/utils/data_util.dart";
class ThumbnailPlaceHolder extends StatelessWidget {
const ThumbnailPlaceHolder({Key? key}) : super(key: key);
@ -143,15 +145,38 @@ class OwnerAvatarOverlayIcon extends StatelessWidget {
class TrashedFileOverlayText extends StatelessWidget {
final TrashFile file;
const TrashedFileOverlayText(this.file, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final int daysLeft =
((file.deleteBy - DateTime.now().microsecondsSinceEpoch) /
Duration.microsecondsPerDay)
.ceil();
final text = S.of(context).trashDaysLeft(daysLeft);
return FileOverlayText(text);
}
}
class FileSizeOverlayText extends StatelessWidget {
final EnteFile file;
const FileSizeOverlayText(this.file, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
if (file.fileSize == null) {
return const SizedBox.shrink();
}
final text = convertBytesToReadableFormat(file.fileSize!);
return FileOverlayText(text);
}
}
class FileOverlayText extends StatelessWidget {
final String text;
const FileOverlayText(this.text, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
@ -163,7 +188,7 @@ class TrashedFileOverlayText extends StatelessWidget {
alignment: Alignment.bottomCenter,
padding: const EdgeInsets.only(bottom: 5),
child: Text(
S.of(context).trashDaysLeft(daysLeft),
text,
style: Theme.of(context)
.textTheme
.titleSmall!

View file

@ -18,6 +18,8 @@ import 'package:photos/models/file/trash_file.dart';
import 'package:photos/services/collections_service.dart';
import 'package:photos/services/favorites_service.dart';
import 'package:photos/ui/viewer/file/file_icons_widget.dart';
import "package:photos/ui/viewer/gallery/component/group/type.dart";
import "package:photos/ui/viewer/gallery/state/gallery_context_state.dart";
import 'package:photos/utils/file_util.dart';
import 'package:photos/utils/thumbnail_util.dart';
@ -178,6 +180,8 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
if (widget.file.isTrash) {
viewChildren.add(TrashedFileOverlayText(widget.file as TrashFile));
} else if (GalleryContextState.of(context)?.type == GroupType.size) {
viewChildren.add(FileSizeOverlayText(widget.file));
}
// todo: Move this icon overlay to the collection widget.
if (widget.shouldShowArchiveStatus) {

View file

@ -5,7 +5,14 @@ import "package:photos/generated/l10n.dart";
import "package:photos/models/file/file.dart";
import "package:photos/utils/date_time_util.dart";
enum GroupType { day, week, month, size, year }
enum GroupType {
day,
week,
month,
size,
year,
none,
}
extension GroupTypeExtension on GroupType {
String get name {
@ -20,9 +27,25 @@ extension GroupTypeExtension on GroupType {
return "size";
case GroupType.year:
return "year";
case GroupType.none:
return "none";
}
}
bool timeGrouping() {
return this == GroupType.day ||
this == GroupType.week ||
this == GroupType.month ||
this == GroupType.year;
}
bool showGroupHeader() {
if (this == GroupType.size || this == GroupType.none) {
return false;
}
return true;
}
String getTitle(BuildContext context, EnteFile file, {EnteFile? lastFile}) {
if (this == GroupType.day) {
return _getDayTitle(context, file.creationTime!);
@ -41,7 +64,7 @@ extension GroupTypeExtension on GroupType {
return DateFormat.yMMM(Localizations.localeOf(context).languageCode)
.format(date);
} else {
throw UnimplementedError("not implemented for $this");
throw UnimplementedError("getTitle not implemented for $this");
}
}

View file

@ -9,7 +9,10 @@ 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/component/group/type.dart";
import "package:photos/ui/viewer/gallery/gallery.dart";
import "package:photos/ui/viewer/gallery/state/gallery_context_state.dart";
import "package:photos/utils/data_util.dart";
import "package:photos/utils/local_settings.dart";
import "package:scrollable_positioned_list/scrollable_positioned_list.dart";
@ -65,6 +68,7 @@ class MultipleGroupsGalleryView extends StatelessWidget {
@override
Widget build(BuildContext context) {
final gType = GalleryContextState.of(context)!.type;
return HugeListView<List<EnteFile>>(
controller: itemScroller,
startIndex: 0,
@ -123,10 +127,17 @@ class MultipleGroupsGalleryView extends StatelessWidget {
},
labelTextBuilder: (int index) {
try {
final EnteFile file = groupedFiles[index][0];
if (gType == GroupType.size) {
return file.fileSize != null
? convertBytesToReadableFormat(file.fileSize!)
: "";
}
return DateFormat.yMMM(Localizations.localeOf(context).languageCode)
.format(
DateTime.fromMicrosecondsSinceEpoch(
groupedFiles[index][0].creationTime!,
file.creationTime!,
),
);
} catch (e) {

View file

@ -214,7 +214,9 @@ class GalleryState extends State<Gallery> {
// gallery reload
bool _onFilesLoaded(List<EnteFile> files) {
final updatedGroupedFiles =
widget.enableFileGrouping ? _groupFiles(files) : [files];
widget.enableFileGrouping && widget.groupType.timeGrouping()
? _groupBasedOnTime(files)
: _genericGroupForPerf(files);
if (currentGroupedFiles.length != updatedGroupedFiles.length ||
currentGroupedFiles.isEmpty) {
if (mounted) {
@ -261,20 +263,58 @@ class GalleryState extends State<Gallery> {
tagPrefix: widget.tagPrefix,
scrollBottomSafeArea: widget.scrollBottomSafeArea,
limitSelectionToOne: widget.limitSelectionToOne,
enableFileGrouping: widget.enableFileGrouping,
enableFileGrouping:
widget.enableFileGrouping && widget.groupType.showGroupHeader(),
logTag: _logTag,
logger: _logger,
reloadEvent: widget.reloadEvent,
header: widget.header,
footer: widget.footer,
selectedFiles: widget.selectedFiles,
showSelectAllByDefault: widget.showSelectAllByDefault,
showSelectAllByDefault:
widget.showSelectAllByDefault && widget.groupType.showGroupHeader(),
isScrollablePositionedList: widget.isScrollablePositionedList,
),
);
}
List<List<EnteFile>> _groupFiles(List<EnteFile> files) {
// create groups of 200 files for performance
List<List<EnteFile>> _genericGroupForPerf(List<EnteFile> files) {
if (widget.groupType == GroupType.size) {
// sort files by fileSize on the bases of _sortOrderAsc
files.sort((a, b) {
if (_sortOrderAsc) {
return a.fileSize!.compareTo(b.fileSize!);
} else {
return b.fileSize!.compareTo(a.fileSize!);
}
});
}
// 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) {
return [files];
}
final List<List<EnteFile>> resultGroupedFiles = [];
List<EnteFile> singleGroupFile = [];
const int groupSize = 40;
for (int i = 0; i < files.length; i += 1) {
singleGroupFile.add(files[i]);
if (singleGroupFile.length == groupSize) {
resultGroupedFiles.add(singleGroupFile);
singleGroupFile = [];
}
}
if (singleGroupFile.isNotEmpty) {
resultGroupedFiles.add(singleGroupFile);
}
_logger.info('Grouped files into ${resultGroupedFiles.length} groups');
return resultGroupedFiles;
}
List<List<EnteFile>> _groupBasedOnTime(List<EnteFile> files) {
List<EnteFile> dailyFiles = [];
final List<List<EnteFile>> resultGroupedFiles = [];