mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-02-24 10:28:50 +01:00
Support sorting by filename in Photos tab
This commit is contained in:
parent
3982f5d5ff
commit
083263c561
5 changed files with 208 additions and 20 deletions
|
@ -394,6 +394,12 @@
|
|||
"@settingsUseBlackInDarkThemeFalseDescription": {
|
||||
"description": "When black in dark theme is set to false"
|
||||
},
|
||||
"settingsMiscellaneousTitle": "Miscellaneous",
|
||||
"settingsMiscellaneousPageTitle": "Miscellaneous settings",
|
||||
"settingsPhotosTabSortByNameTitle": "Sort by filename in Photos",
|
||||
"@settingsPhotosTabSortByNameTitle": {
|
||||
"description": "Sort photos listed in the Photos tab by filename (descending)"
|
||||
},
|
||||
"settingsExperimentalTitle": "Experimental",
|
||||
"settingsExperimentalDescription": "Features that are not ready for everyday use",
|
||||
"settingsExperimentalPageTitle": "Experimental settings",
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
"settingsPhotoEnhancementPageTitle",
|
||||
"settingsEnhanceMaxResolutionTitle",
|
||||
"settingsEnhanceMaxResolutionDescription",
|
||||
"settingsMiscellaneousTitle",
|
||||
"settingsMiscellaneousPageTitle",
|
||||
"settingsPhotosTabSortByNameTitle",
|
||||
"settingsExperimentalTitle",
|
||||
"settingsExperimentalDescription",
|
||||
"settingsExperimentalPageTitle",
|
||||
|
@ -124,6 +127,9 @@
|
|||
"settingsPhotoEnhancementPageTitle",
|
||||
"settingsEnhanceMaxResolutionTitle",
|
||||
"settingsEnhanceMaxResolutionDescription",
|
||||
"settingsMiscellaneousTitle",
|
||||
"settingsMiscellaneousPageTitle",
|
||||
"settingsPhotosTabSortByNameTitle",
|
||||
"settingsExperimentalTitle",
|
||||
"settingsExperimentalDescription",
|
||||
"settingsExperimentalPageTitle",
|
||||
|
@ -257,6 +263,9 @@
|
|||
"settingsUseBlackInDarkThemeTitle",
|
||||
"settingsUseBlackInDarkThemeTrueDescription",
|
||||
"settingsUseBlackInDarkThemeFalseDescription",
|
||||
"settingsMiscellaneousTitle",
|
||||
"settingsMiscellaneousPageTitle",
|
||||
"settingsPhotosTabSortByNameTitle",
|
||||
"settingsExperimentalTitle",
|
||||
"settingsExperimentalDescription",
|
||||
"settingsExperimentalPageTitle",
|
||||
|
@ -399,6 +408,9 @@
|
|||
"settingsPhotoEnhancementPageTitle",
|
||||
"settingsEnhanceMaxResolutionTitle",
|
||||
"settingsEnhanceMaxResolutionDescription",
|
||||
"settingsMiscellaneousTitle",
|
||||
"settingsMiscellaneousPageTitle",
|
||||
"settingsPhotosTabSortByNameTitle",
|
||||
"rootPickerSkipConfirmationDialogContent2",
|
||||
"helpButtonLabel",
|
||||
"backgroundServiceStopping",
|
||||
|
@ -418,6 +430,9 @@
|
|||
],
|
||||
|
||||
"fi": [
|
||||
"settingsMiscellaneousTitle",
|
||||
"settingsMiscellaneousPageTitle",
|
||||
"settingsPhotosTabSortByNameTitle",
|
||||
"enhanceSuperResolution4xTitle",
|
||||
"enhanceStyleTransferTitle"
|
||||
],
|
||||
|
@ -428,6 +443,9 @@
|
|||
"settingsPhotoEnhancementPageTitle",
|
||||
"settingsEnhanceMaxResolutionTitle",
|
||||
"settingsEnhanceMaxResolutionDescription",
|
||||
"settingsMiscellaneousTitle",
|
||||
"settingsMiscellaneousPageTitle",
|
||||
"settingsPhotosTabSortByNameTitle",
|
||||
"helpTooltip",
|
||||
"helpButtonLabel",
|
||||
"removeFromAlbumTooltip",
|
||||
|
@ -450,6 +468,9 @@
|
|||
"settingsPhotoEnhancementPageTitle",
|
||||
"settingsEnhanceMaxResolutionTitle",
|
||||
"settingsEnhanceMaxResolutionDescription",
|
||||
"settingsMiscellaneousTitle",
|
||||
"settingsMiscellaneousPageTitle",
|
||||
"settingsPhotosTabSortByNameTitle",
|
||||
"createCollectionTooltip",
|
||||
"createCollectionDialogAlbumLabel",
|
||||
"createCollectionDialogAlbumDescription",
|
||||
|
@ -490,6 +511,9 @@
|
|||
"settingsPhotoEnhancementPageTitle",
|
||||
"settingsEnhanceMaxResolutionTitle",
|
||||
"settingsEnhanceMaxResolutionDescription",
|
||||
"settingsMiscellaneousTitle",
|
||||
"settingsMiscellaneousPageTitle",
|
||||
"settingsPhotosTabSortByNameTitle",
|
||||
"enhanceTooltip",
|
||||
"enhanceButtonLabel",
|
||||
"enhanceIntroDialogTitle",
|
||||
|
@ -509,6 +533,9 @@
|
|||
"settingsPhotoEnhancementPageTitle",
|
||||
"settingsEnhanceMaxResolutionTitle",
|
||||
"settingsEnhanceMaxResolutionDescription",
|
||||
"settingsMiscellaneousTitle",
|
||||
"settingsMiscellaneousPageTitle",
|
||||
"settingsPhotosTabSortByNameTitle",
|
||||
"enhanceTooltip",
|
||||
"enhanceButtonLabel",
|
||||
"enhanceIntroDialogTitle",
|
||||
|
@ -528,6 +555,9 @@
|
|||
"settingsPhotoEnhancementPageTitle",
|
||||
"settingsEnhanceMaxResolutionTitle",
|
||||
"settingsEnhanceMaxResolutionDescription",
|
||||
"settingsMiscellaneousTitle",
|
||||
"settingsMiscellaneousPageTitle",
|
||||
"settingsPhotosTabSortByNameTitle",
|
||||
"enhanceTooltip",
|
||||
"enhanceButtonLabel",
|
||||
"enhanceIntroDialogTitle",
|
||||
|
@ -547,6 +577,9 @@
|
|||
"settingsPhotoEnhancementPageTitle",
|
||||
"settingsEnhanceMaxResolutionTitle",
|
||||
"settingsEnhanceMaxResolutionDescription",
|
||||
"settingsMiscellaneousTitle",
|
||||
"settingsMiscellaneousPageTitle",
|
||||
"settingsPhotosTabSortByNameTitle",
|
||||
"enhanceTooltip",
|
||||
"enhanceButtonLabel",
|
||||
"enhanceIntroDialogTitle",
|
||||
|
|
|
@ -199,6 +199,15 @@ class Pref {
|
|||
Future<bool> setFirstRunTime(int value) => _set<int>(
|
||||
PrefKey.firstRunTime, value, (key, value) => provider.setInt(key, value));
|
||||
|
||||
bool? isPhotosTabSortByName() =>
|
||||
provider.getBool(PrefKey.isPhotosTabSortByName);
|
||||
bool isPhotosTabSortByNameOr([bool def = false]) =>
|
||||
isPhotosTabSortByName() ?? def;
|
||||
Future<bool> setPhotosTabSortByName(bool value) => _set<bool>(
|
||||
PrefKey.isPhotosTabSortByName,
|
||||
value,
|
||||
(key, value) => provider.setBool(key, value));
|
||||
|
||||
Future<bool> _set<T>(PrefKey key, T value,
|
||||
Future<bool> Function(PrefKey key, T value) setFn) async {
|
||||
if (await setFn(key, value)) {
|
||||
|
@ -492,6 +501,7 @@ enum PrefKey {
|
|||
enhanceMaxHeight,
|
||||
hasShownEnhanceInfo,
|
||||
firstRunTime,
|
||||
isPhotosTabSortByName,
|
||||
|
||||
// account pref
|
||||
isEnableFaceRecognitionApp,
|
||||
|
@ -554,6 +564,8 @@ extension on PrefKey {
|
|||
return "hasShownEnhanceInfo";
|
||||
case PrefKey.firstRunTime:
|
||||
return "firstRunTime";
|
||||
case PrefKey.isPhotosTabSortByName:
|
||||
return "isPhotosTabSortByName";
|
||||
|
||||
// account pref
|
||||
case PrefKey.isEnableFaceRecognitionApp:
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:math' as math;
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:collection/collection.dart' show compareNatural;
|
||||
import 'package:draggable_scrollbar/draggable_scrollbar.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
@ -436,6 +437,13 @@ class _HomePhotosState extends State<HomePhotos>
|
|||
} else {
|
||||
_stopMetadataTask();
|
||||
}
|
||||
} else if (ev.key == PrefKey.isPhotosTabSortByName) {
|
||||
if (_bloc.state is! ScanAccountDirBlocInit) {
|
||||
_log.info("[_onPrefUpdated] Update view after changing sort option");
|
||||
setState(() {
|
||||
_transformItems(_bloc.state.files);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -484,6 +492,30 @@ class _HomePhotosState extends State<HomePhotos>
|
|||
|
||||
/// Transform a File list to grid items
|
||||
void _transformItems(List<File> files) {
|
||||
if (!Pref().isPhotosTabSortByNameOr()) {
|
||||
_transformItemsByDate(files);
|
||||
} else {
|
||||
_transformItemsByName(files);
|
||||
}
|
||||
}
|
||||
|
||||
void _transformItemsByName(List<File> files) {
|
||||
_backingFiles = files
|
||||
.where((f) => f.isArchived != true)
|
||||
.sorted((a, b) => compareNatural(b.filename, a.filename));
|
||||
|
||||
itemStreamListItems = () sync* {
|
||||
for (int i = 0; i < _backingFiles.length; ++i) {
|
||||
final item = _transformItemToListItem(i, _backingFiles[i]);
|
||||
if (item != null) {
|
||||
yield item;
|
||||
}
|
||||
}
|
||||
}()
|
||||
.toList();
|
||||
}
|
||||
|
||||
void _transformItemsByDate(List<File> files) {
|
||||
_backingFiles = files
|
||||
.where((f) => f.isArchived != true)
|
||||
.sorted(compareFileDateTimeDescending);
|
||||
|
@ -503,25 +535,9 @@ class _HomePhotosState extends State<HomePhotos>
|
|||
}
|
||||
memoryAlbumHelper.addFile(f);
|
||||
|
||||
final previewUrl = api_util.getFilePreviewUrl(widget.account, f,
|
||||
width: k.photoThumbSize, height: k.photoThumbSize);
|
||||
if (file_util.isSupportedImageFormat(f)) {
|
||||
yield _ImageListItem(
|
||||
file: f,
|
||||
account: widget.account,
|
||||
previewUrl: previewUrl,
|
||||
onTap: () => _onItemTap(i),
|
||||
);
|
||||
} else if (file_util.isSupportedVideoFormat(f)) {
|
||||
yield _VideoListItem(
|
||||
file: f,
|
||||
account: widget.account,
|
||||
previewUrl: previewUrl,
|
||||
onTap: () => _onItemTap(i),
|
||||
);
|
||||
} else {
|
||||
_log.shout(
|
||||
"[_transformItems] Unsupported file format: ${f.contentType}");
|
||||
final item = _transformItemToListItem(i, f);
|
||||
if (item != null) {
|
||||
yield item;
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
@ -530,6 +546,30 @@ class _HomePhotosState extends State<HomePhotos>
|
|||
.build((year) => L10n.global().memoryAlbumName(today.year - year));
|
||||
}
|
||||
|
||||
_ListItem? _transformItemToListItem(int i, File f) {
|
||||
final previewUrl = api_util.getFilePreviewUrl(widget.account, f,
|
||||
width: k.photoThumbSize, height: k.photoThumbSize);
|
||||
if (file_util.isSupportedImageFormat(f)) {
|
||||
return _ImageListItem(
|
||||
file: f,
|
||||
account: widget.account,
|
||||
previewUrl: previewUrl,
|
||||
onTap: () => _onItemTap(i),
|
||||
);
|
||||
} else if (file_util.isSupportedVideoFormat(f)) {
|
||||
return _VideoListItem(
|
||||
file: f,
|
||||
account: widget.account,
|
||||
previewUrl: previewUrl,
|
||||
onTap: () => _onItemTap(i),
|
||||
);
|
||||
} else {
|
||||
_log.shout(
|
||||
"[_transformItemToListItem] Unsupported file format: ${f.contentType}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
void _reqQuery() {
|
||||
_bloc.add(const ScanAccountDirBlocQuery());
|
||||
}
|
||||
|
|
|
@ -66,6 +66,14 @@ class _SettingsState extends State<Settings> {
|
|||
|
||||
final settings = AccountPref.of(widget.account);
|
||||
_isEnableMemoryAlbum = settings.isEnableMemoryAlbumOr(true);
|
||||
|
||||
_prefUpdatedListener.begin();
|
||||
}
|
||||
|
||||
@override
|
||||
dispose() {
|
||||
_prefUpdatedListener.end();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -107,7 +115,9 @@ class _SettingsState extends State<Settings> {
|
|||
title: Text(L10n.global().settingsMemoriesTitle),
|
||||
subtitle: Text(L10n.global().settingsMemoriesSubtitle),
|
||||
value: _isEnableMemoryAlbum,
|
||||
onChanged: _onEnableMemoryAlbumChanged,
|
||||
onChanged: Pref().isPhotosTabSortByNameOr()
|
||||
? null
|
||||
: _onEnableMemoryAlbumChanged,
|
||||
),
|
||||
_buildSubSettings(
|
||||
context,
|
||||
|
@ -157,6 +167,15 @@ class _SettingsState extends State<Settings> {
|
|||
description: L10n.global().settingsThemeDescription,
|
||||
builder: () => _ThemeSettings(),
|
||||
),
|
||||
_buildSubSettings(
|
||||
context,
|
||||
leading: Icon(
|
||||
Icons.emoji_symbols_outlined,
|
||||
color: AppTheme.getUnfocusedIconColor(context),
|
||||
),
|
||||
label: L10n.global().settingsMiscellaneousTitle,
|
||||
builder: () => const _MiscSettings(),
|
||||
),
|
||||
if (_enabledExperiments.isNotEmpty)
|
||||
_buildSubSettings(
|
||||
context,
|
||||
|
@ -365,6 +384,12 @@ class _SettingsState extends State<Settings> {
|
|||
}
|
||||
}
|
||||
|
||||
void _onPrefUpdated(PrefUpdatedEvent ev) {
|
||||
if (ev.key == PrefKey.isPhotosTabSortByName) {
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _setExifSupport(bool value) async {
|
||||
final oldValue = _isEnableExif;
|
||||
setState(() {
|
||||
|
@ -385,6 +410,9 @@ class _SettingsState extends State<Settings> {
|
|||
late bool _isEnableExif;
|
||||
late bool _isEnableMemoryAlbum;
|
||||
|
||||
late final _prefUpdatedListener =
|
||||
AppEventListener<PrefUpdatedEvent>(_onPrefUpdated);
|
||||
|
||||
static final _log = Logger("widget.settings._SettingsState");
|
||||
|
||||
static const String _sourceRepo = "https://bit.ly/3LQerBv";
|
||||
|
@ -1287,6 +1315,75 @@ class _ThemeSettingsState extends State<_ThemeSettings> {
|
|||
static final _log = Logger("widget.settings._ThemeSettingsState");
|
||||
}
|
||||
|
||||
class _MiscSettings extends StatefulWidget {
|
||||
const _MiscSettings({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
createState() => _MiscSettingsState();
|
||||
}
|
||||
|
||||
class _MiscSettingsState extends State<_MiscSettings> {
|
||||
@override
|
||||
initState() {
|
||||
super.initState();
|
||||
_isPhotosTabSortByName = Pref().isPhotosTabSortByNameOr();
|
||||
}
|
||||
|
||||
@override
|
||||
build(BuildContext context) {
|
||||
return AppTheme(
|
||||
child: Scaffold(
|
||||
body: Builder(
|
||||
builder: (context) => _buildContent(context),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildContent(BuildContext context) {
|
||||
return CustomScrollView(
|
||||
slivers: [
|
||||
SliverAppBar(
|
||||
pinned: true,
|
||||
title: Text(L10n.global().settingsMiscellaneousPageTitle),
|
||||
),
|
||||
SliverList(
|
||||
delegate: SliverChildListDelegate(
|
||||
[
|
||||
SwitchListTile(
|
||||
title: Text(L10n.global().settingsPhotosTabSortByNameTitle),
|
||||
value: _isPhotosTabSortByName,
|
||||
onChanged: (value) => _onPhotosTabSortByNameChanged(value),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _onPhotosTabSortByNameChanged(bool value) async {
|
||||
final oldValue = _isPhotosTabSortByName;
|
||||
setState(() {
|
||||
_isPhotosTabSortByName = value;
|
||||
});
|
||||
if (!await Pref().setPhotosTabSortByName(value)) {
|
||||
_log.severe("[_onPhotosTabSortByNameChanged] Failed writing pref");
|
||||
SnackBarManager().showSnackBar(SnackBar(
|
||||
content: Text(L10n.global().writePreferenceFailureNotification),
|
||||
duration: k.snackBarDurationNormal,
|
||||
));
|
||||
setState(() {
|
||||
_isPhotosTabSortByName = oldValue;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
late bool _isPhotosTabSortByName;
|
||||
|
||||
static final _log = Logger("widget.settings._MiscSettingsState");
|
||||
}
|
||||
|
||||
class _ExperimentalSettings extends StatefulWidget {
|
||||
@override
|
||||
createState() => _ExperimentalSettingsState();
|
||||
|
|
Loading…
Reference in a new issue