mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-03-24 16:04:43 +01:00
Group photos by date in album browser
This commit is contained in:
parent
dfe1acc6e4
commit
5557b591c9
9 changed files with 266 additions and 34 deletions
|
@ -323,6 +323,14 @@
|
||||||
"settingsScreenBrightnessDescription": "Override system brightness level",
|
"settingsScreenBrightnessDescription": "Override system brightness level",
|
||||||
"settingsForceRotationTitle": "Ignore rotation lock",
|
"settingsForceRotationTitle": "Ignore rotation lock",
|
||||||
"settingsForceRotationDescription": "Rotate the screen even when auto rotation is disabled",
|
"settingsForceRotationDescription": "Rotate the screen even when auto rotation is disabled",
|
||||||
|
"settingsAlbumTitle": "Album",
|
||||||
|
"settingsAlbumDescription": "Customize albums",
|
||||||
|
"settingsAlbumPageTitle": "Album settings",
|
||||||
|
"@settingsAlbumPageTitle": {
|
||||||
|
"description": "Dedicated page for album settings"
|
||||||
|
},
|
||||||
|
"settingsShowDateInAlbumTitle": "Group photos by date",
|
||||||
|
"settingsShowDateInAlbumDescription": "Apply only when the album is sorted by time",
|
||||||
"settingsThemeTitle": "Theme",
|
"settingsThemeTitle": "Theme",
|
||||||
"settingsThemeDescription": "Customize the appearance of the app",
|
"settingsThemeDescription": "Customize the appearance of the app",
|
||||||
"settingsThemePageTitle": "Theme settings",
|
"settingsThemePageTitle": "Theme settings",
|
||||||
|
@ -844,7 +852,6 @@
|
||||||
"description": "Create a password protected share link on server and share it"
|
"description": "Create a password protected share link on server and share it"
|
||||||
},
|
},
|
||||||
"shareMethodPasswordLinkDescription": "Create a new password protected link on the server",
|
"shareMethodPasswordLinkDescription": "Create a new password protected link on the server",
|
||||||
|
|
||||||
"errorUnauthenticated": "Unauthenticated access. Please sign-in again if the problem continues",
|
"errorUnauthenticated": "Unauthenticated access. Please sign-in again if the problem continues",
|
||||||
"@errorUnauthenticated": {
|
"@errorUnauthenticated": {
|
||||||
"description": "Error message when server responds with HTTP401"
|
"description": "Error message when server responds with HTTP401"
|
||||||
|
@ -869,4 +876,4 @@
|
||||||
"@errorServerError": {
|
"@errorServerError": {
|
||||||
"description": "HTTP 500"
|
"description": "HTTP 500"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,18 @@
|
||||||
{
|
{
|
||||||
|
"cs": [
|
||||||
|
"settingsAlbumTitle",
|
||||||
|
"settingsAlbumDescription",
|
||||||
|
"settingsAlbumPageTitle",
|
||||||
|
"settingsShowDateInAlbumTitle",
|
||||||
|
"settingsShowDateInAlbumDescription"
|
||||||
|
],
|
||||||
|
|
||||||
"de": [
|
"de": [
|
||||||
|
"settingsAlbumTitle",
|
||||||
|
"settingsAlbumDescription",
|
||||||
|
"settingsAlbumPageTitle",
|
||||||
|
"settingsShowDateInAlbumTitle",
|
||||||
|
"settingsShowDateInAlbumDescription",
|
||||||
"timeSecondInputHint",
|
"timeSecondInputHint",
|
||||||
"slideshowTooltip",
|
"slideshowTooltip",
|
||||||
"slideshowSetupDialogTitle",
|
"slideshowSetupDialogTitle",
|
||||||
|
@ -25,6 +38,11 @@
|
||||||
"settingsScreenBrightnessDescription",
|
"settingsScreenBrightnessDescription",
|
||||||
"settingsForceRotationTitle",
|
"settingsForceRotationTitle",
|
||||||
"settingsForceRotationDescription",
|
"settingsForceRotationDescription",
|
||||||
|
"settingsAlbumTitle",
|
||||||
|
"settingsAlbumDescription",
|
||||||
|
"settingsAlbumPageTitle",
|
||||||
|
"settingsShowDateInAlbumTitle",
|
||||||
|
"settingsShowDateInAlbumDescription",
|
||||||
"settingsThemeTitle",
|
"settingsThemeTitle",
|
||||||
"settingsThemeDescription",
|
"settingsThemeDescription",
|
||||||
"settingsThemePageTitle",
|
"settingsThemePageTitle",
|
||||||
|
@ -88,6 +106,14 @@
|
||||||
"shareMethodPasswordLinkDescription"
|
"shareMethodPasswordLinkDescription"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"es": [
|
||||||
|
"settingsAlbumTitle",
|
||||||
|
"settingsAlbumDescription",
|
||||||
|
"settingsAlbumPageTitle",
|
||||||
|
"settingsShowDateInAlbumTitle",
|
||||||
|
"settingsShowDateInAlbumDescription"
|
||||||
|
],
|
||||||
|
|
||||||
"fr": [
|
"fr": [
|
||||||
"collectionsTooltip",
|
"collectionsTooltip",
|
||||||
"settingsViewerTitle",
|
"settingsViewerTitle",
|
||||||
|
@ -97,6 +123,11 @@
|
||||||
"settingsScreenBrightnessDescription",
|
"settingsScreenBrightnessDescription",
|
||||||
"settingsForceRotationTitle",
|
"settingsForceRotationTitle",
|
||||||
"settingsForceRotationDescription",
|
"settingsForceRotationDescription",
|
||||||
|
"settingsAlbumTitle",
|
||||||
|
"settingsAlbumDescription",
|
||||||
|
"settingsAlbumPageTitle",
|
||||||
|
"settingsShowDateInAlbumTitle",
|
||||||
|
"settingsShowDateInAlbumDescription",
|
||||||
"settingsThemeTitle",
|
"settingsThemeTitle",
|
||||||
"settingsThemeDescription",
|
"settingsThemeDescription",
|
||||||
"settingsThemePageTitle",
|
"settingsThemePageTitle",
|
||||||
|
@ -141,6 +172,11 @@
|
||||||
],
|
],
|
||||||
|
|
||||||
"ru": [
|
"ru": [
|
||||||
|
"settingsAlbumTitle",
|
||||||
|
"settingsAlbumDescription",
|
||||||
|
"settingsAlbumPageTitle",
|
||||||
|
"settingsShowDateInAlbumTitle",
|
||||||
|
"settingsShowDateInAlbumDescription",
|
||||||
"settingsCaptureLogsTitle",
|
"settingsCaptureLogsTitle",
|
||||||
"settingsCaptureLogsDescription",
|
"settingsCaptureLogsDescription",
|
||||||
"captureLogDetails",
|
"captureLogDetails",
|
||||||
|
|
|
@ -114,6 +114,13 @@ class Pref {
|
||||||
Future<bool> setSlideshowRepeat(bool value) =>
|
Future<bool> setSlideshowRepeat(bool value) =>
|
||||||
_setBool(PrefKey.isSlideshowRepeat, value);
|
_setBool(PrefKey.isSlideshowRepeat, value);
|
||||||
|
|
||||||
|
bool? isAlbumBrowserShowDate() =>
|
||||||
|
_pref.getBool(_toKey(PrefKey.isAlbumBrowserShowDate));
|
||||||
|
bool isAlbumBrowserShowDateOr([bool def = false]) =>
|
||||||
|
isAlbumBrowserShowDate() ?? def;
|
||||||
|
Future<bool> setAlbumBrowserShowDate(bool value) =>
|
||||||
|
_setBool(PrefKey.isAlbumBrowserShowDate, value);
|
||||||
|
|
||||||
bool? hasNewSharedAlbum() => _pref.getBool(_toKey(PrefKey.newSharedAlbum));
|
bool? hasNewSharedAlbum() => _pref.getBool(_toKey(PrefKey.newSharedAlbum));
|
||||||
bool hasNewSharedAlbumOr(bool def) => hasNewSharedAlbum() ?? def;
|
bool hasNewSharedAlbumOr(bool def) => hasNewSharedAlbum() ?? def;
|
||||||
Future<bool> setNewSharedAlbum(bool value) =>
|
Future<bool> setNewSharedAlbum(bool value) =>
|
||||||
|
@ -189,6 +196,8 @@ class Pref {
|
||||||
return "isSlideshowShuffle";
|
return "isSlideshowShuffle";
|
||||||
case PrefKey.isSlideshowRepeat:
|
case PrefKey.isSlideshowRepeat:
|
||||||
return "isSlideshowRepeat";
|
return "isSlideshowRepeat";
|
||||||
|
case PrefKey.isAlbumBrowserShowDate:
|
||||||
|
return "isAlbumBrowserShowDate";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,6 +225,7 @@ enum PrefKey {
|
||||||
slideshowDuration,
|
slideshowDuration,
|
||||||
isSlideshowShuffle,
|
isSlideshowShuffle,
|
||||||
isSlideshowRepeat,
|
isSlideshowRepeat,
|
||||||
|
isAlbumBrowserShowDate,
|
||||||
}
|
}
|
||||||
|
|
||||||
extension PrefExtension on Pref {
|
extension PrefExtension on Pref {
|
||||||
|
|
|
@ -19,6 +19,7 @@ import 'package:nc_photos/k.dart' as k;
|
||||||
import 'package:nc_photos/list_extension.dart';
|
import 'package:nc_photos/list_extension.dart';
|
||||||
import 'package:nc_photos/or_null.dart';
|
import 'package:nc_photos/or_null.dart';
|
||||||
import 'package:nc_photos/platform/k.dart' as platform_k;
|
import 'package:nc_photos/platform/k.dart' as platform_k;
|
||||||
|
import 'package:nc_photos/pref.dart';
|
||||||
import 'package:nc_photos/session_storage.dart';
|
import 'package:nc_photos/session_storage.dart';
|
||||||
import 'package:nc_photos/share_handler.dart';
|
import 'package:nc_photos/share_handler.dart';
|
||||||
import 'package:nc_photos/snack_bar_manager.dart';
|
import 'package:nc_photos/snack_bar_manager.dart';
|
||||||
|
@ -30,6 +31,7 @@ import 'package:nc_photos/use_case/update_album_with_actual_items.dart';
|
||||||
import 'package:nc_photos/widget/album_browser_mixin.dart';
|
import 'package:nc_photos/widget/album_browser_mixin.dart';
|
||||||
import 'package:nc_photos/widget/draggable_item_list_mixin.dart';
|
import 'package:nc_photos/widget/draggable_item_list_mixin.dart';
|
||||||
import 'package:nc_photos/widget/fancy_option_picker.dart';
|
import 'package:nc_photos/widget/fancy_option_picker.dart';
|
||||||
|
import 'package:nc_photos/widget/photo_list_helper.dart';
|
||||||
import 'package:nc_photos/widget/photo_list_item.dart';
|
import 'package:nc_photos/widget/photo_list_item.dart';
|
||||||
import 'package:nc_photos/widget/selectable_item_stream_list_mixin.dart';
|
import 'package:nc_photos/widget/selectable_item_stream_list_mixin.dart';
|
||||||
import 'package:nc_photos/widget/simple_input_dialog.dart';
|
import 'package:nc_photos/widget/simple_input_dialog.dart';
|
||||||
|
@ -571,6 +573,9 @@ class _AlbumBrowserState extends State<AlbumBrowser>
|
||||||
.map((e) => e.file)
|
.map((e) => e.file)
|
||||||
.where((element) => file_util.isSupportedFormat(element))
|
.where((element) => file_util.isSupportedFormat(element))
|
||||||
.toList();
|
.toList();
|
||||||
|
final dateHelper = PhotoListDateGroupHelper(
|
||||||
|
isMonthOnly: false,
|
||||||
|
);
|
||||||
|
|
||||||
final items = () sync* {
|
final items = () sync* {
|
||||||
for (int i = 0; i < _sortedItems.length; ++i) {
|
for (int i = 0; i < _sortedItems.length; ++i) {
|
||||||
|
@ -582,6 +587,14 @@ class _AlbumBrowserState extends State<AlbumBrowser>
|
||||||
width: k.photoThumbSize,
|
width: k.photoThumbSize,
|
||||||
height: k.photoThumbSize,
|
height: k.photoThumbSize,
|
||||||
);
|
);
|
||||||
|
if ((_editAlbum ?? _album)?.sortProvider is AlbumTimeSortProvider &&
|
||||||
|
Pref.inst().isAlbumBrowserShowDateOr()) {
|
||||||
|
final date = dateHelper.onFile(item.file);
|
||||||
|
if (date != null) {
|
||||||
|
yield _DateListItem(date: date);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (file_util.isSupportedImageFormat(item.file)) {
|
if (file_util.isSupportedImageFormat(item.file)) {
|
||||||
yield _ImageListItem(
|
yield _ImageListItem(
|
||||||
index: i,
|
index: i,
|
||||||
|
@ -705,7 +718,7 @@ enum _SelectionMenuOption {
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class _ListItem implements SelectableItem, DraggableItem {
|
abstract class _ListItem implements SelectableItem, DraggableItem {
|
||||||
_ListItem({
|
const _ListItem({
|
||||||
required this.index,
|
required this.index,
|
||||||
VoidCallback? onTap,
|
VoidCallback? onTap,
|
||||||
DragTargetAccept<DraggableItem>? onDropBefore,
|
DragTargetAccept<DraggableItem>? onDropBefore,
|
||||||
|
@ -911,3 +924,24 @@ class _EditLabelListItem extends _LabelListItem {
|
||||||
|
|
||||||
final VoidCallback? onEditPressed;
|
final VoidCallback? onEditPressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _DateListItem extends _ListItem {
|
||||||
|
const _DateListItem({
|
||||||
|
required this.date,
|
||||||
|
}) : super(index: -1);
|
||||||
|
|
||||||
|
@override
|
||||||
|
get isSelectable => false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
get staggeredTile => const StaggeredTile.extent(99, 32);
|
||||||
|
|
||||||
|
@override
|
||||||
|
buildWidget(BuildContext context) {
|
||||||
|
return PhotoListDate(
|
||||||
|
date: date,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final DateTime date;
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import 'package:nc_photos/iterable_extension.dart';
|
||||||
import 'package:nc_photos/k.dart' as k;
|
import 'package:nc_photos/k.dart' as k;
|
||||||
import 'package:nc_photos/or_null.dart';
|
import 'package:nc_photos/or_null.dart';
|
||||||
import 'package:nc_photos/platform/k.dart' as platform_k;
|
import 'package:nc_photos/platform/k.dart' as platform_k;
|
||||||
|
import 'package:nc_photos/pref.dart';
|
||||||
import 'package:nc_photos/share_handler.dart';
|
import 'package:nc_photos/share_handler.dart';
|
||||||
import 'package:nc_photos/snack_bar_manager.dart';
|
import 'package:nc_photos/snack_bar_manager.dart';
|
||||||
import 'package:nc_photos/theme.dart';
|
import 'package:nc_photos/theme.dart';
|
||||||
|
@ -31,6 +32,7 @@ import 'package:nc_photos/use_case/update_album.dart';
|
||||||
import 'package:nc_photos/use_case/update_album_with_actual_items.dart';
|
import 'package:nc_photos/use_case/update_album_with_actual_items.dart';
|
||||||
import 'package:nc_photos/widget/album_browser_mixin.dart';
|
import 'package:nc_photos/widget/album_browser_mixin.dart';
|
||||||
import 'package:nc_photos/widget/fancy_option_picker.dart';
|
import 'package:nc_photos/widget/fancy_option_picker.dart';
|
||||||
|
import 'package:nc_photos/widget/photo_list_helper.dart';
|
||||||
import 'package:nc_photos/widget/photo_list_item.dart';
|
import 'package:nc_photos/widget/photo_list_item.dart';
|
||||||
import 'package:nc_photos/widget/selectable_item_stream_list_mixin.dart';
|
import 'package:nc_photos/widget/selectable_item_stream_list_mixin.dart';
|
||||||
import 'package:nc_photos/widget/viewer.dart';
|
import 'package:nc_photos/widget/viewer.dart';
|
||||||
|
@ -535,6 +537,10 @@ class _DynamicAlbumBrowserState extends State<DynamicAlbumBrowser>
|
||||||
.map((e) => e.file)
|
.map((e) => e.file)
|
||||||
.where((element) => file_util.isSupportedFormat(element))
|
.where((element) => file_util.isSupportedFormat(element))
|
||||||
.toList();
|
.toList();
|
||||||
|
final dateHelper = PhotoListDateGroupHelper(
|
||||||
|
isMonthOnly: false,
|
||||||
|
);
|
||||||
|
|
||||||
itemStreamListItems = () sync* {
|
itemStreamListItems = () sync* {
|
||||||
for (int i = 0; i < _sortedItems.length; ++i) {
|
for (int i = 0; i < _sortedItems.length; ++i) {
|
||||||
final item = _sortedItems[i];
|
final item = _sortedItems[i];
|
||||||
|
@ -545,6 +551,14 @@ class _DynamicAlbumBrowserState extends State<DynamicAlbumBrowser>
|
||||||
width: k.photoThumbSize,
|
width: k.photoThumbSize,
|
||||||
height: k.photoThumbSize,
|
height: k.photoThumbSize,
|
||||||
);
|
);
|
||||||
|
if ((_editAlbum ?? _album)?.sortProvider is AlbumTimeSortProvider &&
|
||||||
|
Pref.inst().isAlbumBrowserShowDateOr()) {
|
||||||
|
final date = dateHelper.onFile(item.file);
|
||||||
|
if (date != null) {
|
||||||
|
yield _DateListItem(date: date);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (file_util.isSupportedImageFormat(item.file)) {
|
if (file_util.isSupportedImageFormat(item.file)) {
|
||||||
yield _ImageListItem(
|
yield _ImageListItem(
|
||||||
index: i,
|
index: i,
|
||||||
|
@ -596,7 +610,7 @@ enum _SelectionMenuOption {
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class _ListItem implements SelectableItem {
|
abstract class _ListItem implements SelectableItem {
|
||||||
_ListItem({
|
const _ListItem({
|
||||||
required this.index,
|
required this.index,
|
||||||
VoidCallback? onTap,
|
VoidCallback? onTap,
|
||||||
}) : _onTap = onTap;
|
}) : _onTap = onTap;
|
||||||
|
@ -685,3 +699,24 @@ class _VideoListItem extends _FileListItem {
|
||||||
final Account account;
|
final Account account;
|
||||||
final String previewUrl;
|
final String previewUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _DateListItem extends _ListItem {
|
||||||
|
const _DateListItem({
|
||||||
|
required this.date,
|
||||||
|
}) : super(index: -1);
|
||||||
|
|
||||||
|
@override
|
||||||
|
get isSelectable => false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
get staggeredTile => const StaggeredTile.extent(99, 32);
|
||||||
|
|
||||||
|
@override
|
||||||
|
buildWidget(BuildContext context) {
|
||||||
|
return PhotoListDate(
|
||||||
|
date: date,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final DateTime date;
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
|
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
|
||||||
import 'package:intl/intl.dart';
|
|
||||||
import 'package:kiwi/kiwi.dart';
|
import 'package:kiwi/kiwi.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:nc_photos/account.dart';
|
import 'package:nc_photos/account.dart';
|
||||||
|
@ -40,6 +39,7 @@ import 'package:nc_photos/widget/album_picker_dialog.dart';
|
||||||
import 'package:nc_photos/widget/home_app_bar.dart';
|
import 'package:nc_photos/widget/home_app_bar.dart';
|
||||||
import 'package:nc_photos/widget/measure.dart';
|
import 'package:nc_photos/widget/measure.dart';
|
||||||
import 'package:nc_photos/widget/page_visibility_mixin.dart';
|
import 'package:nc_photos/widget/page_visibility_mixin.dart';
|
||||||
|
import 'package:nc_photos/widget/photo_list_helper.dart';
|
||||||
import 'package:nc_photos/widget/photo_list_item.dart';
|
import 'package:nc_photos/widget/photo_list_item.dart';
|
||||||
import 'package:nc_photos/widget/selectable_item_stream_list_mixin.dart';
|
import 'package:nc_photos/widget/selectable_item_stream_list_mixin.dart';
|
||||||
import 'package:nc_photos/widget/selection_app_bar.dart';
|
import 'package:nc_photos/widget/selection_app_bar.dart';
|
||||||
|
@ -547,18 +547,16 @@ class _HomePhotosState extends State<HomePhotos>
|
||||||
file_util.isSupportedFormat(element) && element.isArchived != true)
|
file_util.isSupportedFormat(element) && element.isArchived != true)
|
||||||
.sorted(compareFileDateTimeDescending);
|
.sorted(compareFileDateTimeDescending);
|
||||||
|
|
||||||
DateTime? currentDate;
|
|
||||||
final isMonthOnly = _thumbZoomLevel < 0;
|
final isMonthOnly = _thumbZoomLevel < 0;
|
||||||
|
final dateHelper = PhotoListDateGroupHelper(
|
||||||
|
isMonthOnly: isMonthOnly,
|
||||||
|
);
|
||||||
itemStreamListItems = () sync* {
|
itemStreamListItems = () sync* {
|
||||||
for (int i = 0; i < _backingFiles.length; ++i) {
|
for (int i = 0; i < _backingFiles.length; ++i) {
|
||||||
final f = _backingFiles[i];
|
final f = _backingFiles[i];
|
||||||
|
final date = dateHelper.onFile(f);
|
||||||
final newDate = f.bestDateTime.toLocal();
|
if (date != null) {
|
||||||
if (newDate.year != currentDate?.year ||
|
yield _DateListItem(date: date, isMonthOnly: isMonthOnly);
|
||||||
newDate.month != currentDate?.month ||
|
|
||||||
(!isMonthOnly && newDate.day != currentDate?.day)) {
|
|
||||||
yield _DateListItem(date: newDate, isMonthOnly: isMonthOnly);
|
|
||||||
currentDate = newDate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final previewUrl = api_util.getFilePreviewUrl(widget.account, f,
|
final previewUrl = api_util.getFilePreviewUrl(widget.account, f,
|
||||||
|
@ -744,30 +742,13 @@ class _DateListItem extends _ListItem {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
buildWidget(BuildContext context) {
|
buildWidget(BuildContext context) {
|
||||||
String subtitle = "";
|
return PhotoListDate(
|
||||||
if (date != null) {
|
date: date,
|
||||||
final pattern =
|
isMonthOnly: isMonthOnly,
|
||||||
isMonthOnly ? DateFormat.YEAR_MONTH : DateFormat.YEAR_MONTH_DAY;
|
|
||||||
subtitle =
|
|
||||||
DateFormat(pattern, Localizations.localeOf(context).languageCode)
|
|
||||||
.format(date!.toLocal());
|
|
||||||
}
|
|
||||||
return Align(
|
|
||||||
alignment: AlignmentDirectional.centerStart,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
|
||||||
child: Text(
|
|
||||||
subtitle,
|
|
||||||
style: Theme.of(context).textTheme.caption!.copyWith(
|
|
||||||
color: AppTheme.getPrimaryTextColor(context),
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final DateTime? date;
|
final DateTime date;
|
||||||
final bool isMonthOnly;
|
final bool isMonthOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
20
lib/widget/photo_list_helper.dart
Normal file
20
lib/widget/photo_list_helper.dart
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import 'package:nc_photos/entity/file.dart';
|
||||||
|
|
||||||
|
class PhotoListDateGroupHelper {
|
||||||
|
PhotoListDateGroupHelper({
|
||||||
|
required this.isMonthOnly,
|
||||||
|
});
|
||||||
|
|
||||||
|
DateTime? onFile(File file) {
|
||||||
|
final newDate = file.bestDateTime.toLocal();
|
||||||
|
if (newDate.year != _currentDate?.year ||
|
||||||
|
newDate.month != _currentDate?.month ||
|
||||||
|
(!isMonthOnly && newDate.day != _currentDate?.day)) {
|
||||||
|
_currentDate = newDate;
|
||||||
|
return newDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final bool isMonthOnly;
|
||||||
|
DateTime? _currentDate;
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
import 'package:nc_photos/account.dart';
|
import 'package:nc_photos/account.dart';
|
||||||
import 'package:nc_photos/api/api.dart';
|
import 'package:nc_photos/api/api.dart';
|
||||||
import 'package:nc_photos/app_localizations.dart';
|
import 'package:nc_photos/app_localizations.dart';
|
||||||
|
@ -192,3 +193,36 @@ class PhotoListLabelEdit extends PhotoListLabel {
|
||||||
|
|
||||||
final VoidCallback? onEditPressed;
|
final VoidCallback? onEditPressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PhotoListDate extends StatelessWidget {
|
||||||
|
const PhotoListDate({
|
||||||
|
Key? key,
|
||||||
|
required this.date,
|
||||||
|
this.isMonthOnly = false,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
build(BuildContext context) {
|
||||||
|
final pattern =
|
||||||
|
isMonthOnly ? DateFormat.YEAR_MONTH : DateFormat.YEAR_MONTH_DAY;
|
||||||
|
final subtitle =
|
||||||
|
DateFormat(pattern, Localizations.localeOf(context).languageCode)
|
||||||
|
.format(date.toLocal());
|
||||||
|
return Align(
|
||||||
|
alignment: AlignmentDirectional.centerStart,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
child: Text(
|
||||||
|
subtitle,
|
||||||
|
style: Theme.of(context).textTheme.caption!.copyWith(
|
||||||
|
color: AppTheme.getPrimaryTextColor(context),
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final DateTime date;
|
||||||
|
final bool isMonthOnly;
|
||||||
|
}
|
||||||
|
|
|
@ -99,6 +99,12 @@ class _SettingsState extends State<Settings> {
|
||||||
description: L10n.global().settingsViewerDescription,
|
description: L10n.global().settingsViewerDescription,
|
||||||
builder: () => _ViewerSettings(),
|
builder: () => _ViewerSettings(),
|
||||||
),
|
),
|
||||||
|
_buildSubSettings(
|
||||||
|
context,
|
||||||
|
label: L10n.global().settingsAlbumTitle,
|
||||||
|
description: L10n.global().settingsAlbumDescription,
|
||||||
|
builder: () => _AlbumSettings(),
|
||||||
|
),
|
||||||
_buildSubSettings(
|
_buildSubSettings(
|
||||||
context,
|
context,
|
||||||
label: L10n.global().settingsThemeTitle,
|
label: L10n.global().settingsThemeTitle,
|
||||||
|
@ -512,6 +518,75 @@ class _ViewerSettingsState extends State<_ViewerSettings> {
|
||||||
static final _log = Logger("widget.settings._ViewerSettingsState");
|
static final _log = Logger("widget.settings._ViewerSettingsState");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _AlbumSettings extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
createState() => _AlbumSettingsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AlbumSettingsState extends State<_AlbumSettings> {
|
||||||
|
@override
|
||||||
|
initState() {
|
||||||
|
super.initState();
|
||||||
|
_isBrowserShowDate = Pref.inst().isAlbumBrowserShowDateOr();
|
||||||
|
}
|
||||||
|
|
||||||
|
@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().settingsAlbumPageTitle),
|
||||||
|
),
|
||||||
|
SliverList(
|
||||||
|
delegate: SliverChildListDelegate(
|
||||||
|
[
|
||||||
|
SwitchListTile(
|
||||||
|
title: Text(L10n.global().settingsShowDateInAlbumTitle),
|
||||||
|
subtitle:
|
||||||
|
Text(L10n.global().settingsShowDateInAlbumDescription),
|
||||||
|
value: _isBrowserShowDate,
|
||||||
|
onChanged: (value) => _onBrowserShowDateChanged(value),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onBrowserShowDateChanged(bool value) async {
|
||||||
|
final oldValue = _isBrowserShowDate;
|
||||||
|
setState(() {
|
||||||
|
_isBrowserShowDate = value;
|
||||||
|
});
|
||||||
|
if (!await Pref.inst().setAlbumBrowserShowDate(value)) {
|
||||||
|
_log.severe("[_onBrowserShowDateChanged] Failed writing pref");
|
||||||
|
SnackBarManager().showSnackBar(SnackBar(
|
||||||
|
content: Text(L10n.global().writePreferenceFailureNotification),
|
||||||
|
duration: k.snackBarDurationNormal,
|
||||||
|
));
|
||||||
|
setState(() {
|
||||||
|
_isBrowserShowDate = oldValue;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
late bool _isBrowserShowDate;
|
||||||
|
|
||||||
|
static final _log = Logger("widget.settings._AlbumSettingsState");
|
||||||
|
}
|
||||||
|
|
||||||
class _ThemeSettings extends StatefulWidget {
|
class _ThemeSettings extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
createState() => _ThemeSettingsState();
|
createState() => _ThemeSettingsState();
|
||||||
|
|
Loading…
Add table
Reference in a new issue