Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d389d3d163 | ||
|
|
60e34f780e | ||
|
|
16d57b8bad | ||
|
|
ddc14a031e | ||
|
|
bd7402fe38 | ||
|
|
ad3ae560bd | ||
|
|
1a15410f0d | ||
|
|
3d7a4b1d32 | ||
|
|
ba1c74b9b5 | ||
|
|
9d3a7efe29 | ||
|
|
95d7a9fe67 | ||
|
|
e4a549a55b | ||
|
|
9f0a53e733 | ||
|
|
c89bffb8ff | ||
|
|
7456b0a2e7 | ||
|
|
bffff57d28 | ||
|
|
442bab6bdd | ||
|
|
ef9530af24 | ||
|
|
cdb615b0ba | ||
|
|
fddf9169d3 | ||
|
|
91cd77ad8d | ||
|
|
1697547091 | ||
|
|
7fb3ab02f9 | ||
|
|
d855559bab | ||
|
|
c02a16a321 | ||
|
|
97bc2ba141 |
3
lib/events/icons_changed_event.dart
Normal file
3
lib/events/icons_changed_event.dart
Normal file
@@ -0,0 +1,3 @@
|
||||
import 'package:ente_auth/events/event.dart';
|
||||
|
||||
class IconsChangedEvent extends Event {}
|
||||
@@ -102,6 +102,7 @@
|
||||
"no": "No",
|
||||
"email": "Email",
|
||||
"support": "Support",
|
||||
"general": "General",
|
||||
"settings": "Settings",
|
||||
"copied": "Copied",
|
||||
"pleaseTryAgain": "Please try again",
|
||||
@@ -183,6 +184,7 @@
|
||||
"enterDetailsManually": "Enter details manually",
|
||||
"edit": "Edit",
|
||||
"copiedToClipboard": "Copied to clipboard",
|
||||
"copiedNextToClipboard": "Copied next code to clipboard",
|
||||
"error": "Error",
|
||||
"recoveryKeyCopiedToClipboard": "Recovery key copied to clipboard",
|
||||
"recoveryKeyOnForgotPassword": "If you forget your password, the only way you can recover your data is with this key.",
|
||||
@@ -325,5 +327,7 @@
|
||||
"signInToBackup": "Sign in to backup your codes",
|
||||
"singIn": "Sign in",
|
||||
"sigInBackupReminder": "Please export your codes to ensure that you have a backup you can restore from.",
|
||||
"offlineModeWarning": "You have chosen to proceed without backups. Please take manual backups to make sure your codes are safe."
|
||||
"offlineModeWarning": "You have chosen to proceed without backups. Please take manual backups to make sure your codes are safe.",
|
||||
"showLargeIcons": "Show large icons",
|
||||
"focusOnSearchBar": "Focus search on app start"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'package:ente_auth/core/event_bus.dart';
|
||||
import 'package:ente_auth/events/icons_changed_event.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class PreferenceService {
|
||||
@@ -8,6 +10,8 @@ class PreferenceService {
|
||||
late final SharedPreferences _prefs;
|
||||
|
||||
static const kHasShownCoachMarkKey = "has_shown_coach_mark";
|
||||
static const kShouldShowLargeIconsKey = "should_show_large_icons";
|
||||
static const kShouldAutoFocusOnSearchBar = "should_auto_focus_on_search_bar";
|
||||
|
||||
Future<void> init() async {
|
||||
_prefs = await SharedPreferences.getInstance();
|
||||
@@ -24,4 +28,30 @@ class PreferenceService {
|
||||
Future<void> setHasShownCoachMark(bool value) {
|
||||
return _prefs.setBool(kHasShownCoachMarkKey, value);
|
||||
}
|
||||
|
||||
bool shouldShowLargeIcons() {
|
||||
if (_prefs.containsKey(kShouldShowLargeIconsKey)) {
|
||||
return _prefs.getBool(kShouldShowLargeIconsKey)!;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setShowLargeIcons(bool value) async {
|
||||
await _prefs.setBool(kShouldShowLargeIconsKey, value);
|
||||
Bus.instance.fire(IconsChangedEvent());
|
||||
}
|
||||
|
||||
bool shouldAutoFocusOnSearchBar() {
|
||||
if (_prefs.containsKey(kShouldAutoFocusOnSearchBar)) {
|
||||
return _prefs.getBool(kShouldAutoFocusOnSearchBar)!;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setAutoFocusOnSearchBar(bool value) async {
|
||||
await _prefs.setBool(kShouldAutoFocusOnSearchBar, value);
|
||||
Bus.instance.fire(IconsChangedEvent());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:ente_auth/l10n/l10n.dart';
|
||||
import 'package:ente_auth/models/code.dart';
|
||||
import 'package:ente_auth/onboarding/view/setup_enter_secret_key_page.dart';
|
||||
import 'package:ente_auth/onboarding/view/view_qr_page.dart';
|
||||
import 'package:ente_auth/services/preference_service.dart';
|
||||
import 'package:ente_auth/store/code_store.dart';
|
||||
import 'package:ente_auth/ui/code_timer_progress.dart';
|
||||
import 'package:ente_auth/ui/utils/icon_utils.dart';
|
||||
@@ -33,6 +34,7 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
final Logger logger = Logger("_CodeWidgetState");
|
||||
bool _isInitialized = false;
|
||||
late bool hasConfiguredAccount;
|
||||
late bool _shouldShowLargeIcon;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -61,6 +63,7 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
_shouldShowLargeIcon = PreferenceService.instance.shouldShowLargeIcons();
|
||||
if (!_isInitialized) {
|
||||
_currentCode.value = _getCurrentOTP();
|
||||
if (widget.code.type == Type.totp) {
|
||||
@@ -136,132 +139,7 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
onLongPress: () {
|
||||
_copyToClipboard();
|
||||
},
|
||||
child: SizedBox(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (widget.code.type == Type.totp)
|
||||
CodeTimerProgress(
|
||||
period: widget.code.period,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
safeDecode(widget.code.issuer).trim(),
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
safeDecode(widget.code.account).trim(),
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall
|
||||
?.copyWith(
|
||||
fontSize: 12,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
(widget.code.hasSynced != null &&
|
||||
widget.code.hasSynced!) || !hasConfiguredAccount
|
||||
? const SizedBox.shrink()
|
||||
: const Icon(
|
||||
Icons.sync_disabled,
|
||||
size: 20,
|
||||
color: Colors.amber,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
IconUtils.instance.getIcon(
|
||||
safeDecode(widget.code.issuer).trim(),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Container(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Expanded(
|
||||
child: ValueListenableBuilder<String>(
|
||||
valueListenable: _currentCode,
|
||||
builder: (context, value, child) {
|
||||
return Text(
|
||||
value,
|
||||
style: const TextStyle(fontSize: 24),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
widget.code.type == Type.totp
|
||||
? Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
l10n.nextTotpTitle,
|
||||
style:
|
||||
Theme.of(context).textTheme.bodySmall,
|
||||
),
|
||||
ValueListenableBuilder<String>(
|
||||
valueListenable: _nextCode,
|
||||
builder: (context, value, child) {
|
||||
return Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
color: Colors.grey,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
l10n.nextTotpTitle,
|
||||
style:
|
||||
Theme.of(context).textTheme.bodySmall,
|
||||
),
|
||||
InkWell(
|
||||
onTap: _onNextHotpTapped,
|
||||
child: const Icon(
|
||||
Icons.forward_outlined,
|
||||
size: 32,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
child: _getCardContents(l10n),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -270,11 +148,181 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getCardContents(AppLocalizations l10n) {
|
||||
return SizedBox(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (widget.code.type == Type.totp)
|
||||
CodeTimerProgress(
|
||||
period: widget.code.period,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
_shouldShowLargeIcon ? _getIcon() : const SizedBox.shrink(),
|
||||
Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
_getTopRow(),
|
||||
const SizedBox(height: 4),
|
||||
_getBottomRow(l10n),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getBottomRow(AppLocalizations l10n) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Expanded(
|
||||
child: ValueListenableBuilder<String>(
|
||||
valueListenable: _currentCode,
|
||||
builder: (context, value, child) {
|
||||
return Material(
|
||||
type: MaterialType.transparency,
|
||||
child: Text(
|
||||
_getFormattedCode(value),
|
||||
style: const TextStyle(fontSize: 24),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
widget.code.type == Type.totp
|
||||
? GestureDetector(
|
||||
onTap: () {
|
||||
_copyNextToClipboard();
|
||||
},
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
l10n.nextTotpTitle,
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
),
|
||||
ValueListenableBuilder<String>(
|
||||
valueListenable: _nextCode,
|
||||
builder: (context, value, child) {
|
||||
return Material(
|
||||
type: MaterialType.transparency,
|
||||
child: Text(
|
||||
_getFormattedCode(value),
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
l10n.nextTotpTitle,
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
),
|
||||
InkWell(
|
||||
onTap: _onNextHotpTapped,
|
||||
child: const Icon(
|
||||
Icons.forward_outlined,
|
||||
size: 32,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getTopRow() {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 16, right: 16),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
safeDecode(widget.code.issuer).trim(),
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
safeDecode(widget.code.account).trim(),
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
fontSize: 12,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
(widget.code.hasSynced != null && widget.code.hasSynced!) ||
|
||||
!hasConfiguredAccount
|
||||
? const SizedBox.shrink()
|
||||
: const Icon(
|
||||
Icons.sync_disabled,
|
||||
size: 20,
|
||||
color: Colors.amber,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
_shouldShowLargeIcon ? const SizedBox.shrink() : _getIcon(),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getIcon() {
|
||||
return Padding(
|
||||
padding: _shouldShowLargeIcon
|
||||
? const EdgeInsets.only(left: 16)
|
||||
: const EdgeInsets.all(0),
|
||||
child: IconUtils.instance.getIcon(
|
||||
safeDecode(widget.code.issuer).trim(),
|
||||
width: _shouldShowLargeIcon ? 42 : 24,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _copyToClipboard() {
|
||||
FlutterClipboard.copy(_getCurrentOTP())
|
||||
.then((value) => showToast(context, context.l10n.copiedToClipboard));
|
||||
}
|
||||
|
||||
void _copyNextToClipboard() {
|
||||
FlutterClipboard.copy(_getNextTotp()).then(
|
||||
(value) => showToast(context, context.l10n.copiedNextToClipboard),
|
||||
);
|
||||
}
|
||||
|
||||
void _onNextHotpTapped() {
|
||||
if (widget.code.type == Type.hotp) {
|
||||
CodeStore.instance
|
||||
@@ -300,6 +348,7 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
}
|
||||
|
||||
Future<void> _onShowQrPressed(_) async {
|
||||
// ignore: unused_local_variable
|
||||
final Code? code = await Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) {
|
||||
@@ -339,4 +388,11 @@ class _CodeWidgetState extends State<CodeWidget> {
|
||||
return context.l10n.error;
|
||||
}
|
||||
}
|
||||
|
||||
String _getFormattedCode(String code) {
|
||||
if (code.length == 6) {
|
||||
return code.substring(0, 3) + " " + code.substring(3, 6);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ class _ToggleSwitchWidgetState extends State<ToggleSwitchWidget> {
|
||||
fit: BoxFit.contain,
|
||||
child: Switch.adaptive(
|
||||
activeColor: enteColorScheme.primary400,
|
||||
activeTrackColor: enteColorScheme.primary300,
|
||||
inactiveTrackColor: enteColorScheme.fillMuted,
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
value: toggleValue ?? false,
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:ente_auth/core/configuration.dart';
|
||||
import 'package:ente_auth/core/event_bus.dart';
|
||||
import 'package:ente_auth/ente_theme_data.dart';
|
||||
import 'package:ente_auth/events/codes_updated_event.dart';
|
||||
import 'package:ente_auth/events/icons_changed_event.dart';
|
||||
import 'package:ente_auth/events/trigger_logout_event.dart';
|
||||
import "package:ente_auth/l10n/l10n.dart";
|
||||
import 'package:ente_auth/models/code.dart';
|
||||
@@ -51,6 +52,7 @@ class _HomePageState extends State<HomePage> {
|
||||
List<Code> _filteredCodes = [];
|
||||
StreamSubscription<CodesUpdatedEvent>? _streamSubscription;
|
||||
StreamSubscription<TriggerLogoutEvent>? _triggerLogoutEvent;
|
||||
StreamSubscription<IconsChangedEvent>? _iconsChangedEvent;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -69,6 +71,10 @@ class _HomePageState extends State<HomePage> {
|
||||
const Duration(seconds: 1),
|
||||
() async => await CodeStore.instance.importOfflineCodes(),
|
||||
);
|
||||
_iconsChangedEvent = Bus.instance.on<IconsChangedEvent>().listen((event) {
|
||||
setState(() {});
|
||||
});
|
||||
_showSearchBox = PreferenceService.instance.shouldAutoFocusOnSearchBar();
|
||||
}
|
||||
|
||||
void _loadCodes() {
|
||||
@@ -100,6 +106,7 @@ class _HomePageState extends State<HomePage> {
|
||||
void dispose() {
|
||||
_streamSubscription?.cancel();
|
||||
_triggerLogoutEvent?.cancel();
|
||||
_iconsChangedEvent?.cancel();
|
||||
_textController.removeListener(_applyFilteringAndRefresh);
|
||||
super.dispose();
|
||||
}
|
||||
@@ -171,7 +178,7 @@ class _HomePageState extends State<HomePage> {
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: AppBar(
|
||||
title: !_showSearchBox
|
||||
? const Text('ente Authenticator')
|
||||
? const Text('ente Auth')
|
||||
: TextField(
|
||||
autofocus: _searchText.isEmpty,
|
||||
controller: _textController,
|
||||
@@ -182,6 +189,7 @@ class _HomePageState extends State<HomePage> {
|
||||
decoration: InputDecoration(
|
||||
hintText: l10n.searchHint,
|
||||
border: InputBorder.none,
|
||||
focusedBorder: InputBorder.none,
|
||||
),
|
||||
),
|
||||
actions: <Widget>[
|
||||
@@ -228,7 +236,7 @@ class _HomePageState extends State<HomePage> {
|
||||
itemBuilder: ((context, index) {
|
||||
try {
|
||||
return CodeWidget(_filteredCodes[index]);
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
return const Text("Failed");
|
||||
}
|
||||
}),
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
|
||||
|
||||
import 'package:ente_auth/app/view/app.dart';
|
||||
import 'package:ente_auth/l10n/l10n.dart';
|
||||
import 'package:ente_auth/locale.dart';
|
||||
import 'package:ente_auth/services/local_authentication_service.dart';
|
||||
import 'package:ente_auth/services/user_service.dart';
|
||||
import 'package:ente_auth/theme/ente_theme.dart';
|
||||
@@ -13,7 +11,6 @@ import 'package:ente_auth/ui/components/captioned_text_widget.dart';
|
||||
import 'package:ente_auth/ui/components/expandable_menu_item_widget.dart';
|
||||
import 'package:ente_auth/ui/components/menu_item_widget.dart';
|
||||
import 'package:ente_auth/ui/settings/common_settings.dart';
|
||||
import 'package:ente_auth/ui/settings/language_picker.dart';
|
||||
import 'package:ente_auth/utils/dialog_util.dart';
|
||||
import 'package:ente_auth/utils/navigation_util.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -89,29 +86,6 @@ class AccountSectionWidget extends StatelessWidget {
|
||||
},
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: l10n.language,
|
||||
),
|
||||
pressedColor: getEnteColorScheme(context).fillFaint,
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
final locale = await getLocale();
|
||||
routeToPage(
|
||||
context,
|
||||
LanguageSelectorPage(
|
||||
appSupportedLocales,
|
||||
(locale) async {
|
||||
await setLocale(locale);
|
||||
App.setLocale(context, locale);
|
||||
},
|
||||
locale,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: context.l10n.logout,
|
||||
|
||||
111
lib/ui/settings/general_section_widget.dart
Normal file
111
lib/ui/settings/general_section_widget.dart
Normal file
@@ -0,0 +1,111 @@
|
||||
import 'package:ente_auth/app/view/app.dart';
|
||||
import 'package:ente_auth/core/logging/super_logging.dart';
|
||||
import 'package:ente_auth/l10n/l10n.dart';
|
||||
import 'package:ente_auth/locale.dart';
|
||||
import 'package:ente_auth/services/preference_service.dart';
|
||||
import 'package:ente_auth/theme/ente_theme.dart';
|
||||
import 'package:ente_auth/ui/components/captioned_text_widget.dart';
|
||||
import 'package:ente_auth/ui/components/expandable_menu_item_widget.dart';
|
||||
import 'package:ente_auth/ui/components/menu_item_widget.dart';
|
||||
import 'package:ente_auth/ui/components/toggle_switch_widget.dart';
|
||||
import 'package:ente_auth/ui/settings/common_settings.dart';
|
||||
import 'package:ente_auth/ui/settings/language_picker.dart';
|
||||
import 'package:ente_auth/utils/navigation_util.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AdvancedSectionWidget extends StatefulWidget {
|
||||
const AdvancedSectionWidget({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<AdvancedSectionWidget> createState() => _AdvancedSectionWidgetState();
|
||||
}
|
||||
|
||||
class _AdvancedSectionWidgetState extends State<AdvancedSectionWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = context.l10n;
|
||||
return ExpandableMenuItemWidget(
|
||||
title: l10n.general,
|
||||
selectionOptionsWidget: _getSectionOptions(context),
|
||||
leadingIcon: Icons.graphic_eq,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getSectionOptions(BuildContext context) {
|
||||
final l10n = context.l10n;
|
||||
return Column(
|
||||
children: [
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: l10n.language,
|
||||
),
|
||||
pressedColor: getEnteColorScheme(context).fillFaint,
|
||||
trailingIcon: Icons.chevron_right_outlined,
|
||||
trailingIconIsMuted: true,
|
||||
onTap: () async {
|
||||
final locale = await getLocale();
|
||||
routeToPage(
|
||||
context,
|
||||
LanguageSelectorPage(
|
||||
appSupportedLocales,
|
||||
(locale) async {
|
||||
await setLocale(locale);
|
||||
App.setLocale(context, locale);
|
||||
},
|
||||
locale,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: l10n.showLargeIcons,
|
||||
),
|
||||
trailingWidget: ToggleSwitchWidget(
|
||||
value: () => PreferenceService.instance.shouldShowLargeIcons(),
|
||||
onChanged: () async {
|
||||
await PreferenceService.instance.setShowLargeIcons(
|
||||
!PreferenceService.instance.shouldShowLargeIcons(),
|
||||
);
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: l10n.focusOnSearchBar,
|
||||
),
|
||||
trailingWidget: ToggleSwitchWidget(
|
||||
value: () =>
|
||||
PreferenceService.instance.shouldAutoFocusOnSearchBar(),
|
||||
onChanged: () async {
|
||||
await PreferenceService.instance.setAutoFocusOnSearchBar(
|
||||
!PreferenceService.instance.shouldAutoFocusOnSearchBar(),
|
||||
);
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: l10n.crashAndErrorReporting,
|
||||
),
|
||||
trailingWidget: ToggleSwitchWidget(
|
||||
value: () => SuperLogging.shouldReportErrors(),
|
||||
onChanged: () async {
|
||||
await SuperLogging.setShouldReportErrors(
|
||||
!SuperLogging.shouldReportErrors(),
|
||||
);
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,9 @@
|
||||
import 'package:ente_auth/core/constants.dart';
|
||||
import 'package:ente_auth/core/logging/super_logging.dart';
|
||||
import 'package:ente_auth/l10n/l10n.dart';
|
||||
import 'package:ente_auth/theme/ente_theme.dart';
|
||||
import 'package:ente_auth/ui/components/captioned_text_widget.dart';
|
||||
import 'package:ente_auth/ui/components/expandable_menu_item_widget.dart';
|
||||
import 'package:ente_auth/ui/components/menu_item_widget.dart';
|
||||
import 'package:ente_auth/ui/components/toggle_switch_widget.dart';
|
||||
import 'package:ente_auth/ui/settings/common_settings.dart';
|
||||
import 'package:ente_auth/ui/settings/faq.dart';
|
||||
import 'package:ente_auth/utils/email_util.dart';
|
||||
@@ -35,7 +33,6 @@ class _SupportSectionWidgetState extends State<SupportSectionWidget> {
|
||||
return Column(
|
||||
children: [
|
||||
sectionOptionSpacing,
|
||||
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: l10n.faq,
|
||||
@@ -98,21 +95,6 @@ class _SupportSectionWidgetState extends State<SupportSectionWidget> {
|
||||
},
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
MenuItemWidget(
|
||||
captionedTextWidget: CaptionedTextWidget(
|
||||
title: l10n.crashAndErrorReporting,
|
||||
),
|
||||
trailingWidget: ToggleSwitchWidget(
|
||||
value: () => SuperLogging.shouldReportErrors(),
|
||||
onChanged: () async {
|
||||
await SuperLogging.setShouldReportErrors(
|
||||
!SuperLogging.shouldReportErrors(),
|
||||
);
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
sectionOptionSpacing,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import 'package:ente_auth/ui/settings/account_section_widget.dart';
|
||||
import 'package:ente_auth/ui/settings/app_version_widget.dart';
|
||||
import 'package:ente_auth/ui/settings/data/data_section_widget.dart';
|
||||
import 'package:ente_auth/ui/settings/data/export_widget.dart';
|
||||
import 'package:ente_auth/ui/settings/general_section_widget.dart';
|
||||
import 'package:ente_auth/ui/settings/security_section_widget.dart';
|
||||
import 'package:ente_auth/ui/settings/social_section_widget.dart';
|
||||
import 'package:ente_auth/ui/settings/support_dev_widget.dart';
|
||||
@@ -125,6 +126,8 @@ class SettingsPage extends StatelessWidget {
|
||||
}
|
||||
|
||||
contents.addAll([
|
||||
const AdvancedSectionWidget(),
|
||||
sectionSpacing,
|
||||
const SupportSectionWidget(),
|
||||
sectionSpacing,
|
||||
const SocialSectionWidget(),
|
||||
|
||||
@@ -18,29 +18,39 @@ class IconUtils {
|
||||
await _loadJson();
|
||||
}
|
||||
|
||||
Widget getIcon(String provider) {
|
||||
Widget getIcon(
|
||||
String provider, {
|
||||
double width = 24,
|
||||
}) {
|
||||
final title = _getProviderTitle(provider);
|
||||
if (_customIcons.containsKey(title)) {
|
||||
return _getSVGIcon(
|
||||
"assets/custom-icons/icons/$title.svg",
|
||||
title,
|
||||
_customIcons[title]!,
|
||||
width,
|
||||
);
|
||||
} else if (_simpleIcons.containsKey(title)) {
|
||||
return _getSVGIcon(
|
||||
"assets/simple-icons/icons/$title.svg",
|
||||
title,
|
||||
_simpleIcons[title]!,
|
||||
width,
|
||||
);
|
||||
} else {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
}
|
||||
|
||||
Widget _getSVGIcon(String path, String title, String color) {
|
||||
Widget _getSVGIcon(
|
||||
String path,
|
||||
String title,
|
||||
String color,
|
||||
double width,
|
||||
) {
|
||||
return SvgPicture.asset(
|
||||
path,
|
||||
width: 24,
|
||||
width: width,
|
||||
semanticsLabel: title,
|
||||
colorFilter: ColorFilter.mode(
|
||||
Color(int.parse("0xFF" + color)),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: ente_auth
|
||||
description: ente two-factor authenticator
|
||||
version: 2.0.1+201
|
||||
version: 2.0.4+204
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
|
||||
Reference in New Issue
Block a user