Merge pull request #552 from ente-io/redesign-settings-new
Redesign + use components for settings
This commit is contained in:
commit
e2fb00af59
18 changed files with 850 additions and 634 deletions
|
@ -341,10 +341,6 @@ extension CustomColorScheme on ColorScheme {
|
|||
? const Color.fromRGBO(180, 180, 180, 1)
|
||||
: const Color.fromRGBO(100, 100, 100, 1);
|
||||
|
||||
Color get themeSwitchInactiveIconColor => brightness == Brightness.light
|
||||
? const Color.fromRGBO(0, 0, 0, 1).withOpacity(0.5)
|
||||
: const Color.fromRGBO(255, 255, 255, 1).withOpacity(0.5);
|
||||
|
||||
Color get searchResultsColor => brightness == Brightness.light
|
||||
? const Color.fromRGBO(245, 245, 245, 1.0)
|
||||
: const Color.fromRGBO(30, 30, 30, 1.0);
|
||||
|
|
57
lib/ui/components/captioned_text_widget.dart
Normal file
57
lib/ui/components/captioned_text_widget.dart
Normal file
|
@ -0,0 +1,57 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:photos/ente_theme_data.dart';
|
||||
|
||||
class CaptionedTextWidget extends StatelessWidget {
|
||||
final String title;
|
||||
final String? subTitle;
|
||||
final TextStyle? textStyle;
|
||||
final bool makeTextBold;
|
||||
final Color? textColor;
|
||||
const CaptionedTextWidget({
|
||||
required this.title,
|
||||
this.subTitle,
|
||||
this.textStyle,
|
||||
this.makeTextBold = false,
|
||||
this.textColor,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final enteColorScheme = Theme.of(context).colorScheme.enteTheme.colorScheme;
|
||||
final enteTextTheme = Theme.of(context).colorScheme.enteTheme.textTheme;
|
||||
|
||||
return Flexible(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 2),
|
||||
child: Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
style: textStyle ??
|
||||
(makeTextBold
|
||||
? enteTextTheme.bodyBold.copyWith(color: textColor)
|
||||
: enteTextTheme.body.copyWith(color: textColor)),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: title,
|
||||
),
|
||||
subTitle != null
|
||||
? TextSpan(
|
||||
text: ' \u2022 $subTitle',
|
||||
style: enteTextTheme.small.copyWith(
|
||||
color: enteColorScheme.textMuted,
|
||||
),
|
||||
)
|
||||
: const TextSpan(text: ''),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
60
lib/ui/components/expandable_menu_item_widget.dart
Normal file
60
lib/ui/components/expandable_menu_item_widget.dart
Normal file
|
@ -0,0 +1,60 @@
|
|||
import 'package:expandable/expandable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:photos/ente_theme_data.dart';
|
||||
import 'package:photos/ui/components/captioned_text_widget.dart';
|
||||
import 'package:photos/ui/components/menu_item_widget.dart';
|
||||
import 'package:photos/ui/settings/common_settings.dart';
|
||||
|
||||
class ExpandableMenuItemWidget extends StatefulWidget {
|
||||
final String title;
|
||||
final Widget selectionOptionsWidget;
|
||||
final IconData leadingIcon;
|
||||
const ExpandableMenuItemWidget({
|
||||
required this.title,
|
||||
required this.selectionOptionsWidget,
|
||||
required this.leadingIcon,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<ExpandableMenuItemWidget> createState() =>
|
||||
_ExpandableMenuItemWidgetState();
|
||||
}
|
||||
|
||||
class _ExpandableMenuItemWidgetState extends State<ExpandableMenuItemWidget> {
|
||||
final expandableController = ExpandableController(initialExpanded: false);
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
expandableController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final enteColorScheme = Theme.of(context).colorScheme.enteTheme.colorScheme;
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: enteColorScheme.backgroundElevated2,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: ExpandablePanel(
|
||||
header: MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: widget.title,
|
||||
makeTextBold: true,
|
||||
),
|
||||
isHeaderOfExpansion: true,
|
||||
leadingIcon: widget.leadingIcon,
|
||||
trailingIcon: Icons.expand_more,
|
||||
menuItemColor: enteColorScheme.fillFaint,
|
||||
expandableController: expandableController,
|
||||
),
|
||||
collapsed: const SizedBox.shrink(),
|
||||
expanded: widget.selectionOptionsWidget,
|
||||
theme: getExpandableTheme(context),
|
||||
controller: expandableController,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
123
lib/ui/components/menu_item_widget.dart
Normal file
123
lib/ui/components/menu_item_widget.dart
Normal file
|
@ -0,0 +1,123 @@
|
|||
import 'package:expandable/expandable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:photos/ente_theme_data.dart';
|
||||
|
||||
class MenuItemWidget extends StatefulWidget {
|
||||
final Widget captionedTextWidget;
|
||||
final bool isHeaderOfExpansion;
|
||||
// leading icon can be passed without specifing size of icon, this component sets size to 20x20 irrespective of passed icon's size
|
||||
final IconData? leadingIcon;
|
||||
final Color? leadingIconColor;
|
||||
// trailing icon can be passed without size as default size set by flutter is what this component expects
|
||||
final IconData? trailingIcon;
|
||||
final Widget? trailingSwitch;
|
||||
final bool trailingIconIsMuted;
|
||||
final VoidCallback? onTap;
|
||||
final VoidCallback? onDoubleTap;
|
||||
final Color? menuItemColor;
|
||||
final bool alignCaptionedTextToLeft;
|
||||
final double borderRadius;
|
||||
final ExpandableController? expandableController;
|
||||
const MenuItemWidget({
|
||||
required this.captionedTextWidget,
|
||||
this.isHeaderOfExpansion = false,
|
||||
this.leadingIcon,
|
||||
this.leadingIconColor,
|
||||
this.trailingIcon,
|
||||
this.trailingSwitch,
|
||||
this.trailingIconIsMuted = false,
|
||||
this.onTap,
|
||||
this.onDoubleTap,
|
||||
this.menuItemColor,
|
||||
this.alignCaptionedTextToLeft = false,
|
||||
this.borderRadius = 4.0,
|
||||
this.expandableController,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<MenuItemWidget> createState() => _MenuItemWidgetState();
|
||||
}
|
||||
|
||||
class _MenuItemWidgetState extends State<MenuItemWidget> {
|
||||
@override
|
||||
void initState() {
|
||||
if (widget.expandableController != null) {
|
||||
widget.expandableController!.addListener(() {
|
||||
setState(() {});
|
||||
});
|
||||
}
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
if (widget.expandableController != null) {
|
||||
widget.expandableController!.dispose();
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return widget.isHeaderOfExpansion
|
||||
? menuItemWidget(context)
|
||||
: GestureDetector(
|
||||
onTap: widget.onTap,
|
||||
onDoubleTap: widget.onDoubleTap,
|
||||
child: menuItemWidget(context),
|
||||
);
|
||||
}
|
||||
|
||||
Widget menuItemWidget(BuildContext context) {
|
||||
final enteColorScheme = Theme.of(context).colorScheme.enteTheme.colorScheme;
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(widget.borderRadius),
|
||||
color: widget.menuItemColor,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
widget.alignCaptionedTextToLeft && widget.leadingIcon == null
|
||||
? const SizedBox.shrink()
|
||||
: Padding(
|
||||
padding: const EdgeInsets.only(right: 10),
|
||||
child: SizedBox(
|
||||
height: 20,
|
||||
width: 20,
|
||||
child: widget.leadingIcon == null
|
||||
? const SizedBox.shrink()
|
||||
: FittedBox(
|
||||
fit: BoxFit.contain,
|
||||
child: Icon(
|
||||
widget.leadingIcon,
|
||||
color: widget.leadingIconColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
widget.captionedTextWidget,
|
||||
widget.expandableController != null
|
||||
? _isExpanded()
|
||||
? const SizedBox.shrink()
|
||||
: Icon(widget.trailingIcon)
|
||||
: widget.trailingIcon != null
|
||||
? Icon(
|
||||
widget.trailingIcon,
|
||||
color: widget.trailingIconIsMuted
|
||||
? enteColorScheme.strokeMuted
|
||||
: null,
|
||||
)
|
||||
: widget.trailingSwitch ?? const SizedBox.shrink(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
bool _isExpanded() {
|
||||
return widget.expandableController!.value;
|
||||
}
|
||||
}
|
38
lib/ui/components/toggle_switch_widget.dart
Normal file
38
lib/ui/components/toggle_switch_widget.dart
Normal file
|
@ -0,0 +1,38 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:photos/ente_theme_data.dart';
|
||||
|
||||
typedef OnChangedCallBack = void Function(bool);
|
||||
|
||||
class ToggleSwitchWidget extends StatefulWidget {
|
||||
final bool value;
|
||||
final OnChangedCallBack onChanged;
|
||||
const ToggleSwitchWidget(
|
||||
{required this.value, required this.onChanged, Key? key})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<ToggleSwitchWidget> createState() => _ToggleSwitchWidgetState();
|
||||
}
|
||||
|
||||
class _ToggleSwitchWidgetState extends State<ToggleSwitchWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final enteColorScheme = Theme.of(context).colorScheme.enteTheme.colorScheme;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: SizedBox(
|
||||
height: 30,
|
||||
child: FittedBox(
|
||||
fit: BoxFit.contain,
|
||||
child: Switch.adaptive(
|
||||
activeColor: enteColorScheme.primary400,
|
||||
inactiveTrackColor: enteColorScheme.fillMuted,
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
value: widget.value,
|
||||
onChanged: widget.onChanged,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
127
lib/ui/settings/about_section_widget.dart
Normal file
127
lib/ui/settings/about_section_widget.dart
Normal file
|
@ -0,0 +1,127 @@
|
|||
// @dart=2.9
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:photos/services/update_service.dart';
|
||||
import 'package:photos/ui/common/web_page.dart';
|
||||
import 'package:photos/ui/components/captioned_text_widget.dart';
|
||||
import 'package:photos/ui/components/expandable_menu_item_widget.dart';
|
||||
import 'package:photos/ui/components/menu_item_widget.dart';
|
||||
import 'package:photos/ui/settings/app_update_dialog.dart';
|
||||
import 'package:photos/ui/settings/common_settings.dart';
|
||||
import 'package:photos/utils/dialog_util.dart';
|
||||
import 'package:photos/utils/toast_util.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class AboutSectionWidget extends StatelessWidget {
|
||||
const AboutSectionWidget({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ExpandableMenuItemWidget(
|
||||
title: "About",
|
||||
selectionOptionsWidget: _getSectionOptions(context),
|
||||
leadingIcon: Icons.info_outline,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getSectionOptions(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
sectionOptionSpacing,
|
||||
const AboutMenuItemWidget(
|
||||
title: "FAQ",
|
||||
url: "https://ente.io/faq",
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
const AboutMenuItemWidget(
|
||||
title: "Terms",
|
||||
url: "https://ente.io/terms",
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
const AboutMenuItemWidget(
|
||||
title: "Privacy",
|
||||
url: "https://ente.io/privacy",
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Source code",
|
||||
),
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
launchUrl(Uri.parse("https://github.com/ente-io/frame"));
|
||||
},
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
UpdateService.instance.isIndependent()
|
||||
? Column(
|
||||
children: [
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Check for updates",
|
||||
),
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
final dialog =
|
||||
createProgressDialog(context, "Checking...");
|
||||
await dialog.show();
|
||||
final shouldUpdate =
|
||||
await UpdateService.instance.shouldUpdate();
|
||||
await dialog.hide();
|
||||
if (shouldUpdate) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AppUpdateDialog(
|
||||
UpdateService.instance.getLatestVersionInfo(),
|
||||
);
|
||||
},
|
||||
barrierColor: Colors.black.withOpacity(0.85),
|
||||
);
|
||||
} else {
|
||||
showToast(context, "You are on the latest version");
|
||||
}
|
||||
},
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
],
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AboutMenuItemWidget extends StatelessWidget {
|
||||
final String title;
|
||||
final String url;
|
||||
final String webPageTitle;
|
||||
const AboutMenuItemWidget({
|
||||
@required this.title,
|
||||
@required this.url,
|
||||
this.webPageTitle,
|
||||
Key key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: title,
|
||||
),
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return WebPage(webPageTitle ?? title, url);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
// @dart=2.9
|
||||
|
||||
import 'package:expandable/expandable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_sodium/flutter_sodium.dart';
|
||||
import 'package:photos/services/local_authentication_service.dart';
|
||||
|
@ -8,35 +7,35 @@ import 'package:photos/services/user_service.dart';
|
|||
import 'package:photos/ui/account/change_email_dialog.dart';
|
||||
import 'package:photos/ui/account/password_entry_page.dart';
|
||||
import 'package:photos/ui/account/recovery_key_page.dart';
|
||||
import 'package:photos/ui/components/captioned_text_widget.dart';
|
||||
import 'package:photos/ui/components/expandable_menu_item_widget.dart';
|
||||
import 'package:photos/ui/components/menu_item_widget.dart';
|
||||
import 'package:photos/ui/settings/common_settings.dart';
|
||||
import 'package:photos/ui/settings/settings_section_title.dart';
|
||||
import 'package:photos/ui/settings/settings_text_item.dart';
|
||||
import 'package:photos/utils/dialog_util.dart';
|
||||
import 'package:photos/utils/navigation_util.dart';
|
||||
|
||||
class AccountSectionWidget extends StatefulWidget {
|
||||
class AccountSectionWidget extends StatelessWidget {
|
||||
const AccountSectionWidget({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
AccountSectionWidgetState createState() => AccountSectionWidgetState();
|
||||
}
|
||||
|
||||
class AccountSectionWidgetState extends State<AccountSectionWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ExpandablePanel(
|
||||
header: const SettingsSectionTitle("Account"),
|
||||
collapsed: const SizedBox.shrink(),
|
||||
expanded: _getSectionOptions(context),
|
||||
theme: getExpandableTheme(context),
|
||||
return ExpandableMenuItemWidget(
|
||||
title: "Account",
|
||||
selectionOptionsWidget: _getSectionOptions(context),
|
||||
leadingIcon: Icons.account_circle_outlined,
|
||||
);
|
||||
}
|
||||
|
||||
Column _getSectionOptions(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Recovery key",
|
||||
),
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
final hasAuthenticated = await LocalAuthenticationService.instance
|
||||
.requestLocalAuthentication(
|
||||
|
@ -46,7 +45,7 @@ class AccountSectionWidgetState extends State<AccountSectionWidget> {
|
|||
if (hasAuthenticated) {
|
||||
String recoveryKey;
|
||||
try {
|
||||
recoveryKey = await _getOrCreateRecoveryKey();
|
||||
recoveryKey = await _getOrCreateRecoveryKey(context);
|
||||
} catch (e) {
|
||||
showGenericErrorDialog(context);
|
||||
return;
|
||||
|
@ -62,14 +61,14 @@ class AccountSectionWidgetState extends State<AccountSectionWidget> {
|
|||
);
|
||||
}
|
||||
},
|
||||
child: const SettingsTextItem(
|
||||
text: "Recovery key",
|
||||
icon: Icons.navigate_next,
|
||||
),
|
||||
),
|
||||
sectionOptionDivider,
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Change email",
|
||||
),
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
final hasAuthenticated = await LocalAuthenticationService.instance
|
||||
.requestLocalAuthentication(
|
||||
|
@ -87,14 +86,14 @@ class AccountSectionWidgetState extends State<AccountSectionWidget> {
|
|||
);
|
||||
}
|
||||
},
|
||||
child: const SettingsTextItem(
|
||||
text: "Change email",
|
||||
icon: Icons.navigate_next,
|
||||
),
|
||||
),
|
||||
sectionOptionDivider,
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Change password",
|
||||
),
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
final hasAuthenticated = await LocalAuthenticationService.instance
|
||||
.requestLocalAuthentication(
|
||||
|
@ -113,16 +112,12 @@ class AccountSectionWidgetState extends State<AccountSectionWidget> {
|
|||
);
|
||||
}
|
||||
},
|
||||
child: const SettingsTextItem(
|
||||
text: "Change password",
|
||||
icon: Icons.navigate_next,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<String> _getOrCreateRecoveryKey() async {
|
||||
Future<String> _getOrCreateRecoveryKey(BuildContext context) async {
|
||||
return Sodium.bin2hex(
|
||||
await UserService.instance.getOrCreateRecoveryKey(context),
|
||||
);
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:expandable/expandable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:photos/core/configuration.dart';
|
||||
import 'package:photos/ente_theme_data.dart';
|
||||
|
@ -12,9 +11,11 @@ import 'package:photos/services/deduplication_service.dart';
|
|||
import 'package:photos/services/sync_service.dart';
|
||||
import 'package:photos/ui/backup_folder_selection_page.dart';
|
||||
import 'package:photos/ui/common/dialogs.dart';
|
||||
import 'package:photos/ui/components/captioned_text_widget.dart';
|
||||
import 'package:photos/ui/components/expandable_menu_item_widget.dart';
|
||||
import 'package:photos/ui/components/menu_item_widget.dart';
|
||||
import 'package:photos/ui/components/toggle_switch_widget.dart';
|
||||
import 'package:photos/ui/settings/common_settings.dart';
|
||||
import 'package:photos/ui/settings/settings_section_title.dart';
|
||||
import 'package:photos/ui/settings/settings_text_item.dart';
|
||||
import 'package:photos/ui/tools/deduplicate_page.dart';
|
||||
import 'package:photos/ui/tools/free_space_page.dart';
|
||||
import 'package:photos/utils/data_util.dart';
|
||||
|
@ -33,19 +34,23 @@ class BackupSectionWidget extends StatefulWidget {
|
|||
class BackupSectionWidgetState extends State<BackupSectionWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ExpandablePanel(
|
||||
header: const SettingsSectionTitle("Backup"),
|
||||
collapsed: Container(),
|
||||
expanded: _getSectionOptions(context),
|
||||
theme: getExpandableTheme(context),
|
||||
return ExpandableMenuItemWidget(
|
||||
title: "Backup",
|
||||
selectionOptionsWidget: _getSectionOptions(context),
|
||||
leadingIcon: Icons.backup_outlined,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getSectionOptions(BuildContext context) {
|
||||
final List<Widget> sectionOptions = [
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () async {
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Backed up folders",
|
||||
),
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () {
|
||||
routeToPage(
|
||||
context,
|
||||
const BackupFolderSelectionPage(
|
||||
|
@ -53,93 +58,72 @@ class BackupSectionWidgetState extends State<BackupSectionWidget> {
|
|||
),
|
||||
);
|
||||
},
|
||||
child: const SettingsTextItem(
|
||||
text: "Backed up folders",
|
||||
icon: Icons.navigate_next,
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Backup over mobile data",
|
||||
),
|
||||
trailingSwitch: ToggleSwitchWidget(
|
||||
value: Configuration.instance.shouldBackupOverMobileData(),
|
||||
onChanged: (value) async {
|
||||
Configuration.instance.setBackupOverMobileData(value);
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
sectionOptionDivider,
|
||||
SizedBox(
|
||||
height: 48,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Backup over mobile data",
|
||||
style: Theme.of(context).textTheme.subtitle1,
|
||||
),
|
||||
Switch.adaptive(
|
||||
value: Configuration.instance.shouldBackupOverMobileData(),
|
||||
onChanged: (value) async {
|
||||
Configuration.instance.setBackupOverMobileData(value);
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
sectionOptionDivider,
|
||||
SizedBox(
|
||||
height: 48,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Backup videos",
|
||||
style: Theme.of(context).textTheme.subtitle1,
|
||||
),
|
||||
Switch.adaptive(
|
||||
value: Configuration.instance.shouldBackupVideos(),
|
||||
onChanged: (value) async {
|
||||
Configuration.instance.setShouldBackupVideos(value);
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
],
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Backup videos",
|
||||
),
|
||||
trailingSwitch: ToggleSwitchWidget(
|
||||
value: Configuration.instance.shouldBackupVideos(),
|
||||
onChanged: (value) async {
|
||||
Configuration.instance.setShouldBackupVideos(value);
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
];
|
||||
if (Platform.isIOS) {
|
||||
sectionOptions.addAll([
|
||||
sectionOptionDivider,
|
||||
SizedBox(
|
||||
height: 48,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Disable auto lock",
|
||||
style: Theme.of(context).textTheme.subtitle1,
|
||||
),
|
||||
Switch.adaptive(
|
||||
value: Configuration.instance.shouldKeepDeviceAwake(),
|
||||
onChanged: (value) async {
|
||||
if (value) {
|
||||
final choice = await showChoiceDialog(
|
||||
context,
|
||||
"Disable automatic screen lock when ente is running?",
|
||||
"This will ensure faster uploads by ensuring your device does not sleep when uploads are in progress.",
|
||||
firstAction: "No",
|
||||
secondAction: "Yes",
|
||||
);
|
||||
if (choice != DialogUserChoice.secondChoice) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
await Configuration.instance.setShouldKeepDeviceAwake(value);
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
],
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Disable auto lock",
|
||||
),
|
||||
trailingSwitch: ToggleSwitchWidget(
|
||||
value: Configuration.instance.shouldKeepDeviceAwake(),
|
||||
onChanged: (value) async {
|
||||
if (value) {
|
||||
final choice = await showChoiceDialog(
|
||||
context,
|
||||
"Disable automatic screen lock when ente is running?",
|
||||
"This will ensure faster uploads by ensuring your device does not sleep when uploads are in progress.",
|
||||
firstAction: "No",
|
||||
secondAction: "Yes",
|
||||
);
|
||||
if (choice != DialogUserChoice.secondChoice) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
await Configuration.instance.setShouldKeepDeviceAwake(value);
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
]);
|
||||
}
|
||||
sectionOptions.addAll(
|
||||
[
|
||||
sectionOptionDivider,
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Free up space",
|
||||
),
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
final dialog = createProgressDialog(context, "Calculating...");
|
||||
await dialog.show();
|
||||
|
@ -160,20 +144,21 @@ class BackupSectionWidgetState extends State<BackupSectionWidget> {
|
|||
"You've no files on this device that can be deleted",
|
||||
);
|
||||
} else {
|
||||
final bool result = await routeToPage(context, FreeSpacePage(status));
|
||||
final bool result =
|
||||
await routeToPage(context, FreeSpacePage(status));
|
||||
if (result == true) {
|
||||
_showSpaceFreedDialog(status);
|
||||
}
|
||||
}
|
||||
},
|
||||
child: const SettingsTextItem(
|
||||
text: "Free up space",
|
||||
icon: Icons.navigate_next,
|
||||
),
|
||||
),
|
||||
sectionOptionDivider,
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Deduplicate files",
|
||||
),
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
final dialog = createProgressDialog(context, "Calculating...");
|
||||
await dialog.show();
|
||||
|
@ -202,11 +187,8 @@ class BackupSectionWidgetState extends State<BackupSectionWidget> {
|
|||
}
|
||||
}
|
||||
},
|
||||
child: const SettingsTextItem(
|
||||
text: "Deduplicate files",
|
||||
icon: Icons.navigate_next,
|
||||
),
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
],
|
||||
);
|
||||
return Column(
|
||||
|
|
|
@ -1,23 +1,14 @@
|
|||
// @dart=2.9
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:expandable/expandable.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
Widget sectionOptionDivider = Padding(
|
||||
padding: EdgeInsets.all(Platform.isIOS ? 4 : 2),
|
||||
);
|
||||
Widget sectionOptionSpacing = const SizedBox(height: 6);
|
||||
|
||||
ExpandableThemeData getExpandableTheme(BuildContext context) {
|
||||
return ExpandableThemeData(
|
||||
expandIcon: CupertinoIcons.chevron_down,
|
||||
collapseIcon: CupertinoIcons.chevron_up,
|
||||
iconPadding: const EdgeInsets.all(4),
|
||||
iconColor: Theme.of(context).colorScheme.onSurface,
|
||||
iconSize: 20.0,
|
||||
iconRotationAngle: -3.14 / 2,
|
||||
hasIcon: true,
|
||||
return const ExpandableThemeData(
|
||||
hasIcon: false,
|
||||
useInkWell: false,
|
||||
tapBodyToCollapse: true,
|
||||
tapBodyToExpand: true,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,60 +1,58 @@
|
|||
// @dart=2.9
|
||||
|
||||
import 'package:expandable/expandable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:photos/ente_theme_data.dart';
|
||||
import 'package:photos/services/user_service.dart';
|
||||
import 'package:photos/ui/account/delete_account_page.dart';
|
||||
import 'package:photos/ui/components/captioned_text_widget.dart';
|
||||
import 'package:photos/ui/components/expandable_menu_item_widget.dart';
|
||||
import 'package:photos/ui/components/menu_item_widget.dart';
|
||||
import 'package:photos/ui/settings/common_settings.dart';
|
||||
import 'package:photos/ui/settings/settings_section_title.dart';
|
||||
import 'package:photos/ui/settings/settings_text_item.dart';
|
||||
import 'package:photos/utils/navigation_util.dart';
|
||||
|
||||
class DangerSectionWidget extends StatefulWidget {
|
||||
class DangerSectionWidget extends StatelessWidget {
|
||||
const DangerSectionWidget({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<DangerSectionWidget> createState() => _DangerSectionWidgetState();
|
||||
}
|
||||
|
||||
class _DangerSectionWidgetState extends State<DangerSectionWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ExpandablePanel(
|
||||
header: const SettingsSectionTitle("Exit", color: Colors.red),
|
||||
collapsed: Container(),
|
||||
expanded: _getSectionOptions(context),
|
||||
theme: getExpandableTheme(context),
|
||||
return ExpandableMenuItemWidget(
|
||||
title: "Exit",
|
||||
selectionOptionsWidget: _getSectionOptions(context),
|
||||
leadingIcon: Icons.logout_outlined,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getSectionOptions(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Logout",
|
||||
),
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () {
|
||||
_onLogoutTapped();
|
||||
_onLogoutTapped(context);
|
||||
},
|
||||
child:
|
||||
const SettingsTextItem(text: "Logout", icon: Icons.navigate_next),
|
||||
),
|
||||
sectionOptionDivider,
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () async {
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Delete account",
|
||||
),
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () {
|
||||
routeToPage(context, const DeleteAccountPage());
|
||||
},
|
||||
child: const SettingsTextItem(
|
||||
text: "Delete account",
|
||||
icon: Icons.navigate_next,
|
||||
),
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onLogoutTapped() async {
|
||||
Future<void> _onLogoutTapped(BuildContext context) async {
|
||||
final AlertDialog alert = AlertDialog(
|
||||
title: const Text(
|
||||
"Logout",
|
||||
|
|
|
@ -1,65 +1,69 @@
|
|||
// @dart=2.9
|
||||
|
||||
import 'package:expandable/expandable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_sodium/flutter_sodium.dart';
|
||||
import 'package:photos/core/configuration.dart';
|
||||
import 'package:photos/services/ignored_files_service.dart';
|
||||
import 'package:photos/services/local_sync_service.dart';
|
||||
import 'package:photos/services/sync_service.dart';
|
||||
import 'package:photos/ui/components/captioned_text_widget.dart';
|
||||
import 'package:photos/ui/components/expandable_menu_item_widget.dart';
|
||||
import 'package:photos/ui/components/menu_item_widget.dart';
|
||||
import 'package:photos/ui/settings/common_settings.dart';
|
||||
import 'package:photos/ui/settings/settings_section_title.dart';
|
||||
import 'package:photos/ui/settings/settings_text_item.dart';
|
||||
import 'package:photos/utils/toast_util.dart';
|
||||
|
||||
class DebugSectionWidget extends StatelessWidget {
|
||||
const DebugSectionWidget({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ExpandablePanel(
|
||||
header: const SettingsSectionTitle("Debug"),
|
||||
collapsed: Container(),
|
||||
expanded: _getSectionOptions(context),
|
||||
theme: getExpandableTheme(context),
|
||||
return ExpandableMenuItemWidget(
|
||||
title: "Debug",
|
||||
selectionOptionsWidget: _getSectionOptions(context),
|
||||
leadingIcon: Icons.bug_report_outlined,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getSectionOptions(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Key attributes",
|
||||
),
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
_showKeyAttributesDialog(context);
|
||||
},
|
||||
child: const SettingsTextItem(
|
||||
text: "Key attributes",
|
||||
icon: Icons.navigate_next,
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Delete Local Import DB",
|
||||
),
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
await LocalSyncService.instance.resetLocalSync();
|
||||
showToast(context, "Done");
|
||||
},
|
||||
child: const SettingsTextItem(
|
||||
text: "Delete Local Import DB",
|
||||
icon: Icons.navigate_next,
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Allow auto-upload for ignored files",
|
||||
),
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
await IgnoredFilesService.instance.reset();
|
||||
SyncService.instance.sync();
|
||||
showToast(context, "Done");
|
||||
},
|
||||
child: const SettingsTextItem(
|
||||
text: "Allow auto-upload for ignored files",
|
||||
icon: Icons.navigate_next,
|
||||
),
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -89,10 +89,8 @@ class _DetailsSectionWidgetState extends State<DetailsSectionWidget> {
|
|||
}
|
||||
|
||||
Widget getContainer() {
|
||||
return SizedBox(
|
||||
width: 350,
|
||||
height: 175,
|
||||
// constraints: BoxConstraints(maxWidth: 390, maxHeight: 195),
|
||||
return ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 428, maxHeight: 175),
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
|
|
|
@ -1,125 +0,0 @@
|
|||
// @dart=2.9
|
||||
|
||||
import 'package:expandable/expandable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:photos/services/update_service.dart';
|
||||
import 'package:photos/ui/common/web_page.dart';
|
||||
import 'package:photos/ui/settings/app_update_dialog.dart';
|
||||
import 'package:photos/ui/settings/common_settings.dart';
|
||||
import 'package:photos/ui/settings/settings_section_title.dart';
|
||||
import 'package:photos/ui/settings/settings_text_item.dart';
|
||||
import 'package:photos/utils/dialog_util.dart';
|
||||
import 'package:photos/utils/toast_util.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class InfoSectionWidget extends StatelessWidget {
|
||||
const InfoSectionWidget({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ExpandablePanel(
|
||||
header: const SettingsSectionTitle("About"),
|
||||
collapsed: Container(),
|
||||
expanded: _getSectionOptions(context),
|
||||
theme: getExpandableTheme(context),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getSectionOptions(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () async {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return const WebPage("FAQ", "https://ente.io/faq");
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
child: const SettingsTextItem(text: "FAQ", icon: Icons.navigate_next),
|
||||
),
|
||||
sectionOptionDivider,
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return const WebPage("terms", "https://ente.io/terms");
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
child:
|
||||
const SettingsTextItem(text: "Terms", icon: Icons.navigate_next),
|
||||
),
|
||||
sectionOptionDivider,
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
return const WebPage("privacy", "https://ente.io/privacy");
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
child: const SettingsTextItem(
|
||||
text: "Privacy",
|
||||
icon: Icons.navigate_next,
|
||||
),
|
||||
),
|
||||
sectionOptionDivider,
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () async {
|
||||
launchUrl(Uri.parse("https://github.com/ente-io/frame"));
|
||||
},
|
||||
child: const SettingsTextItem(
|
||||
text: "Source code",
|
||||
icon: Icons.navigate_next,
|
||||
),
|
||||
),
|
||||
sectionOptionDivider,
|
||||
UpdateService.instance.isIndependent()
|
||||
? Column(
|
||||
children: [
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () async {
|
||||
final dialog =
|
||||
createProgressDialog(context, "Checking...");
|
||||
await dialog.show();
|
||||
final shouldUpdate =
|
||||
await UpdateService.instance.shouldUpdate();
|
||||
await dialog.hide();
|
||||
if (shouldUpdate) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AppUpdateDialog(
|
||||
UpdateService.instance.getLatestVersionInfo(),
|
||||
);
|
||||
},
|
||||
barrierColor: Colors.black.withOpacity(0.85),
|
||||
);
|
||||
} else {
|
||||
showToast(context, "You are on the latest version");
|
||||
}
|
||||
},
|
||||
child: const SettingsTextItem(
|
||||
text: "Check for updates",
|
||||
icon: Icons.navigate_next,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:expandable/expandable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_windowmanager/flutter_windowmanager.dart';
|
||||
import 'package:photos/core/configuration.dart';
|
||||
|
@ -14,9 +13,11 @@ import 'package:photos/services/local_authentication_service.dart';
|
|||
import 'package:photos/services/user_service.dart';
|
||||
import 'package:photos/ui/account/sessions_page.dart';
|
||||
import 'package:photos/ui/common/loading_widget.dart';
|
||||
import 'package:photos/ui/components/captioned_text_widget.dart';
|
||||
import 'package:photos/ui/components/expandable_menu_item_widget.dart';
|
||||
import 'package:photos/ui/components/menu_item_widget.dart';
|
||||
import 'package:photos/ui/components/toggle_switch_widget.dart';
|
||||
import 'package:photos/ui/settings/common_settings.dart';
|
||||
import 'package:photos/ui/settings/settings_section_title.dart';
|
||||
import 'package:photos/ui/settings/settings_text_item.dart';
|
||||
|
||||
class SecuritySectionWidget extends StatefulWidget {
|
||||
const SecuritySectionWidget({Key key}) : super(key: key);
|
||||
|
@ -49,11 +50,10 @@ class _SecuritySectionWidgetState extends State<SecuritySectionWidget> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ExpandablePanel(
|
||||
header: const SettingsSectionTitle("Security"),
|
||||
collapsed: Container(),
|
||||
expanded: _getSectionOptions(context),
|
||||
theme: getExpandableTheme(context),
|
||||
return ExpandableMenuItemWidget(
|
||||
title: "Security",
|
||||
selectionOptionsWidget: _getSectionOptions(context),
|
||||
leadingIcon: Icons.local_police_outlined,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -62,21 +62,16 @@ class _SecuritySectionWidgetState extends State<SecuritySectionWidget> {
|
|||
if (_config.hasConfiguredAccount()) {
|
||||
children.addAll(
|
||||
[
|
||||
const Padding(padding: EdgeInsets.all(2)),
|
||||
SizedBox(
|
||||
height: 48,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Two-factor",
|
||||
style: Theme.of(context).textTheme.subtitle1,
|
||||
sectionOptionSpacing,
|
||||
FutureBuilder(
|
||||
future: UserService.instance.fetchTwoFactorStatus(),
|
||||
builder: (_, snapshot) {
|
||||
return MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Two-factor",
|
||||
),
|
||||
FutureBuilder(
|
||||
future: UserService.instance.fetchTwoFactorStatus(),
|
||||
builder: (_, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return Switch.adaptive(
|
||||
trailingSwitch: snapshot.hasData
|
||||
? ToggleSwitchWidget(
|
||||
value: snapshot.data,
|
||||
onChanged: (value) async {
|
||||
final hasAuthenticated =
|
||||
|
@ -93,155 +88,136 @@ class _SecuritySectionWidgetState extends State<SecuritySectionWidget> {
|
|||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
} else if (snapshot.hasError) {
|
||||
return Icon(
|
||||
Icons.error_outline,
|
||||
color: Colors.white.withOpacity(0.8),
|
||||
);
|
||||
}
|
||||
return const EnteLoadingWidget();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: snapshot.hasError
|
||||
? const Icon(Icons.error_outline_outlined)
|
||||
: const EnteLoadingWidget(),
|
||||
);
|
||||
},
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
],
|
||||
);
|
||||
}
|
||||
children.addAll([
|
||||
sectionOptionDivider,
|
||||
SizedBox(
|
||||
height: 48,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Lockscreen",
|
||||
style: Theme.of(context).textTheme.subtitle1,
|
||||
),
|
||||
Switch.adaptive(
|
||||
value: _config.shouldShowLockScreen(),
|
||||
onChanged: (value) async {
|
||||
final hasAuthenticated = await LocalAuthenticationService
|
||||
.instance
|
||||
.requestLocalAuthForLockScreen(
|
||||
context,
|
||||
value,
|
||||
"Please authenticate to change lockscreen setting",
|
||||
"To enable lockscreen, please setup device passcode or screen lock in your system settings.",
|
||||
);
|
||||
if (hasAuthenticated) {
|
||||
setState(() {});
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Lockscreen",
|
||||
),
|
||||
trailingSwitch: ToggleSwitchWidget(
|
||||
value: _config.shouldShowLockScreen(),
|
||||
onChanged: (value) async {
|
||||
final hasAuthenticated = await LocalAuthenticationService.instance
|
||||
.requestLocalAuthForLockScreen(
|
||||
context,
|
||||
value,
|
||||
"Please authenticate to change lockscreen setting",
|
||||
"To enable lockscreen, please setup device passcode or screen lock in your system settings.",
|
||||
);
|
||||
if (hasAuthenticated) {
|
||||
setState(() {});
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
]);
|
||||
if (Platform.isAndroid) {
|
||||
children.addAll(
|
||||
[
|
||||
sectionOptionDivider,
|
||||
SizedBox(
|
||||
height: 48,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Hide from recents",
|
||||
style: Theme.of(context).textTheme.subtitle1,
|
||||
),
|
||||
Switch.adaptive(
|
||||
value: _config.shouldHideFromRecents(),
|
||||
onChanged: (value) async {
|
||||
if (value) {
|
||||
final AlertDialog alert = AlertDialog(
|
||||
title: const Text("Hide from recents?"),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: const [
|
||||
Text(
|
||||
"Hiding from the task switcher will prevent you from taking screenshots in this app.",
|
||||
style: TextStyle(
|
||||
height: 1.5,
|
||||
),
|
||||
),
|
||||
Padding(padding: EdgeInsets.all(8)),
|
||||
Text(
|
||||
"Are you sure?",
|
||||
style: TextStyle(
|
||||
height: 1.5,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text(
|
||||
"No",
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.defaultTextColor,
|
||||
),
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Hide from recents",
|
||||
),
|
||||
trailingSwitch: Switch.adaptive(
|
||||
value: _config.shouldHideFromRecents(),
|
||||
onChanged: (value) async {
|
||||
if (value) {
|
||||
final AlertDialog alert = AlertDialog(
|
||||
title: const Text("Hide from recents?"),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: const [
|
||||
Text(
|
||||
"Hiding from the task switcher will prevent you from taking screenshots in this app.",
|
||||
style: TextStyle(
|
||||
height: 1.5,
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context, rootNavigator: true)
|
||||
.pop('dialog');
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: Text(
|
||||
"Yes",
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.defaultTextColor,
|
||||
),
|
||||
Padding(padding: EdgeInsets.all(8)),
|
||||
Text(
|
||||
"Are you sure?",
|
||||
style: TextStyle(
|
||||
height: 1.5,
|
||||
),
|
||||
onPressed: () async {
|
||||
Navigator.of(context, rootNavigator: true)
|
||||
.pop('dialog');
|
||||
await _config.setShouldHideFromRecents(true);
|
||||
await FlutterWindowManager.addFlags(
|
||||
FlutterWindowManager.FLAG_SECURE,
|
||||
);
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return alert;
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text(
|
||||
"No",
|
||||
style: TextStyle(
|
||||
color:
|
||||
Theme.of(context).colorScheme.defaultTextColor,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context, rootNavigator: true)
|
||||
.pop('dialog');
|
||||
},
|
||||
);
|
||||
} else {
|
||||
await _config.setShouldHideFromRecents(false);
|
||||
await FlutterWindowManager.clearFlags(
|
||||
FlutterWindowManager.FLAG_SECURE,
|
||||
);
|
||||
setState(() {});
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
TextButton(
|
||||
child: Text(
|
||||
"Yes",
|
||||
style: TextStyle(
|
||||
color:
|
||||
Theme.of(context).colorScheme.defaultTextColor,
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
Navigator.of(context, rootNavigator: true)
|
||||
.pop('dialog');
|
||||
await _config.setShouldHideFromRecents(true);
|
||||
await FlutterWindowManager.addFlags(
|
||||
FlutterWindowManager.FLAG_SECURE,
|
||||
);
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return alert;
|
||||
},
|
||||
);
|
||||
} else {
|
||||
await _config.setShouldHideFromRecents(false);
|
||||
await FlutterWindowManager.clearFlags(
|
||||
FlutterWindowManager.FLAG_SECURE,
|
||||
);
|
||||
setState(() {});
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
],
|
||||
);
|
||||
}
|
||||
children.addAll([
|
||||
sectionOptionDivider,
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Active sessions",
|
||||
),
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
final hasAuthenticated = await LocalAuthenticationService.instance
|
||||
.requestLocalAuthentication(
|
||||
|
@ -258,11 +234,8 @@ class _SecuritySectionWidgetState extends State<SecuritySectionWidget> {
|
|||
);
|
||||
}
|
||||
},
|
||||
child: const SettingsTextItem(
|
||||
text: "Active sessions",
|
||||
icon: Icons.navigate_next,
|
||||
),
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
]);
|
||||
return Column(
|
||||
children: children,
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:expandable/expandable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:photos/services/update_service.dart';
|
||||
import 'package:photos/ui/components/captioned_text_widget.dart';
|
||||
import 'package:photos/ui/components/expandable_menu_item_widget.dart';
|
||||
import 'package:photos/ui/components/menu_item_widget.dart';
|
||||
import 'package:photos/ui/settings/common_settings.dart';
|
||||
import 'package:photos/ui/settings/settings_section_title.dart';
|
||||
import 'package:photos/ui/settings/settings_text_item.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
class SocialSectionWidget extends StatelessWidget {
|
||||
|
@ -15,68 +15,57 @@ class SocialSectionWidget extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ExpandablePanel(
|
||||
header: const SettingsSectionTitle("Social"),
|
||||
collapsed: Container(),
|
||||
expanded: _getSectionOptions(context),
|
||||
theme: getExpandableTheme(context),
|
||||
return ExpandableMenuItemWidget(
|
||||
title: "Social",
|
||||
selectionOptionsWidget: _getSectionOptions(context),
|
||||
leadingIcon: Icons.interests_outlined,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getSectionOptions(BuildContext context) {
|
||||
final List<Widget> options = [
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () {
|
||||
launchUrlString("https://twitter.com/enteio");
|
||||
},
|
||||
child:
|
||||
const SettingsTextItem(text: "Twitter", icon: Icons.navigate_next),
|
||||
),
|
||||
sectionOptionDivider,
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () {
|
||||
launchUrlString("https://ente.io/discord");
|
||||
},
|
||||
child:
|
||||
const SettingsTextItem(text: "Discord", icon: Icons.navigate_next),
|
||||
),
|
||||
sectionOptionDivider,
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () {
|
||||
launchUrlString("https://reddit.com/r/enteio");
|
||||
},
|
||||
child:
|
||||
const SettingsTextItem(text: "Reddit", icon: Icons.navigate_next),
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
const SocialsMenuItemWidget("Twitter", "https://twitter.com/enteio"),
|
||||
sectionOptionSpacing,
|
||||
const SocialsMenuItemWidget("Discord", "https://ente.io/discord"),
|
||||
sectionOptionSpacing,
|
||||
const SocialsMenuItemWidget("Reddit", "https://reddit.com/r/enteio"),
|
||||
sectionOptionSpacing,
|
||||
];
|
||||
if (!UpdateService.instance.isIndependent()) {
|
||||
options.addAll(
|
||||
[
|
||||
sectionOptionDivider,
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () {
|
||||
if (Platform.isAndroid) {
|
||||
launchUrlString(
|
||||
"https://play.google.com/store/apps/details?id=io.ente.photos",
|
||||
);
|
||||
} else {
|
||||
launchUrlString(
|
||||
"https://apps.apple.com/in/app/ente-photos/id1542026904",
|
||||
);
|
||||
}
|
||||
},
|
||||
child: const SettingsTextItem(
|
||||
text: "Rate us! ✨",
|
||||
icon: Icons.navigate_next,
|
||||
),
|
||||
)
|
||||
SocialsMenuItemWidget(
|
||||
"Rate us! ✨",
|
||||
Platform.isAndroid
|
||||
? "https://play.google.com/store/apps/details?id=io.ente.photos"
|
||||
: "https://apps.apple.com/in/app/ente-photos/id1542026904",
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
],
|
||||
);
|
||||
}
|
||||
return Column(children: options);
|
||||
}
|
||||
}
|
||||
|
||||
class SocialsMenuItemWidget extends StatelessWidget {
|
||||
final String text;
|
||||
final String urlSring;
|
||||
const SocialsMenuItemWidget(this.text, this.urlSring, {Key key})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: text,
|
||||
),
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () {
|
||||
launchUrlString(urlSring);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,14 +2,14 @@
|
|||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:expandable/expandable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:photos/core/configuration.dart';
|
||||
import 'package:photos/core/constants.dart';
|
||||
import 'package:photos/ui/common/web_page.dart';
|
||||
import 'package:photos/ui/components/captioned_text_widget.dart';
|
||||
import 'package:photos/ui/components/expandable_menu_item_widget.dart';
|
||||
import 'package:photos/ui/components/menu_item_widget.dart';
|
||||
import 'package:photos/ui/settings/common_settings.dart';
|
||||
import 'package:photos/ui/settings/settings_section_title.dart';
|
||||
import 'package:photos/ui/settings/settings_text_item.dart';
|
||||
import 'package:photos/utils/email_util.dart';
|
||||
|
||||
class SupportSectionWidget extends StatelessWidget {
|
||||
|
@ -17,11 +17,10 @@ class SupportSectionWidget extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ExpandablePanel(
|
||||
header: const SettingsSectionTitle("Support"),
|
||||
collapsed: Container(),
|
||||
expanded: _getSectionOptions(context),
|
||||
theme: getExpandableTheme(context),
|
||||
return ExpandableMenuItemWidget(
|
||||
title: "Support",
|
||||
selectionOptionsWidget: _getSectionOptions(context),
|
||||
leadingIcon: Icons.help_outline_outlined,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -30,17 +29,24 @@ class SupportSectionWidget extends StatelessWidget {
|
|||
Platform.isAndroid ? "android-bugs@ente.io" : "ios-bugs@ente.io";
|
||||
return Column(
|
||||
children: [
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Email",
|
||||
),
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
await sendEmail(context, to: supportEmail);
|
||||
},
|
||||
child:
|
||||
const SettingsTextItem(text: "Email", icon: Icons.navigate_next),
|
||||
),
|
||||
sectionOptionDivider,
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Roadmap",
|
||||
),
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
|
@ -56,14 +62,14 @@ class SupportSectionWidget extends StatelessWidget {
|
|||
),
|
||||
);
|
||||
},
|
||||
child: const SettingsTextItem(
|
||||
text: "Roadmap",
|
||||
icon: Icons.navigate_next,
|
||||
),
|
||||
),
|
||||
sectionOptionDivider,
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: const CaptionedTextWidget(
|
||||
title: "Report a bug",
|
||||
),
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
await sendLogs(context, "Report bug", bugsEmail);
|
||||
},
|
||||
|
@ -71,11 +77,8 @@ class SupportSectionWidget extends StatelessWidget {
|
|||
final zipFilePath = await getZippedLogsFile(context);
|
||||
await shareLogs(context, bugsEmail, zipFilePath);
|
||||
},
|
||||
child: const SettingsTextItem(
|
||||
text: "Report bug 🐞",
|
||||
icon: Icons.navigate_next,
|
||||
),
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
// @dart=2.9
|
||||
|
||||
import 'package:adaptive_theme/adaptive_theme.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:photos/ente_theme_data.dart';
|
||||
import 'package:photos/ui/components/captioned_text_widget.dart';
|
||||
import 'package:photos/ui/components/expandable_menu_item_widget.dart';
|
||||
import 'package:photos/ui/components/menu_item_widget.dart';
|
||||
import 'package:photos/ui/settings/common_settings.dart';
|
||||
|
||||
class ThemeSwitchWidget extends StatefulWidget {
|
||||
const ThemeSwitchWidget({Key key}) : super(key: key);
|
||||
|
@ -12,13 +17,14 @@ class ThemeSwitchWidget extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _ThemeSwitchWidgetState extends State<ThemeSwitchWidget> {
|
||||
AdaptiveThemeMode themeMode;
|
||||
AdaptiveThemeMode currentThemeMode;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
AdaptiveTheme.getThemeMode().then(
|
||||
(value) {
|
||||
themeMode = value ?? AdaptiveThemeMode.system;
|
||||
currentThemeMode = value ?? AdaptiveThemeMode.system;
|
||||
debugPrint('theme value $value');
|
||||
if (mounted) {
|
||||
setState(() => {});
|
||||
|
@ -27,44 +33,51 @@ class _ThemeSwitchWidgetState extends State<ThemeSwitchWidget> {
|
|||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
return ExpandableMenuItemWidget(
|
||||
title: "Theme",
|
||||
selectionOptionsWidget: _getSectionOptions(context),
|
||||
leadingIcon: Theme.of(context).brightness == Brightness.light
|
||||
? Icons.light_mode_outlined
|
||||
: Icons.dark_mode_outlined,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getSectionOptions(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
sectionOptionSpacing,
|
||||
_menuItem(context, AdaptiveThemeMode.light),
|
||||
sectionOptionSpacing,
|
||||
_menuItem(context, AdaptiveThemeMode.dark),
|
||||
sectionOptionSpacing,
|
||||
_menuItem(context, AdaptiveThemeMode.system),
|
||||
sectionOptionSpacing,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _menuItem(BuildContext context, AdaptiveThemeMode themeMode) {
|
||||
return MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: toBeginningOfSentenceCase(themeMode.name),
|
||||
textStyle: Theme.of(context).colorScheme.enteTheme.textTheme.body,
|
||||
),
|
||||
isHeaderOfExpansion: false,
|
||||
trailingIcon: currentThemeMode == themeMode ? Icons.check : null,
|
||||
onTap: () async {
|
||||
await showCupertinoModalPopup(
|
||||
context: context,
|
||||
builder: (_) => CupertinoActionSheet(
|
||||
title: Text(
|
||||
"Theme",
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.headline4
|
||||
.copyWith(color: Colors.white),
|
||||
),
|
||||
actions: [
|
||||
for (var mode in AdaptiveThemeMode.values)
|
||||
CupertinoActionSheetAction(
|
||||
child: Text(mode.modeName),
|
||||
onPressed: () async {
|
||||
AdaptiveTheme.of(context).setThemeMode(mode);
|
||||
themeMode = mode;
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
if (mounted) {
|
||||
setState(() => {});
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
cancelButton: CupertinoActionSheetAction(
|
||||
child: const Text("Cancel"),
|
||||
onPressed: () {
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
AdaptiveTheme.of(context).setThemeMode(themeMode);
|
||||
currentThemeMode = themeMode;
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
},
|
||||
child: Text(themeMode?.modeName ?? ">"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,16 +5,16 @@ import 'dart:io';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:photos/core/configuration.dart';
|
||||
import 'package:photos/ente_theme_data.dart';
|
||||
import 'package:photos/services/feature_flag_service.dart';
|
||||
import 'package:photos/ui/settings/about_section_widget.dart';
|
||||
import 'package:photos/ui/settings/account_section_widget.dart';
|
||||
import 'package:photos/ui/settings/app_version_widget.dart';
|
||||
import 'package:photos/ui/settings/backup_section_widget.dart';
|
||||
import 'package:photos/ui/settings/danger_section_widget.dart';
|
||||
import 'package:photos/ui/settings/debug_section_widget.dart';
|
||||
import 'package:photos/ui/settings/details_section_widget.dart';
|
||||
import 'package:photos/ui/settings/info_section_widget.dart';
|
||||
import 'package:photos/ui/settings/security_section_widget.dart';
|
||||
import 'package:photos/ui/settings/settings_section_title.dart';
|
||||
import 'package:photos/ui/settings/social_section_widget.dart';
|
||||
import 'package:photos/ui/settings/support_section_widget.dart';
|
||||
import 'package:photos/ui/settings/theme_switch_widget.dart';
|
||||
|
@ -26,7 +26,14 @@ class SettingsPage extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: _getBody(context),
|
||||
body: Container(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.enteTheme
|
||||
.colorScheme
|
||||
.backgroundElevated,
|
||||
child: _getBody(context),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -54,60 +61,47 @@ class SettingsPage extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
);
|
||||
final sectionDivider = Divider(
|
||||
height: 20,
|
||||
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.12),
|
||||
);
|
||||
contents.add(const Padding(padding: EdgeInsets.all(4)));
|
||||
const sectionSpacing = SizedBox(height: 8);
|
||||
contents.add(const SizedBox(height: 8));
|
||||
if (hasLoggedIn) {
|
||||
contents.addAll([
|
||||
const DetailsSectionWidget(),
|
||||
const Padding(padding: EdgeInsets.only(bottom: 24)),
|
||||
const SizedBox(height: 12),
|
||||
const BackupSectionWidget(),
|
||||
sectionDivider,
|
||||
sectionSpacing,
|
||||
const AccountSectionWidget(),
|
||||
sectionDivider,
|
||||
sectionSpacing,
|
||||
]);
|
||||
}
|
||||
contents.addAll([
|
||||
const SecuritySectionWidget(),
|
||||
sectionDivider,
|
||||
sectionSpacing,
|
||||
]);
|
||||
|
||||
if (Platform.isAndroid || kDebugMode) {
|
||||
contents.addAll([
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: const [
|
||||
SettingsSectionTitle("Theme"),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(right: 4),
|
||||
child: ThemeSwitchWidget(),
|
||||
),
|
||||
],
|
||||
),
|
||||
sectionDivider,
|
||||
const ThemeSwitchWidget(),
|
||||
sectionSpacing,
|
||||
]);
|
||||
}
|
||||
|
||||
contents.addAll([
|
||||
const SupportSectionWidget(),
|
||||
sectionDivider,
|
||||
sectionSpacing,
|
||||
const SocialSectionWidget(),
|
||||
sectionDivider,
|
||||
const InfoSectionWidget(),
|
||||
sectionSpacing,
|
||||
const AboutSectionWidget(),
|
||||
]);
|
||||
if (hasLoggedIn) {
|
||||
contents.addAll([
|
||||
sectionDivider,
|
||||
sectionSpacing,
|
||||
const DangerSectionWidget(),
|
||||
]);
|
||||
}
|
||||
|
||||
if (FeatureFlagService.instance.isInternalUserOrDebugBuild() &&
|
||||
hasLoggedIn) {
|
||||
contents.addAll([sectionDivider, const DebugSectionWidget()]);
|
||||
contents.addAll([sectionSpacing, const DebugSectionWidget()]);
|
||||
}
|
||||
contents.add(const AppVersionWidget());
|
||||
contents.add(
|
||||
|
@ -118,10 +112,10 @@ class SettingsPage extends StatelessWidget {
|
|||
|
||||
return SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 20),
|
||||
padding: const EdgeInsets.fromLTRB(16, 16, 16, 24),
|
||||
child: Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 350),
|
||||
constraints: const BoxConstraints(maxWidth: 428),
|
||||
child: Column(
|
||||
children: contents,
|
||||
),
|
||||
|
|
Loading…
Add table
Reference in a new issue