diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 144127ab..9e63133a 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -313,15 +313,22 @@ "@settingsExifSupportTrueSubtitle": { "description": "Subtitle of the EXIF support setting when the value is true. The goal is to warn user about the possible side effects of enabling this setting" }, - "settingsViewerSectionTitle": "Photo viewer", - "@settingsViewerSectionTitle": { - "description": "Settings for the photo viewer" + "settingsViewerTitle": "Viewer", + "settingsViewerDescription": "Customize the image/video viewer", + "settingsViewerPageTitle": "Viewer settings", + "@settingsViewerPageTitle": { + "description": "Dedicated page for viewer settings" }, "settingsScreenBrightnessTitle": "Screen brightness", "settingsScreenBrightnessDescription": "Override system brightness level", "settingsForceRotationTitle": "Ignore rotation lock", - "settingsForceRotationDescription": "Rotate the screen even if auto rotation is disabled", - "settingsThemeSectionTitle": "Theme", + "settingsForceRotationDescription": "Rotate the screen even when auto rotation is disabled", + "settingsThemeTitle": "Theme", + "settingsThemeDescription": "Customize the appearance of the app", + "settingsThemePageTitle": "Theme settings", + "@settingsThemePageTitle": { + "description": "Dedicated page for theme settings" + }, "settingsFollowSystemThemeTitle": "Follow system theme", "@settingsFollowSystemThemeTitle": { "description": "Respect the system dark mode settings introduced on Android 10" diff --git a/lib/l10n/untranslated-messages.txt b/lib/l10n/untranslated-messages.txt index 407a64e8..d077e2c0 100644 --- a/lib/l10n/untranslated-messages.txt +++ b/lib/l10n/untranslated-messages.txt @@ -1,12 +1,16 @@ { "el": [ "collectionsTooltip", - "settingsViewerSectionTitle", + "settingsViewerTitle", + "settingsViewerDescription", + "settingsViewerPageTitle", "settingsScreenBrightnessTitle", "settingsScreenBrightnessDescription", "settingsForceRotationTitle", "settingsForceRotationDescription", - "settingsThemeSectionTitle", + "settingsThemeTitle", + "settingsThemeDescription", + "settingsThemePageTitle", "settingsFollowSystemThemeTitle", "settingsUseBlackInDarkThemeTitle", "settingsUseBlackInDarkThemeTrueDescription", @@ -45,7 +49,12 @@ "es": [ "collectionsTooltip", - "settingsThemeSectionTitle", + "settingsViewerTitle", + "settingsViewerDescription", + "settingsViewerPageTitle", + "settingsThemeTitle", + "settingsThemeDescription", + "settingsThemePageTitle", "settingsFollowSystemThemeTitle", "settingsUseBlackInDarkThemeTitle", "settingsUseBlackInDarkThemeTrueDescription", @@ -58,12 +67,16 @@ "fr": [ "collectionsTooltip", - "settingsViewerSectionTitle", + "settingsViewerTitle", + "settingsViewerDescription", + "settingsViewerPageTitle", "settingsScreenBrightnessTitle", "settingsScreenBrightnessDescription", "settingsForceRotationTitle", "settingsForceRotationDescription", - "settingsThemeSectionTitle", + "settingsThemeTitle", + "settingsThemeDescription", + "settingsThemePageTitle", "settingsFollowSystemThemeTitle", "settingsUseBlackInDarkThemeTitle", "settingsUseBlackInDarkThemeTrueDescription", @@ -82,12 +95,16 @@ "ru": [ "collectionsTooltip", - "settingsViewerSectionTitle", + "settingsViewerTitle", + "settingsViewerDescription", + "settingsViewerPageTitle", "settingsScreenBrightnessTitle", "settingsScreenBrightnessDescription", "settingsForceRotationTitle", "settingsForceRotationDescription", - "settingsThemeSectionTitle", + "settingsThemeTitle", + "settingsThemeDescription", + "settingsThemePageTitle", "settingsFollowSystemThemeTitle", "settingsUseBlackInDarkThemeTitle", "settingsUseBlackInDarkThemeTrueDescription", diff --git a/lib/widget/settings.dart b/lib/widget/settings.dart index 0311ce53..5b6b0b48 100644 --- a/lib/widget/settings.dart +++ b/lib/widget/settings.dart @@ -1,5 +1,4 @@ import 'package:event_bus/event_bus.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:kiwi/kiwi.dart'; import 'package:logging/logging.dart'; @@ -54,14 +53,10 @@ class _SettingsState extends State { initState() { super.initState(); _isEnableExif = Pref.inst().isEnableExifOr(); - _screenBrightness = Pref.inst().getViewerScreenBrightnessOr(-1); - _isForceRotation = Pref.inst().isViewerForceRotationOr(false); - _isFollowSystemTheme = Pref.inst().isFollowSystemThemeOr(false); - _isUseBlackInDarkTheme = Pref.inst().isUseBlackInDarkThemeOr(false); } @override - build(context) { + build(BuildContext context) { return AppTheme( child: Scaffold( body: Builder( @@ -95,41 +90,18 @@ class _SettingsState extends State { value: _isEnableExif, onChanged: (value) => _onExifSupportChanged(context, value), ), - if (platform_k.isMobile) ...[ - _buildCaption( - context, L10n.global().settingsViewerSectionTitle), - SwitchListTile( - title: Text(L10n.global().settingsScreenBrightnessTitle), - subtitle: - Text(L10n.global().settingsScreenBrightnessDescription), - value: _screenBrightness >= 0, - onChanged: (value) => - _onScreenBrightnessChanged(context, value), + if (platform_k.isMobile) + _buildSubSettings( + context, + label: L10n.global().settingsViewerTitle, + description: L10n.global().settingsViewerDescription, + builder: () => _ViewerSettings(), ), - SwitchListTile( - title: Text(L10n.global().settingsForceRotationTitle), - subtitle: - Text(L10n.global().settingsForceRotationDescription), - value: _isForceRotation, - onChanged: (value) => _onForceRotationChanged(value), - ), - ], - _buildCaption(context, L10n.global().settingsThemeSectionTitle), - if (platform_k.isAndroid && AndroidInfo().sdkInt >= 29) - SwitchListTile( - title: Text(L10n.global().settingsFollowSystemThemeTitle), - value: _isFollowSystemTheme, - onChanged: (value) => _onFollowSystemThemeChanged(value), - ), - SwitchListTile( - title: Text(L10n.global().settingsUseBlackInDarkThemeTitle), - subtitle: Text(_isUseBlackInDarkTheme - ? L10n.global().settingsUseBlackInDarkThemeTrueDescription - : L10n.global() - .settingsUseBlackInDarkThemeFalseDescription), - value: _isUseBlackInDarkTheme, - onChanged: (value) => - _onUseBlackInDarkThemeChanged(context, value), + _buildSubSettings( + context, + label: L10n.global().settingsThemeTitle, + description: L10n.global().settingsThemeDescription, + builder: () => _ThemeSettings(), ), _buildCaption(context, L10n.global().settingsAboutSectionTitle), ListTile( @@ -139,9 +111,9 @@ class _SettingsState extends State { ), ListTile( title: Text(L10n.global().settingsSourceCodeTitle), - subtitle: Text(_sourceRepo), - onTap: () async { - await launch(_sourceRepo); + subtitle: const Text(_sourceRepo), + onTap: () { + launch(_sourceRepo); }, ), ListTile( @@ -160,8 +132,8 @@ class _SettingsState extends State { ) else ListTile( - title: Text("Improve translation"), - subtitle: Text("Help translating to your language"), + title: const Text("Improve translation"), + subtitle: const Text("Help translating to your language"), onTap: () { launch(_translationUrl); }, @@ -173,6 +145,29 @@ class _SettingsState extends State { ); } + Widget _buildSubSettings( + BuildContext context, { + required String label, + String? description, + required Widget Function() builder, + }) { + return ListTile( + title: Text(label), + subtitle: description == null ? null : Text(description), + trailing: Icon( + Icons.arrow_forward_ios, + color: AppTheme.getSecondaryTextColor(context), + ), + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => builder(), + ), + ); + }, + ); + } + Widget _buildCaption(BuildContext context, String label) { return Padding( padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), @@ -249,6 +244,101 @@ class _SettingsState extends State { } } + void _onVersionTap(BuildContext context) { + if (++_labUnlockCount >= 10) { + Navigator.of(context).pushNamed(LabSettings.routeName); + _labUnlockCount = 0; + } + } + + Future _setExifSupport(bool value) async { + final oldValue = _isEnableExif; + setState(() { + _isEnableExif = value; + }); + if (await Pref.inst().setEnableExif(value)) { + if (value) { + MetadataTaskManager().addTask(MetadataTask(widget.account)); + } + } else { + _log.severe("[_setExifSupport] Failed writing pref"); + SnackBarManager().showSnackBar(SnackBar( + content: Text(L10n.global().writePreferenceFailureNotification), + duration: k.snackBarDurationNormal, + )); + setState(() { + _isEnableExif = oldValue; + }); + } + } + + late bool _isEnableExif; + int _labUnlockCount = 0; + + static final _log = Logger("widget.settings._SettingsState"); + + static const String _sourceRepo = "https://gitlab.com/nkming2/nc-photos"; + static const String _bugReportUrl = + "https://gitlab.com/nkming2/nc-photos/-/issues"; + static const String _translationUrl = + "https://gitlab.com/nkming2/nc-photos/-/tree/master/lib/l10n"; +} + +class _ViewerSettings extends StatefulWidget { + @override + createState() => _ViewerSettingsState(); +} + +class _ViewerSettingsState extends State<_ViewerSettings> { + @override + initState() { + super.initState(); + _screenBrightness = Pref.inst().getViewerScreenBrightnessOr(-1); + _isForceRotation = Pref.inst().isViewerForceRotationOr(false); + } + + @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().settingsViewerPageTitle), + ), + SliverList( + delegate: SliverChildListDelegate( + [ + SwitchListTile( + title: Text(L10n.global().settingsScreenBrightnessTitle), + subtitle: + Text(L10n.global().settingsScreenBrightnessDescription), + value: _screenBrightness >= 0, + onChanged: (value) => + _onScreenBrightnessChanged(context, value), + ), + SwitchListTile( + title: Text(L10n.global().settingsForceRotationTitle), + subtitle: Text(L10n.global().settingsForceRotationDescription), + value: _isForceRotation, + onChanged: (value) => _onForceRotationChanged(value), + ), + ], + ), + ), + ], + ); + } + void _onScreenBrightnessChanged(BuildContext context, bool value) async { if (value) { var brightness = 0.5; @@ -320,6 +410,103 @@ class _SettingsState extends State { void _onForceRotationChanged(bool value) => _setForceRotation(value); + Future _setScreenBrightness(int value) async { + final oldValue = _screenBrightness; + setState(() { + _screenBrightness = value; + }); + if (!await Pref.inst().setViewerScreenBrightness(value)) { + _log.severe("[_setScreenBrightness] Failed writing pref"); + SnackBarManager().showSnackBar(SnackBar( + content: Text(L10n.global().writePreferenceFailureNotification), + duration: k.snackBarDurationNormal, + )); + setState(() { + _screenBrightness = oldValue; + }); + } + } + + Future _setForceRotation(bool value) async { + final oldValue = _isForceRotation; + setState(() { + _isForceRotation = value; + }); + if (!await Pref.inst().setViewerForceRotation(value)) { + _log.severe("[_setForceRotation] Failed writing pref"); + SnackBarManager().showSnackBar(SnackBar( + content: Text(L10n.global().writePreferenceFailureNotification), + duration: k.snackBarDurationNormal, + )); + setState(() { + _isForceRotation = oldValue; + }); + } + } + + late int _screenBrightness; + late bool _isForceRotation; + + static final _log = Logger("widget.settings._ViewerSettingsState"); +} + +class _ThemeSettings extends StatefulWidget { + @override + createState() => _ThemeSettingsState(); +} + +class _ThemeSettingsState extends State<_ThemeSettings> { + @override + initState() { + super.initState(); + _isFollowSystemTheme = Pref.inst().isFollowSystemThemeOr(false); + _isUseBlackInDarkTheme = Pref.inst().isUseBlackInDarkThemeOr(false); + } + + @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().settingsThemePageTitle), + ), + SliverList( + delegate: SliverChildListDelegate( + [ + if (platform_k.isAndroid && AndroidInfo().sdkInt >= 29) + SwitchListTile( + title: Text(L10n.global().settingsFollowSystemThemeTitle), + value: _isFollowSystemTheme, + onChanged: (value) => _onFollowSystemThemeChanged(value), + ), + SwitchListTile( + title: Text(L10n.global().settingsUseBlackInDarkThemeTitle), + subtitle: Text(_isUseBlackInDarkTheme + ? L10n.global().settingsUseBlackInDarkThemeTrueDescription + : L10n.global() + .settingsUseBlackInDarkThemeFalseDescription), + value: _isUseBlackInDarkTheme, + onChanged: (value) => + _onUseBlackInDarkThemeChanged(context, value), + ), + ], + ), + ), + ], + ); + } + void _onFollowSystemThemeChanged(bool value) async { final oldValue = _isFollowSystemTheme; setState(() { @@ -360,86 +547,8 @@ class _SettingsState extends State { } } - void _onVersionTap(BuildContext context) { - if (++_labUnlockCount >= 10) { - Navigator.of(context).pushNamed(LabSettings.routeName); - _labUnlockCount = 0; - } - } - - void _setExifSupport(bool value) { - final oldValue = _isEnableExif; - setState(() { - _isEnableExif = value; - }); - Pref.inst().setEnableExif(value).then((result) { - if (result) { - if (value) { - MetadataTaskManager().addTask(MetadataTask(widget.account)); - } - } else { - _log.severe("[_setExifSupport] Failed writing pref"); - SnackBarManager().showSnackBar(SnackBar( - content: Text(L10n.global().writePreferenceFailureNotification), - duration: k.snackBarDurationNormal, - )); - setState(() { - _isEnableExif = oldValue; - }); - } - }); - } - - void _setScreenBrightness(int value) { - final oldValue = _screenBrightness; - setState(() { - _screenBrightness = value; - }); - Pref.inst().setViewerScreenBrightness(value).then((result) { - if (!result) { - _log.severe("[_setScreenBrightness] Failed writing pref"); - SnackBarManager().showSnackBar(SnackBar( - content: Text(L10n.global().writePreferenceFailureNotification), - duration: k.snackBarDurationNormal, - )); - setState(() { - _screenBrightness = oldValue; - }); - } - }); - } - - void _setForceRotation(bool value) { - final oldValue = _isForceRotation; - setState(() { - _isForceRotation = value; - }); - Pref.inst().setViewerForceRotation(value).then((result) { - if (!result) { - _log.severe("[_setForceRotation] Failed writing pref"); - SnackBarManager().showSnackBar(SnackBar( - content: Text(L10n.global().writePreferenceFailureNotification), - duration: k.snackBarDurationNormal, - )); - setState(() { - _isForceRotation = oldValue; - }); - } - }); - } - - static const String _sourceRepo = "https://gitlab.com/nkming2/nc-photos"; - static const String _bugReportUrl = - "https://gitlab.com/nkming2/nc-photos/-/issues"; - static const String _translationUrl = - "https://gitlab.com/nkming2/nc-photos/-/tree/master/lib/l10n"; - - late bool _isEnableExif; - late int _screenBrightness; - late bool _isForceRotation; late bool _isFollowSystemTheme; late bool _isUseBlackInDarkTheme; - int _labUnlockCount = 0; - static final _log = Logger("widget.settings._SettingsState"); + static final _log = Logger("widget.settings._ThemeSettingsState"); }