nc-photos/app/lib/widget/settings.dart
2024-08-06 01:23:29 +08:00

260 lines
9.4 KiB
Dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:logging/logging.dart';
import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/controller/pref_controller.dart';
import 'package:nc_photos/debug_util.dart';
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/language_util.dart' as language_util;
import 'package:nc_photos/mobile/platform.dart'
if (dart.library.html) 'package:nc_photos/web/platform.dart' as platform;
import 'package:nc_photos/platform/features.dart' as features;
import 'package:nc_photos/platform/notification.dart';
import 'package:nc_photos/stream_util.dart';
import 'package:nc_photos/url_launcher_util.dart';
import 'package:nc_photos/widget/list_tile_center_leading.dart';
import 'package:nc_photos/widget/settings/collection_settings.dart';
import 'package:nc_photos/widget/settings/developer_settings.dart';
import 'package:nc_photos/widget/settings/enhancement_settings.dart';
import 'package:nc_photos/widget/settings/expert_settings.dart';
import 'package:nc_photos/widget/settings/language_settings.dart';
import 'package:nc_photos/widget/settings/metadata_settings.dart';
import 'package:nc_photos/widget/settings/misc_settings.dart';
import 'package:nc_photos/widget/settings/photos_settings.dart';
import 'package:nc_photos/widget/settings/settings_list_caption.dart';
import 'package:nc_photos/widget/settings/theme_settings.dart';
import 'package:nc_photos/widget/settings/viewer_settings.dart';
import 'package:np_codegen/np_codegen.dart';
part 'settings.g.dart';
class Settings extends StatefulWidget {
static const routeName = "/settings";
static Route buildRoute() => MaterialPageRoute(
builder: (_) => const Settings(),
);
const Settings({super.key});
@override
State<StatefulWidget> createState() => _SettingsState();
}
@npLog
class _SettingsState extends State<Settings> {
@override
Widget build(BuildContext context) {
final translator = L10n.global().translator;
return Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar(
pinned: true,
title: Text(L10n.global().settingsWidgetTitle),
),
SliverList(
delegate: SliverChildListDelegate(
[
ValueStreamBuilder<language_util.AppLanguage>(
stream: context.read<PrefController>().language,
builder: (context, snapshot) => ListTile(
leading: const ListTileCenterLeading(
child: Icon(Icons.translate_outlined),
),
title: Text(L10n.global().settingsLanguageTitle),
subtitle: Text(snapshot.requireData.nativeName),
onTap: () {
Navigator.of(context)
.pushNamed(LanguageSettings.routeName);
},
),
),
_SubPageItem(
leading: const Icon(Icons.palette_outlined),
label: L10n.global().settingsThemeTitle,
description: L10n.global().settingsThemeDescription,
pageBuilder: () => const ThemeSettings(),
),
_SubPageItem(
leading: const Icon(Icons.local_offer_outlined),
label: L10n.global().settingsMetadataTitle,
pageBuilder: () => const MetadataSettings(),
),
_SubPageItem(
leading: const Icon(Icons.image_outlined),
label: L10n.global().photosTabLabel,
description: L10n.global().settingsPhotosDescription,
pageBuilder: () => const PhotosSettings(),
),
_SubPageItem(
leading: const Icon(Icons.grid_view_outlined),
label: L10n.global().collectionsTooltip,
pageBuilder: () => const CollectionSettings(),
),
_SubPageItem(
leading: const Icon(Icons.view_carousel_outlined),
label: L10n.global().settingsViewerTitle,
description: L10n.global().settingsViewerDescription,
pageBuilder: () => const ViewerSettings(),
),
if (features.isSupportEnhancement)
_SubPageItem(
leading: const Icon(Icons.auto_fix_high_outlined),
label: L10n.global().settingsImageEditTitle,
description: L10n.global().settingsImageEditDescription,
pageBuilder: () => const EnhancementSettings(),
),
_SubPageItem(
leading: const Icon(Icons.emoji_symbols_outlined),
label: L10n.global().settingsMiscellaneousTitle,
pageBuilder: () => const MiscSettings(),
),
_SubPageItem(
leading: const Icon(Icons.warning_amber),
label: L10n.global().settingsExpertTitle,
pageBuilder: () => const ExpertSettings(),
),
if (_isShowDevSettings)
_SubPageItem(
leading: const Icon(Icons.code_outlined),
label: "Developer options",
pageBuilder: () => const DeveloperSettings(),
),
SettingsListCaption(
label: L10n.global().settingsAboutSectionTitle,
),
ListTile(
title: Text(L10n.global().settingsVersionTitle),
subtitle: const Text(k.versionStr),
onTap: () {
if (!_isShowDevSettings && --_devSettingsUnlockCount <= 0) {
setState(() {
_isShowDevSettings = true;
});
}
},
),
ListTile(
title: Text(L10n.global().settingsSourceCodeTitle),
onTap: () {
launch(_sourceRepo);
},
),
ListTile(
title: Text(L10n.global().settingsBugReportTitle),
onTap: () {
launch(_bugReportUrl);
},
),
SwitchListTile(
title: Text(L10n.global().settingsCaptureLogsTitle),
subtitle: Text(L10n.global().settingsCaptureLogsDescription),
value: LogCapturer().isEnable,
onChanged: (value) => _onCaptureLogChanged(context, value),
),
if (translator.isNotEmpty)
ListTile(
title: Text(L10n.global().settingsTranslatorTitle),
subtitle: Text(translator),
onTap: () {
launch(_translationUrl);
},
)
else
ListTile(
title: const Text("Improve translation"),
subtitle: const Text("Help translating to your language"),
onTap: () {
launch(_translationUrl);
},
),
],
),
),
],
),
);
}
Future<void> _onCaptureLogChanged(BuildContext context, bool value) async {
if (value) {
final result = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
content: Text(L10n.global().captureLogDetails),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: Text(L10n.global().enableButtonLabel),
),
],
),
);
if (result == true) {
setState(() {
LogCapturer().start();
});
}
} else {
if (LogCapturer().isEnable) {
setState(() {
LogCapturer().stop().then((result) {
_onLogSaveSuccessful(result);
});
});
}
}
}
Future<void> _onLogSaveSuccessful(dynamic result) async {
final nm = platform.NotificationManager();
try {
await nm.notify(LogSaveSuccessfulNotification(result));
} catch (e, stacktrace) {
_log.shout("[_onLogSaveSuccessful] Failed showing platform notification",
e, stacktrace);
}
}
var _devSettingsUnlockCount = 3;
var _isShowDevSettings = false;
static const String _sourceRepo = "https://bit.ly/3LQerBv";
static const String _bugReportUrl = "https://bit.ly/3NANrr7";
static const String _translationUrl = "https://bit.ly/3NwmdSw";
}
class _SubPageItem extends StatelessWidget {
const _SubPageItem({
this.leading,
required this.label,
this.description,
required this.pageBuilder,
});
@override
Widget build(BuildContext context) {
return ListTile(
leading: leading == null ? null : ListTileCenterLeading(child: leading!),
title: Text(label),
subtitle: description == null ? null : Text(description!),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => pageBuilder(),
),
);
},
);
}
final Widget? leading;
final String label;
final String? description;
final Widget Function() pageBuilder;
}