diff --git a/analysis_options.yaml b/analysis_options.yaml
index 0f21033c9a..99a1885531 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -19,7 +19,8 @@ analyzer:
exclude:
- lib/generated_plugin_registrant.dart
- lib/l10n/*.dart
- - '**.g.dart'
+ - "**.g.dart"
+ - integration_test/test_bundle.dart
dart_code_metrics:
metrics:
diff --git a/assets/images/ic_recovery_key.svg b/assets/images/ic_recovery_key.svg
new file mode 100644
index 0000000000..fdc1a37307
--- /dev/null
+++ b/assets/images/ic_recovery_key.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb
index 433657ab67..9281286b49 100644
--- a/assets/l10n/intl_en.arb
+++ b/assets/l10n/intl_en.arb
@@ -1788,6 +1788,10 @@
},
"recoveryKey": "Recovery key",
"@recoveryKey": {},
+ "recoveryKeyWarningMessage": "This secret grants access to all your encrypted messages to whomever uses it. Keep it safe and do not share it.",
+ "@recoveryKeyWarningMessage": {},
+ "recoveryKeyCopiedToClipboard": "Recovery key copied to clipboard",
+ "@recoveryKeyCopiedToClipboard": {},
"recoveryKeyLost": "Recovery key lost?",
"@recoveryKeyLost": {},
"seenByUser": "Seen by {username}",
diff --git a/integration_test/robots/login_robot.dart b/integration_test/robots/login_robot.dart
index fe59c57d5a..6b5761f957 100644
--- a/integration_test/robots/login_robot.dart
+++ b/integration_test/robots/login_robot.dart
@@ -1,8 +1,11 @@
import 'dart:io';
+import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:fluffychat/pages/chat_list/chat_list.dart';
import 'package:fluffychat/pages/homeserver_picker/homeserver_picker_view.dart';
import 'package:fluffychat/pages/twake_welcome/twake_welcome.dart';
import 'package:fluffychat/utils/platform_infos.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_test/flutter_test.dart';
import 'package:patrol/patrol.dart';
import '../base/core_robot.dart';
@@ -53,7 +56,9 @@ class LoginRobot extends CoreRobot {
}
Future tapOnUseYourCompanyServer() async {
- await $('Use your company server').tap();
+ final context = $.tester.element(find.byType(Scaffold).first);
+ final l10n = L10n.of(context)!;
+ await $(l10n.useYourCompanyServer).tap();
}
Future enterServerUrl(String serverUrl) async {
@@ -61,7 +66,8 @@ class LoginRobot extends CoreRobot {
}
Future clickOnContinueBtn() async {
- const label = 'Continue';
+ final context = $.tester.element(find.byType(Scaffold).first);
+ final label = L10n.of(context)!.continueProcess;
await $.waitUntilVisible($(label));
await $.tap($(label));
await waitUntilAbsent(
@@ -182,8 +188,15 @@ class LoginRobot extends CoreRobot {
// set a delay for verifying Captcha
await Future.delayed(const Duration(seconds: 2));
- // tap on Sign in
- await $.native.tap(getSignInBtn(), appId: getBrowserAppId());
+ // tap on Sign in – the browser modal may close immediately after a
+ // successful login, causing Patrol to report an error even though the
+ // tap succeeded. We catch that error and let the flow continue.
+ try {
+ await $.native.tap(getSignInBtn(), appId: getBrowserAppId());
+ } catch (_) {
+ // Browser closed after successful SSO login – expected.
+ return;
+ }
// if "verify ...please wait for Captcha" dialog is shown, click OK to continue waiting
// and click Sign in again
@@ -197,7 +210,11 @@ class LoginRobot extends CoreRobot {
getOKBtnInVerifyCaptchaDialog(),
appId: getBrowserAppId(),
);
- await $.native.tap(getSignInBtn(), appId: getBrowserAppId());
+ try {
+ await $.native.tap(getSignInBtn(), appId: getBrowserAppId());
+ } catch (_) {
+ // Browser closed after successful SSO login – expected.
+ }
}
}
}
diff --git a/integration_test/robots/setting/settings_recovery_key_robot.dart b/integration_test/robots/setting/settings_recovery_key_robot.dart
new file mode 100644
index 0000000000..e37f059f08
--- /dev/null
+++ b/integration_test/robots/setting/settings_recovery_key_robot.dart
@@ -0,0 +1,71 @@
+import 'dart:io';
+
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:patrol/patrol.dart';
+
+import 'package:fluffychat/generated/l10n/app_localizations.dart';
+
+import '../home_robot.dart';
+
+class SettingsRecoveryKeyRobot extends HomeRobot {
+ SettingsRecoveryKeyRobot(super.$);
+
+ PatrolFinder recoveryKeyItem() {
+ return $(const Key('recovery_key_settings_item'));
+ }
+
+ PatrolFinder recoveryKeyCopyButton() {
+ return $(const Key('recovery_key_copy_button'));
+ }
+
+ Future waitForRecoveryKeyVisible() async {
+ await $.waitUntilVisible(recoveryKeyItem());
+ }
+
+ /// Taps the copy button, then confirms the warning dialog by tapping "Copy".
+ Future tapCopyAndConfirm() async {
+ await recoveryKeyCopyButton().tap();
+ await _tapConfirmCopyInDialog();
+ }
+
+ /// Taps the recovery key row, then confirms the warning dialog.
+ Future tapRowAndConfirm() async {
+ await recoveryKeyItem().tap();
+ await _tapConfirmCopyInDialog();
+ }
+
+ Future _tapConfirmCopyInDialog() async {
+ final context = $.tester.element(find.byType(Scaffold).first);
+ final l10n = L10n.of(context)!;
+
+ if (Platform.isAndroid) {
+ final copyButton = $(
+ AlertDialog,
+ ).$(TextButton).containing(find.text(l10n.copy.toUpperCase()));
+ await $.waitUntilVisible(copyButton);
+ await copyButton.tap();
+ } else {
+ final copyButton = $(
+ CupertinoAlertDialog,
+ ).$(CupertinoDialogAction).containing(find.text(l10n.copy));
+ await $.waitUntilVisible(copyButton);
+ await copyButton.tap();
+ }
+ }
+
+ /// Reads the current text content from the system clipboard.
+ Future getClipboardText() async {
+ final data = await Clipboard.getData(Clipboard.kTextPlain);
+ return data?.text;
+ }
+
+ /// Verifies the snackbar "Recovery key copied to clipboard" is shown.
+ Future verifySnackBarIsShown() async {
+ final context = $.tester.element(find.byType(Scaffold).first);
+ final l10n = L10n.of(context)!;
+ await $.waitUntilVisible($(l10n.recoveryKeyCopiedToClipboard));
+ }
+}
diff --git a/integration_test/tests/setting/settings_recovery_key_test.dart b/integration_test/tests/setting/settings_recovery_key_test.dart
new file mode 100644
index 0000000000..b1fd3a165c
--- /dev/null
+++ b/integration_test/tests/setting/settings_recovery_key_test.dart
@@ -0,0 +1,54 @@
+import 'package:flutter/services.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+import '../../base/test_base.dart';
+import '../../robots/home_robot.dart';
+import '../../robots/setting/setting_robot.dart';
+import '../../robots/setting/settings_recovery_key_robot.dart';
+
+void main() {
+ TestBase().twakePatrolTest(
+ description:
+ 'Copy recovery key and verify clipboard contains the actual key',
+ test: ($) async {
+ // Clear clipboard before test
+ await Clipboard.setData(const ClipboardData(text: ''));
+
+ // Navigate to Settings > Privacy and Security
+ await HomeRobot($).gotoSettingScreen();
+ await SettingRobot($).openPrivacyAndSecuritySetting();
+
+ final recoveryKeyRobot = SettingsRecoveryKeyRobot($);
+
+ // Verify recovery key item is visible
+ await recoveryKeyRobot.waitForRecoveryKeyVisible();
+
+ // Tap the copy button and confirm the warning dialog
+ await recoveryKeyRobot.tapCopyAndConfirm();
+
+ // Verify the snackbar confirmation is shown
+ await recoveryKeyRobot.verifySnackBarIsShown();
+
+ // Read clipboard content and verify it contains the actual key
+ final clipboardText = await recoveryKeyRobot.getClipboardText();
+
+ expect(
+ clipboardText,
+ isNotNull,
+ reason: 'Clipboard should contain the recovery key after copy',
+ );
+ expect(
+ clipboardText,
+ isNotEmpty,
+ reason: 'Recovery key in clipboard should not be empty',
+ );
+ // Ensure the clipboard contains the real key, not the masked bullets
+ expect(
+ clipboardText,
+ isNot(equals('\u2022' * 32)),
+ reason:
+ 'Clipboard should contain the actual recovery key, not the masked value',
+ );
+ },
+ );
+}
diff --git a/lib/config/go_routes/app_route_paths.dart b/lib/config/go_routes/app_route_paths.dart
index cfddc43fb8..3f82c912d3 100644
--- a/lib/config/go_routes/app_route_paths.dart
+++ b/lib/config/go_routes/app_route_paths.dart
@@ -3,9 +3,60 @@
/// This file contains all route paths used in go_router configuration
/// and navigation calls to ensure consistency and prevent typos.
abstract class AppRoutePaths {
+ // Settings prefix check
+ static const String roomsSettings = '/rooms/settings';
+
+ // Profile routes
+ static const String profileSegment = 'profile';
+ static const String profileFull = '/rooms/$profileSegment';
+ static const String profileQrSegment = 'qr';
+ static const String profileQrFull = '$profileFull/$profileQrSegment';
+
+ // Chat settings routes
+ static const String chatSegment = 'chat';
+ static const String chatFull = '/rooms/$chatSegment';
+ static const String emotesSegment = 'emotes';
+ static const String chatEmotesFull = '$chatFull/$emotesSegment';
+
// Security routes
- static const String roomsSecurityFull = '/rooms/security';
+ static const String securitySegment = 'security';
+ static const String roomsSecurityFull = '/rooms/$securitySegment';
static const String contactsVisibilitySegment = 'contactsVisibility';
static const String contactsVisibilityFull =
'$roomsSecurityFull/$contactsVisibilitySegment';
+ static const String storiesSegment = 'stories';
+ static const String securityStoriesFull =
+ '$roomsSecurityFull/$storiesSegment';
+ static const String blockedUsersSegment = 'blockedUsers';
+ static const String securityBlockedUsersFull =
+ '$roomsSecurityFull/$blockedUsersSegment';
+ static const String threePidSegment = '3pid';
+ static const String securityThreePidFull =
+ '$roomsSecurityFull/$threePidSegment';
+
+ // Notifications routes
+ static const String notificationsSegment = 'notifications';
+ static const String notificationsFull = '/rooms/$notificationsSegment';
+
+ // Style routes
+ static const String styleSegment = 'style';
+ static const String styleFull = '/rooms/$styleSegment';
+
+ // App language routes
+ static const String appLanguageSegment = 'appLanguage';
+ static const String appLanguageFull = '/rooms/$appLanguageSegment';
+
+ // Devices routes
+ static const String devicesSegment = 'devices';
+ static const String devicesFull = '/rooms/$devicesSegment';
+
+ // Add account routes
+ static const String addAccountSegment = 'addaccount';
+ static const String addAccountFull = '/rooms/$addAccountSegment';
+ static const String addAccountLoginSegment = 'login';
+ static const String addAccountLoginFull =
+ '$addAccountFull/$addAccountLoginSegment';
+ static const String addAccountHomeserverPickerSegment = 'homeserverpicker';
+ static const String addAccountHomeserverPickerFull =
+ '$addAccountFull/$addAccountHomeserverPickerSegment';
}
diff --git a/lib/config/go_routes/go_router.dart b/lib/config/go_routes/go_router.dart
index 8cb4c93530..9bc535dd51 100644
--- a/lib/config/go_routes/go_router.dart
+++ b/lib/config/go_routes/go_router.dart
@@ -143,7 +143,7 @@ abstract class AppRoutes {
pageBuilder: (context, state, child) => defaultPageBuilder(
context,
!_responsive.isMobile(context) &&
- state.fullPath?.startsWith('/rooms/settings') == false
+ state.fullPath?.startsWith(AppRoutePaths.roomsSettings) == false
? AppAdaptiveScaffold(
body: AppAdaptiveScaffoldBody(
activeRoomId: state.pathParameters['roomid'],
@@ -296,13 +296,13 @@ abstract class AppRoutes {
},
),
GoRoute(
- path: 'profile',
+ path: AppRoutePaths.profileSegment,
pageBuilder: (context, state) =>
defaultPageBuilder(context, const SettingsProfile()),
routes: [
if (PlatformInfos.isMobile)
GoRoute(
- path: 'qr',
+ path: AppRoutePaths.profileQrSegment,
pageBuilder: (context, state) =>
defaultPageBuilder(context, const PersonalQr()),
redirect: loggedOutRedirect,
@@ -310,36 +310,36 @@ abstract class AppRoutes {
],
),
GoRoute(
- path: 'notifications',
+ path: AppRoutePaths.notificationsSegment,
pageBuilder: (context, state) =>
defaultPageBuilder(context, const SettingsNotifications()),
redirect: loggedOutRedirect,
),
GoRoute(
- path: 'style',
+ path: AppRoutePaths.styleSegment,
pageBuilder: (context, state) =>
defaultPageBuilder(context, const SettingsStyle()),
redirect: loggedOutRedirect,
),
GoRoute(
- path: 'devices',
+ path: AppRoutePaths.devicesSegment,
pageBuilder: (context, state) =>
defaultPageBuilder(context, const DevicesSettings()),
redirect: loggedOutRedirect,
),
GoRoute(
- path: 'appLanguage',
+ path: AppRoutePaths.appLanguageSegment,
pageBuilder: (context, state) =>
defaultPageBuilder(context, const SettingsAppLanguage()),
redirect: loggedOutRedirect,
),
GoRoute(
- path: 'chat',
+ path: AppRoutePaths.chatSegment,
pageBuilder: (context, state) =>
defaultPageBuilder(context, const SettingsChat()),
routes: [
GoRoute(
- path: 'emotes',
+ path: AppRoutePaths.emotesSegment,
pageBuilder: (context, state) =>
defaultPageBuilder(context, const EmotesSettings()),
),
@@ -347,7 +347,7 @@ abstract class AppRoutes {
redirect: loggedOutRedirect,
),
GoRoute(
- path: 'addaccount',
+ path: AppRoutePaths.addAccountSegment,
redirect: loggedOutRedirect,
pageBuilder: (context, state) => defaultPageBuilder(
context,
@@ -359,38 +359,38 @@ abstract class AppRoutes {
),
routes: [
GoRoute(
- path: 'login',
+ path: AppRoutePaths.addAccountLoginSegment,
pageBuilder: (context, state) =>
defaultPageBuilder(context, const Login()),
redirect: loggedOutRedirect,
),
GoRoute(
- path: 'homeserverpicker',
+ path: AppRoutePaths.addAccountHomeserverPickerSegment,
pageBuilder: (context, state) =>
defaultPageBuilder(context, const HomeserverPicker()),
),
],
),
GoRoute(
- path: 'security',
+ path: AppRoutePaths.securitySegment,
redirect: loggedOutRedirect,
pageBuilder: (context, state) =>
defaultPageBuilder(context, const SettingsSecurity()),
routes: [
GoRoute(
- path: 'stories',
+ path: AppRoutePaths.storiesSegment,
pageBuilder: (context, state) =>
defaultPageBuilder(context, const SettingsStories()),
redirect: loggedOutRedirect,
),
GoRoute(
- path: 'blockedUsers',
+ path: AppRoutePaths.blockedUsersSegment,
pageBuilder: (context, state) =>
defaultPageBuilder(context, const BlockedUsers()),
redirect: loggedOutRedirect,
),
GoRoute(
- path: '3pid',
+ path: AppRoutePaths.threePidSegment,
pageBuilder: (context, state) =>
defaultPageBuilder(context, const Settings3Pid()),
redirect: loggedOutRedirect,
diff --git a/lib/pages/chat/events/audio_message/audio_play_extension.dart b/lib/pages/chat/events/audio_message/audio_play_extension.dart
index a45c5629d6..9687879c9c 100644
--- a/lib/pages/chat/events/audio_message/audio_play_extension.dart
+++ b/lib/pages/chat/events/audio_message/audio_play_extension.dart
@@ -1,6 +1,9 @@
+// ignore_for_file: experimental_member_use
+
import 'package:just_audio/just_audio.dart';
import 'package:matrix/matrix.dart';
+///TODO(clement): Remove the ignore linter when the experimental member use is no longer needed.
class MatrixFileAudioSource extends StreamAudioSource {
final MatrixFile file;
diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart
index a0db3c9532..b3818eae5f 100644
--- a/lib/pages/chat_list/chat_list.dart
+++ b/lib/pages/chat_list/chat_list.dart
@@ -1,6 +1,7 @@
import 'dart:async';
import 'package:adaptive_dialog/adaptive_dialog.dart';
+import 'package:fluffychat/config/go_routes/app_route_paths.dart';
import 'package:collection/collection.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/first_column_inner_routes.dart';
@@ -741,7 +742,7 @@ class ChatListController extends State
}
void onClickAvatar() {
- context.push('/rooms/profile');
+ context.push(AppRoutePaths.profileFull);
}
void _handleRecovery() {
diff --git a/lib/pages/contacts_tab/contacts_tab.dart b/lib/pages/contacts_tab/contacts_tab.dart
index b1d558b869..bb364c238d 100644
--- a/lib/pages/contacts_tab/contacts_tab.dart
+++ b/lib/pages/contacts_tab/contacts_tab.dart
@@ -1,3 +1,4 @@
+import 'package:fluffychat/config/go_routes/app_route_paths.dart';
import 'package:fluffychat/di/global/get_it_initializer.dart';
import 'package:fluffychat/presentation/mixins/address_book_mixin.dart';
import 'package:fluffychat/presentation/mixins/comparable_presentation_contact_mixin.dart';
@@ -89,7 +90,7 @@ class ContactsTabController extends State
}
void goToSettingsProfile() {
- context.go('/rooms/profile');
+ context.go(AppRoutePaths.profileFull);
}
void goToDraftChat({
diff --git a/lib/pages/multiple_accounts/multiple_accounts_picker.dart b/lib/pages/multiple_accounts/multiple_accounts_picker.dart
index 4c8f5da74e..b6f518be23 100644
--- a/lib/pages/multiple_accounts/multiple_accounts_picker.dart
+++ b/lib/pages/multiple_accounts/multiple_accounts_picker.dart
@@ -1,4 +1,5 @@
import 'package:collection/collection.dart';
+import 'package:fluffychat/config/go_routes/app_route_paths.dart';
import 'package:fluffychat/pages/twake_welcome/twake_welcome.dart';
import 'package:fluffychat/presentation/multiple_account/twake_chat_presentation_account.dart';
import 'package:fluffychat/utils/dialog/twake_dialog.dart';
@@ -79,7 +80,7 @@ class MultipleAccountsPickerController {
void _onAddAnotherAccount() {
context.push(
- '/rooms/addaccount',
+ AppRoutePaths.addAccountFull,
extra: const TwakeWelcomeArg(twakeIdType: TwakeWelcomeType.otherAccounts),
);
}
diff --git a/lib/pages/search/search.dart b/lib/pages/search/search.dart
index a182004730..d255fa00cd 100644
--- a/lib/pages/search/search.dart
+++ b/lib/pages/search/search.dart
@@ -1,4 +1,5 @@
import 'package:dartz/dartz.dart' hide State;
+import 'package:fluffychat/config/go_routes/app_route_paths.dart';
import 'package:fluffychat/app_state/failure.dart';
import 'package:fluffychat/app_state/success.dart';
import 'package:fluffychat/di/global/get_it_initializer.dart';
@@ -103,7 +104,7 @@ class SearchController extends State with WidgetsBindingObserver {
}
void goToSettingsProfile() {
- context.go('/rooms/profile');
+ context.go(AppRoutePaths.profileFull);
}
void onContactTap(ContactPresentationSearch contactPresentationSearch) {
diff --git a/lib/pages/settings_dashboard/settings/settings.dart b/lib/pages/settings_dashboard/settings/settings.dart
index d6066aeb39..c8e36a43fe 100644
--- a/lib/pages/settings_dashboard/settings/settings.dart
+++ b/lib/pages/settings_dashboard/settings/settings.dart
@@ -1,26 +1,25 @@
import 'dart:async';
+import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:fluffychat/config/app_config.dart';
+import 'package:fluffychat/config/go_routes/app_route_paths.dart';
import 'package:fluffychat/di/global/get_it_initializer.dart';
import 'package:fluffychat/domain/model/extensions/common_settings/common_settings_extensions.dart';
import 'package:fluffychat/domain/model/extensions/homeserver_summary_extensions.dart';
import 'package:fluffychat/domain/repository/federation_configurations_repository.dart';
import 'package:fluffychat/domain/repository/tom_configurations_repository.dart';
import 'package:fluffychat/event/twake_inapp_event_types.dart';
+import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:fluffychat/pages/bootstrap/bootstrap_dialog.dart';
-import 'package:fluffychat/presentation/mixins/connect_page_mixin.dart';
import 'package:fluffychat/presentation/enum/settings/settings_enum.dart';
import 'package:fluffychat/presentation/extensions/client_extension.dart';
+import 'package:fluffychat/presentation/mixins/connect_page_mixin.dart';
import 'package:fluffychat/utils/dialog/twake_dialog.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/utils/url_launcher.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:fluffychat/widgets/twake_app.dart';
import 'package:flutter/material.dart';
-
-import 'package:adaptive_dialog/adaptive_dialog.dart';
-import 'package:fluffychat/generated/l10n/app_localizations.dart';
-
import 'package:go_router/go_router.dart';
import 'package:linagora_design_flutter/linagora_design_flutter.dart';
import 'package:matrix/matrix.dart';
@@ -81,13 +80,14 @@ class SettingsController extends State with ConnectPageMixin {
if (twakeContext == null) {
Logs().e('SettingsController()::logoutAction - Twake context is null');
}
+ final l10n = L10n.of(context)!;
if (await showConfirmAlertDialog(
useRootNavigator: false,
context: twakeContext!,
- title: L10n.of(context)!.areYouSureYouWantToLogout,
- message: L10n.of(context)!.logoutDialogWarning,
- okLabel: L10n.of(context)!.logout,
- cancelLabel: L10n.of(context)!.cancel,
+ title: l10n.areYouSureYouWantToLogout,
+ message: l10n.logoutDialogWarning,
+ okLabel: l10n.logout,
+ cancelLabel: l10n.cancel,
) ==
ConfirmResult.cancel) {
return;
@@ -199,12 +199,13 @@ class SettingsController extends State with ConnectPageMixin {
}
void firstRunBootstrapAction([_]) async {
+ final l10n = L10n.of(context)!;
if (showChatBackupSwitch.value != true) {
showOkAlertDialog(
context: context,
- title: L10n.of(context)!.chatBackup,
- message: L10n.of(context)!.onlineKeyBackupEnabled,
- okLabel: L10n.of(context)!.close,
+ title: l10n.chatBackup,
+ message: l10n.onlineKeyBackupEnabled,
+ okLabel: l10n.close,
);
return;
}
@@ -214,7 +215,7 @@ class SettingsController extends State with ConnectPageMixin {
void goToSettingsProfile() async {
optionsSelectNotifier.value = SettingEnum.profile;
- final result = await context.push('/rooms/profile');
+ final result = await context.push(AppRoutePaths.profileFull);
if (result == null) {
optionsSelectNotifier.value = null;
}
@@ -224,19 +225,19 @@ class SettingsController extends State with ConnectPageMixin {
optionsSelectNotifier.value = settingEnum;
switch (settingEnum) {
case SettingEnum.chatSettings:
- final result = await context.push('/rooms/chat');
+ final result = await context.push(AppRoutePaths.chatFull);
if (result == null) {
optionsSelectNotifier.value = null;
}
break;
case SettingEnum.privacyAndSecurity:
- final result = await context.push('/rooms/security');
+ final result = await context.push(AppRoutePaths.roomsSecurityFull);
if (result == null) {
optionsSelectNotifier.value = null;
}
break;
case SettingEnum.notificationAndSounds:
- final result = await context.push('/rooms/notifications');
+ final result = await context.push(AppRoutePaths.notificationsFull);
if (result == null) {
optionsSelectNotifier.value = null;
}
@@ -244,13 +245,13 @@ class SettingsController extends State with ConnectPageMixin {
case SettingEnum.chatFolders:
break;
case SettingEnum.appLanguage:
- final result = await context.push('/rooms/appLanguage');
+ final result = await context.push(AppRoutePaths.appLanguageFull);
if (result == null) {
optionsSelectNotifier.value = null;
}
break;
case SettingEnum.devices:
- final result = await context.push('/rooms/devices');
+ final result = await context.push(AppRoutePaths.devicesFull);
if (result == null) {
optionsSelectNotifier.value = null;
}
@@ -277,17 +278,22 @@ class SettingsController extends State with ConnectPageMixin {
launchUrl(Uri.parse(commonSettingsUrl), webOnlyWindowName: '_blank');
return;
}
+
+ final l10n = L10n.of(context)!;
+ final sysColor = LinagoraSysColors.material();
+ final primaryColor = sysColor.primary;
+
if (await showConfirmAlertDialog(
useRootNavigator: false,
context: context,
- title: L10n.of(context)!.areYouSureYouWantToDeleteAccount,
- message: L10n.of(context)!.deleteAccountMessage,
- okLabel: L10n.of(context)!.continueProcess,
+ title: l10n.areYouSureYouWantToDeleteAccount,
+ message: l10n.deleteAccountMessage,
+ okLabel: l10n.continueProcess,
okLabelButtonColor: Colors.transparent,
- okTextColor: LinagoraSysColors.material().primary,
- cancelLabel: L10n.of(context)!.deleteLater,
- cancelLabelButtonColor: LinagoraSysColors.material().primary,
- cancelTextColor: LinagoraSysColors.material().onPrimary,
+ okTextColor: primaryColor,
+ cancelLabel: l10n.deleteLater,
+ cancelLabelButtonColor: primaryColor,
+ cancelTextColor: sysColor.onPrimary,
) ==
ConfirmResult.cancel) {
return;
diff --git a/lib/pages/settings_dashboard/settings/settings_item_builder.dart b/lib/pages/settings_dashboard/settings/settings_item_builder.dart
index 5de47e3bd0..7a5bed2836 100644
--- a/lib/pages/settings_dashboard/settings/settings_item_builder.dart
+++ b/lib/pages/settings_dashboard/settings/settings_item_builder.dart
@@ -36,6 +36,10 @@ class SettingsItemBuilder extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ final textStyle = LinagoraTextStyle.material();
+ final tertiary30 = LinagoraRefColors.material().tertiary[30];
+ const fontFamily = 'Inter';
+
return TwakeInkWell(
isSelected: isSelected,
onTap: onTap,
@@ -45,7 +49,7 @@ class SettingsItemBuilder extends StatelessWidget {
child: Padding(
padding: SettingsViewStyle.itemBuilderPadding,
child: Row(
- crossAxisAlignment: CrossAxisAlignment.center,
+ crossAxisAlignment: .center,
children: [
Padding(
padding: SettingsViewStyle.leadingItemBuilderPadding,
@@ -59,22 +63,21 @@ class SettingsItemBuilder extends StatelessWidget {
),
Expanded(
child: Row(
- crossAxisAlignment: CrossAxisAlignment.center,
+ crossAxisAlignment: .center,
children: [
Expanded(
child: Column(
- mainAxisSize: MainAxisSize.min,
- crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisSize: .min,
+ crossAxisAlignment: .start,
children: [
Text(
title,
- style: LinagoraTextStyle.material().bodyMedium2
- .copyWith(
- color: titleColor,
- fontFamily: 'Inter',
- ),
+ style: textStyle.bodyMedium2.copyWith(
+ color: titleColor,
+ fontFamily: fontFamily,
+ ),
maxLines: 2,
- overflow: TextOverflow.ellipsis,
+ overflow: .ellipsis,
),
if (subtitle != null)
Padding(
@@ -83,27 +86,24 @@ class SettingsItemBuilder extends StatelessWidget {
subtitle!,
style:
subtitleStyle ??
- LinagoraTextStyle.material().bodyMedium
- .copyWith(
- color:
- subtitleColor ??
- LinagoraRefColors.material()
- .tertiary[30],
- fontFamily: 'Inter',
- ),
- overflow: TextOverflow.ellipsis,
+ textStyle.bodyMedium.copyWith(
+ color: subtitleColor ?? tertiary30,
+ fontFamily: fontFamily,
+ ),
+ overflow: .ellipsis,
),
),
],
),
),
- if (!isHideTrailingIcon)
- trailingWidget ??
- Icon(
- Icons.chevron_right_outlined,
- size: SettingsViewStyle.iconSize,
- color: LinagoraRefColors.material().tertiary[30],
- ),
+ if (trailingWidget != null)
+ trailingWidget!
+ else if (!isHideTrailingIcon)
+ Icon(
+ Icons.chevron_right_outlined,
+ size: SettingsViewStyle.iconSize,
+ color: tertiary30,
+ ),
],
),
),
diff --git a/lib/pages/settings_dashboard/settings/settings_view.dart b/lib/pages/settings_dashboard/settings/settings_view.dart
index 03c60c7aa6..4f6ad00ee4 100644
--- a/lib/pages/settings_dashboard/settings/settings_view.dart
+++ b/lib/pages/settings_dashboard/settings/settings_view.dart
@@ -22,10 +22,18 @@ class SettingsView extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ final l10n = L10n.of(context)!;
+ final sysColor = LinagoraSysColors.material();
+ final refColorTertiary30 = LinagoraRefColors.material().tertiary[30];
+ final theme = Theme.of(context);
+ final appbarTheme = theme.appBarTheme;
+ final textTheme = theme.textTheme;
+ final colorScheme = theme.colorScheme;
+
return Scaffold(
- backgroundColor: LinagoraSysColors.material().onPrimary,
+ backgroundColor: sysColor.onPrimary,
appBar: TwakeAppBar(
- title: L10n.of(context)!.settings,
+ title: l10n.settings,
withDivider: responsiveUtils.isMobile(context),
context: context,
),
@@ -33,24 +41,22 @@ class SettingsView extends StatelessWidget {
body: ListTileTheme(
// TODO: change to colorSurface when its approved
// ignore: deprecated_member_use
- iconColor: Theme.of(context).colorScheme.onBackground,
+ iconColor: colorScheme.onBackground,
child: ListView(
key: const Key('SettingsListViewContent'),
children: [
Padding(
padding: SettingsViewStyle.bodySettingsScreenPadding,
child: Material(
- borderRadius: BorderRadius.circular(
- SettingsViewStyle.borderRadius,
- ),
- clipBehavior: Clip.hardEdge,
+ borderRadius: .circular(SettingsViewStyle.borderRadius),
+ clipBehavior: .hardEdge,
color:
controller.optionsSelectNotifier.value ==
SettingEnum.profile
- ? Theme.of(context).colorScheme.secondaryContainer
- : LinagoraSysColors.material().onPrimary,
+ ? colorScheme.secondaryContainer
+ : sysColor.onPrimary,
child: InkWell(
- onTap: () => controller.goToSettingsProfile(),
+ onTap: controller.goToSettingsProfile,
child: Padding(
padding: SettingsViewStyle.itemBuilderPadding,
child: Row(
@@ -62,18 +68,11 @@ class SettingsView extends StatelessWidget {
padding: SettingsViewStyle.avatarPadding,
child: Material(
elevation:
- Theme.of(
- context,
- ).appBarTheme.scrolledUnderElevation ??
- 4,
- shadowColor: Theme.of(
- context,
- ).appBarTheme.shadowColor,
+ appbarTheme.scrolledUnderElevation ?? 4,
+ shadowColor: appbarTheme.shadowColor,
shape: RoundedRectangleBorder(
- side: BorderSide(
- color: Theme.of(context).dividerColor,
- ),
- borderRadius: BorderRadius.circular(
+ side: BorderSide(color: theme.dividerColor),
+ borderRadius: .circular(
AvatarStyle.defaultSize,
),
),
@@ -89,12 +88,12 @@ class SettingsView extends StatelessWidget {
),
Expanded(
child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ mainAxisAlignment: .spaceBetween,
children: [
Expanded(
child: Column(
- mainAxisAlignment: MainAxisAlignment.center,
- crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: .center,
+ crossAxisAlignment: .start,
children: [
ValueListenableBuilder(
valueListenable:
@@ -102,14 +101,9 @@ class SettingsView extends StatelessWidget {
builder: (context, displayName, _) {
return Text(
displayName ?? controller.displayName,
- style: Theme.of(context)
- .textTheme
- .titleLarge
- ?.copyWith(
- color: Theme.of(
- context,
- ).colorScheme.onSurface,
- ),
+ style: textTheme.titleLarge?.copyWith(
+ color: colorScheme.onSurface,
+ ),
maxLines: 1,
overflow: TextOverflow.ellipsis,
);
@@ -117,13 +111,9 @@ class SettingsView extends StatelessWidget {
),
Text(
controller.client.mxid(context),
- style: Theme.of(context)
- .textTheme
- .labelLarge
- ?.copyWith(
- color: LinagoraRefColors.material()
- .tertiary[30],
- ),
+ style: textTheme.labelLarge?.copyWith(
+ color: refColorTertiary30,
+ ),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
@@ -133,8 +123,7 @@ class SettingsView extends StatelessWidget {
Icon(
Icons.chevron_right_outlined,
size: SettingsViewStyle.iconSize,
- color:
- LinagoraRefColors.material().tertiary[30],
+ color: refColorTertiary30,
),
],
),
@@ -148,34 +137,32 @@ class SettingsView extends StatelessWidget {
Padding(
padding: SettingsViewStyle.profileItemDividerPadding(context),
child: Divider(
- color: LinagoraStateLayer(
- LinagoraSysColors.material().surfaceTint,
- ).opacityLayer3,
- thickness: SettingsViewStyle.settingsItemDividerThikness,
+ color: LinagoraStateLayer(sysColor.surfaceTint).opacityLayer3,
+ thickness: SettingsViewStyle.settingsItemDividerThickness,
height: SettingsViewStyle.settingsItemDividerHeight,
),
),
if (!controller.matrix.twakeSupported)
ValueListenableBuilder(
valueListenable: controller.showChatBackupSwitch,
- builder: (context, backUpAvailable, child) {
+ builder: (_, backUpAvailable, _) {
return SwitchListTile(
- controlAffinity: ListTileControlAffinity.trailing,
+ controlAffinity: .trailing,
contentPadding: SettingsViewStyle.backupSwitchPadding,
value: backUpAvailable == false,
secondary: const Icon(Icons.backup_outlined),
- title: Text(L10n.of(context)!.chatBackup),
+ title: Text(l10n.chatBackup),
onChanged: controller.firstRunBootstrapAction,
);
},
child: ListTile(
leading: const Icon(Icons.backup_outlined),
- title: Text(L10n.of(context)!.chatBackup),
+ title: Text(l10n.chatBackup),
trailing: const CircularProgressIndicator.adaptive(),
),
),
Column(
- children: controller.getListSettingItem.map((item) {
+ children: controller.getListSettingItem.map((SettingEnum item) {
return Column(
children: [
Padding(
@@ -198,10 +185,10 @@ class SettingsView extends StatelessWidget {
SettingsViewStyle.settingsItemDividerPadding(),
child: Divider(
color: LinagoraStateLayer(
- LinagoraSysColors.material().surfaceTint,
+ sysColor.surfaceTint,
).opacityLayer3,
- thickness:
- SettingsViewStyle.settingsItemDividerThikness,
+ thickness: SettingsViewStyle
+ .settingsItemDividerThickness,
height:
SettingsViewStyle.settingsItemDividerHeight,
),
diff --git a/lib/pages/settings_dashboard/settings/settings_view_style.dart b/lib/pages/settings_dashboard/settings/settings_view_style.dart
index f2c75c2d86..5432fe833d 100644
--- a/lib/pages/settings_dashboard/settings/settings_view_style.dart
+++ b/lib/pages/settings_dashboard/settings/settings_view_style.dart
@@ -31,7 +31,7 @@ class SettingsViewStyle {
static const double borderRadius = 4.0;
static const double settingsItemDividerHeight = 1.0;
- static const double settingsItemDividerThikness = 1;
+ static const double settingsItemDividerThickness = 1;
static EdgeInsets settingsItemDividerPadding() =>
const EdgeInsets.only(left: 48.0, right: 8.0);
diff --git a/lib/pages/settings_dashboard/settings_3pid/settings_3pid.dart b/lib/pages/settings_dashboard/settings_3pid/settings_3pid.dart
index 59419da85f..5bdc6d222f 100644
--- a/lib/pages/settings_dashboard/settings_3pid/settings_3pid.dart
+++ b/lib/pages/settings_dashboard/settings_3pid/settings_3pid.dart
@@ -1,12 +1,10 @@
-import 'package:fluffychat/utils/dialog/twake_dialog.dart';
-import 'package:flutter/material.dart';
-
import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:fluffychat/generated/l10n/app_localizations.dart';
-
+import 'package:fluffychat/utils/dialog/twake_dialog.dart';
+import 'package:fluffychat/widgets/matrix.dart';
+import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
-import 'package:fluffychat/widgets/matrix.dart';
import 'settings_3pid_view.dart';
class Settings3Pid extends StatefulWidget {
@@ -20,16 +18,18 @@ class Settings3Pid extends StatefulWidget {
class Settings3PidController extends State {
void add3PidAction() async {
+ final l10n = L10n.of(context)!;
+
final input = await showTextInputDialog(
useRootNavigator: false,
context: context,
- title: L10n.of(context)!.enterAnEmailAddress,
- okLabel: L10n.of(context)!.ok,
- cancelLabel: L10n.of(context)!.cancel,
+ title: l10n.enterAnEmailAddress,
+ okLabel: l10n.ok,
+ cancelLabel: l10n.cancel,
textFields: [
DialogTextField(
- hintText: L10n.of(context)!.enterAnEmailAddress,
- keyboardType: TextInputType.emailAddress,
+ hintText: l10n.enterAnEmailAddress,
+ keyboardType: .emailAddress,
),
],
);
@@ -46,9 +46,9 @@ class Settings3PidController extends State {
final ok = await showOkAlertDialog(
useRootNavigator: false,
context: context,
- title: L10n.of(context)!.weSentYouAnEmail,
- message: L10n.of(context)!.pleaseClickOnLink,
- okLabel: L10n.of(context)!.iHaveClickedOnLink,
+ title: l10n.weSentYouAnEmail,
+ message: l10n.pleaseClickOnLink,
+ okLabel: l10n.iHaveClickedOnLink,
);
if (ok != OkCancelResult.ok) return;
final success = await TwakeDialog.showFutureLoadingDialogFullScreen(
@@ -65,12 +65,13 @@ class Settings3PidController extends State {
Future?>? request;
void delete3Pid(ThirdPartyIdentifier identifier) async {
+ final l10n = L10n.of(context)!;
if (await showOkCancelAlertDialog(
useRootNavigator: false,
context: context,
- title: L10n.of(context)!.areYouSure,
- okLabel: L10n.of(context)!.yes,
- cancelLabel: L10n.of(context)!.cancel,
+ title: l10n.areYouSure,
+ okLabel: l10n.yes,
+ cancelLabel: l10n.cancel,
) !=
OkCancelResult.ok) {
return;
diff --git a/lib/pages/settings_dashboard/settings_3pid/settings_3pid_view.dart b/lib/pages/settings_dashboard/settings_3pid/settings_3pid_view.dart
index 98ecf97751..707b6803e5 100644
--- a/lib/pages/settings_dashboard/settings_3pid/settings_3pid_view.dart
+++ b/lib/pages/settings_dashboard/settings_3pid/settings_3pid_view.dart
@@ -1,14 +1,12 @@
+import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:fluffychat/pages/settings_dashboard/settings_3pid/settings_3pid.dart';
import 'package:fluffychat/widgets/app_bars/twake_app_bar.dart';
+import 'package:fluffychat/widgets/layouts/max_width_body.dart';
+import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/material.dart';
-
-import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:linagora_design_flutter/linagora_design_flutter.dart';
import 'package:matrix/matrix.dart';
-import 'package:fluffychat/widgets/layouts/max_width_body.dart';
-import 'package:fluffychat/widgets/matrix.dart';
-
class Settings3PidView extends StatelessWidget {
final Settings3PidController controller;
@@ -17,15 +15,18 @@ class Settings3PidView extends StatelessWidget {
@override
Widget build(BuildContext context) {
controller.request ??= Matrix.of(context).client.getAccount3PIDs();
+ final l10n = L10n.of(context)!;
+ final bgColor = Theme.of(context).scaffoldBackgroundColor;
+
return Scaffold(
backgroundColor: LinagoraSysColors.material().onPrimary,
appBar: TwakeAppBar(
- title: L10n.of(context)!.passwordRecovery,
+ title: l10n.passwordRecovery,
actions: [
IconButton(
icon: const Icon(Icons.add_outlined),
onPressed: controller.add3PidAction,
- tooltip: L10n.of(context)!.addEmail,
+ tooltip: l10n.addEmail,
),
],
context: context,
@@ -33,75 +34,61 @@ class Settings3PidView extends StatelessWidget {
body: MaxWidthBody(
child: FutureBuilder?>(
future: controller.request,
- builder:
- (
- BuildContext context,
- AsyncSnapshot?> snapshot,
- ) {
- if (snapshot.hasError) {
- return Center(
- child: Text(
- snapshot.error.toString(),
- textAlign: TextAlign.center,
+ builder: (_, AsyncSnapshot?> snapshot) {
+ if (snapshot.hasError) {
+ return Center(
+ child: Text(snapshot.error.toString(), textAlign: .center),
+ );
+ }
+ if (!snapshot.hasData) {
+ return const Center(
+ child: CircularProgressIndicator.adaptive(strokeWidth: 2),
+ );
+ }
+ final identifier = snapshot.data!;
+ return Column(
+ children: [
+ ListTile(
+ leading: CircleAvatar(
+ backgroundColor: bgColor,
+ foregroundColor: identifier.isEmpty
+ ? Colors.orange
+ : Colors.grey,
+ child: Icon(
+ identifier.isEmpty
+ ? Icons.warning_outlined
+ : Icons.info_outlined,
),
- );
- }
- if (!snapshot.hasData) {
- return const Center(
- child: CircularProgressIndicator.adaptive(strokeWidth: 2),
- );
- }
- final identifier = snapshot.data!;
- return Column(
- children: [
- ListTile(
+ ),
+ title: Text(
+ identifier.isEmpty
+ ? l10n.noPasswordRecoveryDescription
+ : l10n.withTheseAddressesRecoveryDescription,
+ ),
+ ),
+ const Divider(height: 1),
+ Expanded(
+ child: ListView.builder(
+ itemCount: identifier.length,
+ itemBuilder: (_, int i) => ListTile(
leading: CircleAvatar(
- backgroundColor: Theme.of(
- context,
- ).scaffoldBackgroundColor,
- foregroundColor: identifier.isEmpty
- ? Colors.orange
- : Colors.grey,
- child: Icon(
- identifier.isEmpty
- ? Icons.warning_outlined
- : Icons.info_outlined,
- ),
+ backgroundColor: bgColor,
+ foregroundColor: Colors.grey,
+ child: Icon(identifier[i].iconData),
),
- title: Text(
- identifier.isEmpty
- ? L10n.of(context)!.noPasswordRecoveryDescription
- : L10n.of(
- context,
- )!.withTheseAddressesRecoveryDescription,
- ),
- ),
- const Divider(height: 1),
- Expanded(
- child: ListView.builder(
- itemCount: identifier.length,
- itemBuilder: (BuildContext context, int i) => ListTile(
- leading: CircleAvatar(
- backgroundColor: Theme.of(
- context,
- ).scaffoldBackgroundColor,
- foregroundColor: Colors.grey,
- child: Icon(identifier[i].iconData),
- ),
- title: Text(identifier[i].address),
- trailing: IconButton(
- tooltip: L10n.of(context)!.delete,
- icon: const Icon(Icons.delete_forever_outlined),
- color: Colors.red,
- onPressed: () =>
- controller.delete3Pid(identifier[i]),
- ),
- ),
+ title: Text(identifier[i].address),
+ trailing: IconButton(
+ tooltip: l10n.delete,
+ icon: const Icon(Icons.delete_forever_outlined),
+ color: Colors.red,
+ onPressed: () => controller.delete3Pid(identifier[i]),
),
),
- ],
- );
- },
+ ),
+ ),
+ ],
+ );
+ },
),
),
);
@@ -111,9 +98,9 @@ class Settings3PidView extends StatelessWidget {
extension on ThirdPartyIdentifier {
IconData get iconData {
switch (medium) {
- case ThirdPartyIdentifierMedium.email:
+ case .email:
return Icons.mail_outline_rounded;
- case ThirdPartyIdentifierMedium.msisdn:
+ case .msisdn:
return Icons.phone_android_outlined;
}
}
diff --git a/lib/pages/settings_dashboard/settings_app_language/settings_app_language_view.dart b/lib/pages/settings_dashboard/settings_app_language/settings_app_language_view.dart
index b3e1c22868..21beab6d40 100644
--- a/lib/pages/settings_dashboard/settings_app_language/settings_app_language_view.dart
+++ b/lib/pages/settings_dashboard/settings_app_language/settings_app_language_view.dart
@@ -1,4 +1,5 @@
import 'package:fluffychat/di/global/get_it_initializer.dart';
+import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:fluffychat/pages/settings_dashboard/settings_app_language/settings_app_language.dart';
import 'package:fluffychat/pages/settings_dashboard/settings_app_language/settings_app_language_view_style.dart';
import 'package:fluffychat/presentation/extensions/localizations/locale_extension.dart';
@@ -7,7 +8,6 @@ import 'package:fluffychat/utils/responsive/responsive_utils.dart';
import 'package:fluffychat/widgets/app_bars/twake_app_bar.dart';
import 'package:fluffychat/widgets/app_bars/twake_app_bar_style.dart';
import 'package:flutter/material.dart';
-import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:go_router/go_router.dart';
import 'package:linagora_design_flutter/linagora_design_flutter.dart';
@@ -19,18 +19,21 @@ class SettingsAppLanguageView extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ final l10n = L10n.of(context)!;
+ final textTheme = Theme.of(context).textTheme;
+
return Scaffold(
backgroundColor: LinagoraSysColors.material().onPrimary,
appBar: TwakeAppBar(
- title: L10n.of(context)!.appLanguage,
+ title: l10n.appLanguage,
context: context,
leading: responsiveUtils.isMobile(context)
? Padding(
padding: TwakeAppBarStyle.leadingIconPadding,
child: IconButton(
- tooltip: L10n.of(context)!.back,
+ tooltip: l10n.back,
icon: const Icon(Icons.arrow_back_ios),
- onPressed: () => context.pop(),
+ onPressed: context.pop,
iconSize: TwakeAppBarStyle.leadingIconSize,
),
)
@@ -42,15 +45,15 @@ class SettingsAppLanguageView extends StatelessWidget {
padding: SettingsAppLanguageViewStyle.paddingBody,
physics: const ClampingScrollPhysics(),
child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
+ crossAxisAlignment: .start,
children: [
ListView.separated(
padding: SettingsAppLanguageViewStyle.paddingListItems,
shrinkWrap: true,
- itemBuilder: (context, index) {
+ itemBuilder: (_, int index) {
return ValueListenableBuilder(
valueListenable: controller.currentLocale,
- builder: (context, locale, child) {
+ builder: (context, locale, _) {
return ListTile(
splashColor: Colors.transparent,
shape: RoundedRectangleBorder(
@@ -62,12 +65,12 @@ class SettingsAppLanguageView extends StatelessWidget {
controller.supportedLocales[index]
.getLanguageNameByCurrentLocale(context)
.capitalize(),
- style: Theme.of(context).textTheme.titleMedium,
+ style: textTheme.titleMedium,
),
subtitle: Text(
controller.supportedLocales[index]
.getSourceLanguageName(),
- style: Theme.of(context).textTheme.bodySmall!.copyWith(
+ style: textTheme.bodySmall!.copyWith(
color: LinagoraRefColors.material().neutral[40],
),
),
@@ -89,7 +92,7 @@ class SettingsAppLanguageView extends StatelessWidget {
},
);
},
- separatorBuilder: (context, index) => const Divider(),
+ separatorBuilder: (_, _) => const Divider(),
itemCount: controller.supportedLocales.length,
),
],
diff --git a/lib/pages/settings_dashboard/settings_blocked_users/settings_blocked_user.dart b/lib/pages/settings_dashboard/settings_blocked_users/settings_blocked_user.dart
index 50af4cc6a6..61093c8f51 100644
--- a/lib/pages/settings_dashboard/settings_blocked_users/settings_blocked_user.dart
+++ b/lib/pages/settings_dashboard/settings_blocked_users/settings_blocked_user.dart
@@ -1,5 +1,9 @@
import 'dart:async';
+import 'package:dartz/dartz.dart' hide State;
+import 'package:fluffychat/app_state/failure.dart';
+import 'package:fluffychat/app_state/success.dart';
+import 'package:fluffychat/config/go_routes/app_route_paths.dart';
import 'package:fluffychat/di/global/get_it_initializer.dart';
import 'package:fluffychat/pages/search/search_debouncer_mixin.dart';
import 'package:fluffychat/pages/settings_dashboard/settings_blocked_users/settings_blocked_users_search_state.dart';
@@ -8,11 +12,9 @@ import 'package:fluffychat/utils/dialog/twake_dialog.dart';
import 'package:fluffychat/utils/responsive/responsive_utils.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/material.dart';
-import 'package:dartz/dartz.dart' hide State;
-import 'package:fluffychat/app_state/failure.dart';
-import 'package:fluffychat/app_state/success.dart';
import 'package:go_router/go_router.dart';
import 'package:matrix/matrix.dart';
+
import 'settings_blocked_users_view.dart';
class BlockedUsers extends StatefulWidget {
@@ -36,15 +38,14 @@ class SettingsIgnoreListController extends State
final inputFocus = FocusNode();
- final ValueNotifier> searchUserResults =
- ValueNotifier>(
- Right(BlockedUsersSearchInitialState()),
- );
+ final searchUserResults = ValueNotifier>(
+ Right(BlockedUsersSearchInitialState()),
+ );
final List blockedUsers = [];
void onBack() {
- context.go('/rooms/security');
+ context.go(AppRoutePaths.roomsSecurityFull);
}
Future initialBlockedUsers() async {
diff --git a/lib/pages/settings_dashboard/settings_blocked_users/settings_blocked_users_view.dart b/lib/pages/settings_dashboard/settings_blocked_users/settings_blocked_users_view.dart
index 66cf28cd53..9533e14d01 100644
--- a/lib/pages/settings_dashboard/settings_blocked_users/settings_blocked_users_view.dart
+++ b/lib/pages/settings_dashboard/settings_blocked_users/settings_blocked_users_view.dart
@@ -1,3 +1,4 @@
+import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:fluffychat/pages/chat_list/chat_list_header_style.dart';
import 'package:fluffychat/pages/settings_dashboard/settings_blocked_users/settings_blocked_users_search_state.dart';
import 'package:fluffychat/presentation/model/contact/presentation_contact_constant.dart';
@@ -10,10 +11,10 @@ import 'package:fluffychat/widgets/matrix.dart';
import 'package:fluffychat/widgets/search/empty_search_widget.dart';
import 'package:fluffychat/widgets/twake_components/twake_icon_button.dart';
import 'package:flutter/material.dart';
-import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:go_router/go_router.dart';
import 'package:linagora_design_flutter/linagora_design_flutter.dart';
import 'package:matrix/matrix.dart';
+
import 'settings_blocked_user.dart';
class SettingsBlockedUsersView extends StatelessWidget {
@@ -23,11 +24,14 @@ class SettingsBlockedUsersView extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ final l10n = L10n.of(context)!;
+ final tertiaryColor = LinagoraSysColors.material().tertiary;
+
return Scaffold(
backgroundColor: LinagoraSysColors.material().onPrimary,
resizeToAvoidBottomInset: false,
appBar: TwakeAppBar(
- title: L10n.of(context)!.blockedUsers,
+ title: l10n.blockedUsers,
centerTitle: true,
withDivider: true,
context: context,
@@ -48,27 +52,25 @@ class SettingsBlockedUsersView extends StatelessWidget {
child: Column(
children: [
Padding(
- padding: const EdgeInsets.all(16.0),
+ padding: const .all(16.0),
child: TextField(
controller: controller.textEditingController,
contextMenuBuilder: mobileTwakeContextMenuBuilder,
focusNode: controller.inputFocus,
- textInputAction: TextInputAction.search,
+ textInputAction: .search,
autofocus: true,
decoration:
ChatListHeaderStyle.searchInputDecoration(
context,
- prefixIconColor: LinagoraSysColors.material().tertiary,
+ prefixIconColor: tertiaryColor,
).copyWith(
- hintStyle: Theme.of(context).textTheme.titleMedium
- ?.copyWith(
- color: LinagoraSysColors.material().tertiary,
- ),
- hintText: L10n.of(context)!.enterAnEmailAddress,
+ hintStyle: Theme.of(
+ context,
+ ).textTheme.titleMedium?.copyWith(color: tertiaryColor),
+ hintText: l10n.enterAnEmailAddress,
suffixIcon: ValueListenableBuilder(
valueListenable: controller.textEditingController,
- builder: (context, value, child) =>
- value.text.isNotEmpty
+ builder: (_, value, _) => value.text.isNotEmpty
? IconButton(
onPressed: () {
controller.textEditingController.clear();
@@ -82,7 +84,7 @@ class SettingsBlockedUsersView extends StatelessWidget {
),
ValueListenableBuilder(
valueListenable: controller.searchUserResults,
- builder: (context, searchResults, child) {
+ builder: (_, searchResults, _) {
return searchResults.fold(
(failure) {
if (failure is BlockedUsersSearchEmptyState) {
@@ -96,7 +98,7 @@ class SettingsBlockedUsersView extends StatelessWidget {
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: success.blockedUsers.length,
- padding: const EdgeInsets.symmetric(horizontal: 12.0),
+ padding: const .symmetric(horizontal: 12.0),
itemBuilder: (context, index) {
final profile = success.blockedUsers[index];
@@ -130,11 +132,11 @@ class SettingsBlockedUsersView extends StatelessWidget {
}) {
return TwakeInkWell(
onTap: () {
- final roomId = Matrix.of(
- context,
- ).client.getDirectChatFromUserId(profile.userId);
+ final client = Matrix.of(context).client;
+ final roomId = client.getDirectChatFromUserId(profile.userId);
+
if (roomId == null) {
- if (profile.userId != Matrix.of(context).client.userID) {
+ if (profile.userId != client.userID) {
Router.neglect(
context,
() => context.go(
@@ -157,7 +159,7 @@ class SettingsBlockedUsersView extends StatelessWidget {
}
},
child: TwakeListItem(
- padding: const EdgeInsets.all(8),
+ padding: const .all(8),
child: Row(
children: [
Avatar(
@@ -167,7 +169,7 @@ class SettingsBlockedUsersView extends StatelessWidget {
const SizedBox(width: 8.0),
Expanded(
child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
+ crossAxisAlignment: .start,
children: [
Row(
children: [
diff --git a/lib/pages/settings_dashboard/settings_chat/settings_chat_view.dart b/lib/pages/settings_dashboard/settings_chat/settings_chat_view.dart
index f30dfb2687..4f02618b88 100644
--- a/lib/pages/settings_dashboard/settings_chat/settings_chat_view.dart
+++ b/lib/pages/settings_dashboard/settings_chat/settings_chat_view.dart
@@ -1,7 +1,9 @@
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/di/global/get_it_initializer.dart';
+import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:fluffychat/utils/platform_infos.dart';
+import 'package:fluffychat/utils/responsive/responsive_utils.dart';
import 'package:fluffychat/widgets/app_bars/twake_app_bar.dart';
import 'package:fluffychat/widgets/app_bars/twake_app_bar_style.dart';
import 'package:fluffychat/widgets/layouts/max_width_body.dart';
@@ -9,10 +11,8 @@ import 'package:fluffychat/widgets/matrix.dart';
import 'package:fluffychat/widgets/settings_switch_list_tile.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
-import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:go_router/go_router.dart';
import 'package:linagora_design_flutter/linagora_design_flutter.dart';
-import 'package:fluffychat/utils/responsive/responsive_utils.dart';
import 'settings_chat.dart';
@@ -23,10 +23,13 @@ class SettingsChatView extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ final l10n = L10n.of(context)!;
+ final isWebRTCSupported = Matrix.of(context).webrtcIsSupported;
+
return Scaffold(
backgroundColor: LinagoraSysColors.material().onPrimary,
appBar: TwakeAppBar(
- title: L10n.of(context)!.chat,
+ title: l10n.chat,
context: context,
withDivider: true,
centerTitle: true,
@@ -34,7 +37,7 @@ class SettingsChatView extends StatelessWidget {
? Padding(
padding: TwakeAppBarStyle.leadingIconPadding,
child: IconButton(
- tooltip: L10n.of(context)!.back,
+ tooltip: l10n.back,
icon: const Icon(Icons.arrow_back_ios),
onPressed: () => context.pop(),
iconSize: TwakeAppBarStyle.leadingIconSize,
@@ -49,39 +52,39 @@ class SettingsChatView extends StatelessWidget {
child: Column(
children: [
SettingsSwitchListTile.adaptive(
- title: L10n.of(context)!.renderRichContent,
+ title: l10n.renderRichContent,
onChanged: (b) => AppConfig.renderHtml = b,
storeKey: SettingKeys.renderHtml,
defaultValue: AppConfig.renderHtml,
),
SettingsSwitchListTile.adaptive(
- title: L10n.of(context)!.hideRedactedEvents,
+ title: l10n.hideRedactedEvents,
onChanged: (b) => AppConfig.hideRedactedEvents = b,
storeKey: SettingKeys.hideRedactedEvents,
defaultValue: AppConfig.hideRedactedEvents,
),
SettingsSwitchListTile.adaptive(
- title: L10n.of(context)!.hideUnknownEvents,
+ title: l10n.hideUnknownEvents,
onChanged: (b) => AppConfig.hideUnknownEvents = b,
storeKey: SettingKeys.hideUnknownEvents,
defaultValue: AppConfig.hideUnknownEvents,
),
SettingsSwitchListTile.adaptive(
- title: L10n.of(context)!.hideUnimportantStateEvents,
+ title: l10n.hideUnimportantStateEvents,
onChanged: (b) => AppConfig.hideUnimportantStateEvents = b,
storeKey: SettingKeys.hideUnimportantStateEvents,
defaultValue: AppConfig.hideUnimportantStateEvents,
),
if (PlatformInfos.isMobile)
SettingsSwitchListTile.adaptive(
- title: L10n.of(context)!.autoplayImages,
+ title: l10n.autoplayImages,
onChanged: (b) => AppConfig.autoplayImages = b,
storeKey: SettingKeys.autoplayImages,
defaultValue: AppConfig.autoplayImages,
),
if (!responsive.isMobile(context))
SettingsSwitchListTile.adaptive(
- title: L10n.of(context)!.enableRightAndLeftMessageAlignment,
+ title: l10n.enableRightAndLeftMessageAlignment,
onChanged: (value) =>
AppConfig.enableRightAndLeftMessageAlignmentOnWeb = value,
storeKey: SettingKeys.enableRightAndLeftMessageAlignmentOnWeb,
@@ -89,9 +92,9 @@ class SettingsChatView extends StatelessWidget {
AppConfig.enableRightAndLeftMessageAlignmentOnWeb,
),
const Divider(),
- if (Matrix.of(context).webrtcIsSupported)
+ if (isWebRTCSupported)
SettingsSwitchListTile.adaptive(
- title: L10n.of(context)!.experimentalVideoCalls,
+ title: l10n.experimentalVideoCalls,
onChanged: (b) {
AppConfig.experimentalVoip = b;
Matrix.of(context).createVoipPlugin();
@@ -100,13 +103,11 @@ class SettingsChatView extends StatelessWidget {
storeKey: SettingKeys.experimentalVoip,
defaultValue: AppConfig.experimentalVoip,
),
- if (Matrix.of(context).webrtcIsSupported && !kIsWeb)
+ if (isWebRTCSupported && !kIsWeb)
ListTile(
- title: Text(L10n.of(context)!.callingPermissions),
- // onTap: () =>
- // CallKeepManager().checkoutPhoneAccountSetting(context),
+ title: Text(l10n.callingPermissions),
trailing: const Padding(
- padding: EdgeInsets.all(16.0),
+ padding: .all(16.0),
child: Icon(Icons.call),
),
),
diff --git a/lib/pages/settings_dashboard/settings_contacts_visibility/settings_contacts_visibility.dart b/lib/pages/settings_dashboard/settings_contacts_visibility/settings_contacts_visibility.dart
index 5dcc147f4f..33835dbe6d 100644
--- a/lib/pages/settings_dashboard/settings_contacts_visibility/settings_contacts_visibility.dart
+++ b/lib/pages/settings_dashboard/settings_contacts_visibility/settings_contacts_visibility.dart
@@ -1,7 +1,9 @@
import 'dart:async';
+
import 'package:dartz/dartz.dart' hide State;
import 'package:fluffychat/app_state/failure.dart';
import 'package:fluffychat/app_state/success.dart';
+import 'package:fluffychat/config/go_routes/app_route_paths.dart';
import 'package:fluffychat/di/global/get_it_initializer.dart';
import 'package:fluffychat/domain/app_state/user_info/get_user_info_visibility_state.dart';
import 'package:fluffychat/domain/app_state/user_info/update_user_info_visibility_state.dart';
@@ -9,11 +11,11 @@ import 'package:fluffychat/domain/model/user_info/user_info_visibility.dart';
import 'package:fluffychat/domain/model/user_info/user_info_visibility_request.dart';
import 'package:fluffychat/domain/usecase/user_info/get_user_info_visibility_interactor.dart';
import 'package:fluffychat/domain/usecase/user_info/update_user_info_visibility_interactor.dart';
+import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:fluffychat/pages/settings_dashboard/settings_contacts_visibility/settings_contacts_visibility_enum.dart';
import 'package:fluffychat/pages/settings_dashboard/settings_contacts_visibility/settings_contacts_visibility_view.dart';
import 'package:fluffychat/utils/dialog/twake_dialog.dart';
import 'package:fluffychat/utils/twake_snackbar.dart';
-import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
@@ -32,53 +34,41 @@ class SettingsContactsVisibilityController
Client get client => Matrix.read(context).client;
void onBack() {
- context.go('/rooms/security');
+ context.go(AppRoutePaths.roomsSecurityFull);
}
StreamSubscription? getUserInfoVisibilityStreamSub;
StreamSubscription? updateUserInfoVisibilityStreamSub;
- final getUserInfoVisibilityInteractor = getIt
- .get();
-
- final updateUserInfoVisibilityInteractor = getIt
- .get();
+ final getUserInfoVisibilityNotifier = ValueNotifier>(
+ Right(GettingUserInfoVisibility()),
+ );
- final ValueNotifier> getUserInfoVisibilityNotifier =
+ final updateUserInfoVisibilityNotifier =
ValueNotifier>(
- Right(GettingUserInfoVisibility()),
+ Right(UpdatingUserInfoVisibility()),
);
- final ValueNotifier>
- updateUserInfoVisibilityNotifier = ValueNotifier>(
- Right(UpdatingUserInfoVisibility()),
- );
-
- final List visibilityOptions = [
+ final visibilityOptions = [
SettingsContactsVisibilityEnum.public,
SettingsContactsVisibilityEnum.contacts,
SettingsContactsVisibilityEnum.private,
];
- final List visibleFieldsOptions = [
- VisibleEnum.phone,
- VisibleEnum.email,
- ];
+ final visibleFieldsOptions = [VisibleEnum.phone, VisibleEnum.email];
- final ValueNotifier
- selectedVisibilityOptionNotifier =
+ final selectedVisibilityOptionNotifier =
ValueNotifier(null);
- final ValueNotifier> selectedVisibleFieldNotifier =
- ValueNotifier>([]);
+ final selectedVisibleFieldNotifier = ValueNotifier>([]);
void onSelectVisibilityOption(SettingsContactsVisibilityEnum option) {
if (option == selectedVisibilityOptionNotifier.value) {
return;
}
switch (option) {
- case SettingsContactsVisibilityEnum.private:
+ case .private:
updateUserInfoVisibility(
userInfoVisibility: UserInfoVisibilityRequest(
visibility: option.name,
@@ -86,8 +76,8 @@ class SettingsContactsVisibilityController
),
);
break;
- case SettingsContactsVisibilityEnum.public:
- case SettingsContactsVisibilityEnum.contacts:
+ case .public:
+ case .contacts:
updateUserInfoVisibility(
userInfoVisibility: UserInfoVisibilityRequest(
visibility: option.name,
@@ -120,15 +110,14 @@ class SettingsContactsVisibilityController
void updateUserInfoVisibility({
required UserInfoVisibilityRequest userInfoVisibility,
}) {
+ final l10n = L10n.of(context)!;
if (client.userID == null) {
- TwakeSnackBar.show(
- context,
- L10n.of(context)!.failedToChangeContactsVisibility,
- );
+ TwakeSnackBar.show(context, l10n.failedToChangeContactsVisibility);
return;
}
updateUserInfoVisibilityStreamSub?.cancel();
- updateUserInfoVisibilityStreamSub = updateUserInfoVisibilityInteractor
+ updateUserInfoVisibilityStreamSub = getIt
+ .get()
.execute(userId: client.userID!, body: userInfoVisibility)
.listen((either) {
if (!mounted) return;
@@ -140,7 +129,7 @@ class SettingsContactsVisibilityController
TwakeDialog.hideLoadingDialog(context);
TwakeSnackBar.show(
context,
- L10n.of(context)!.failedToChangeContactsVisibility,
+ l10n.failedToChangeContactsVisibility,
);
}
},
@@ -150,7 +139,7 @@ class SettingsContactsVisibilityController
SettingsContactsVisibilityEnum.values.firstWhere(
(option) =>
option.name == success.userInfoVisibility.visibility,
- orElse: () => SettingsContactsVisibilityEnum.contacts,
+ orElse: () => .contacts,
);
selectedVisibleFieldNotifier.value =
success.userInfoVisibility.visibleFields ?? [];
@@ -170,7 +159,8 @@ class SettingsContactsVisibilityController
return;
}
getUserInfoVisibilityStreamSub?.cancel();
- getUserInfoVisibilityStreamSub = getUserInfoVisibilityInteractor
+ getUserInfoVisibilityStreamSub = getIt
+ .get()
.execute(userId: client.userID!)
.listen((either) {
if (!mounted) return;
@@ -196,7 +186,7 @@ class SettingsContactsVisibilityController
SettingsContactsVisibilityEnum.values.firstWhere(
(option) =>
option.name == success.userInfoVisibility.visibility,
- orElse: () => SettingsContactsVisibilityEnum.contacts,
+ orElse: () => .contacts,
);
selectedVisibleFieldNotifier.value =
success.userInfoVisibility.visibleFields ?? [];
@@ -225,7 +215,7 @@ class SettingsContactsVisibilityController
}
@override
- Widget build(BuildContext context) {
+ Widget build(_) {
return SettingsContactsVisibilityView(controller: this);
}
}
diff --git a/lib/pages/settings_dashboard/settings_contacts_visibility/settings_contacts_visibility_enum.dart b/lib/pages/settings_dashboard/settings_contacts_visibility/settings_contacts_visibility_enum.dart
index cfa7c8327b..d746022278 100644
--- a/lib/pages/settings_dashboard/settings_contacts_visibility/settings_contacts_visibility_enum.dart
+++ b/lib/pages/settings_dashboard/settings_contacts_visibility/settings_contacts_visibility_enum.dart
@@ -7,23 +7,24 @@ enum SettingsContactsVisibilityEnum {
contacts;
String title(BuildContext context) {
+ final l10n = L10n.of(context)!;
switch (this) {
- case SettingsContactsVisibilityEnum.public:
- return L10n.of(context)!.everyOne;
- case SettingsContactsVisibilityEnum.contacts:
- return L10n.of(context)!.myContacts;
- case SettingsContactsVisibilityEnum.private:
- return L10n.of(context)!.nobody;
+ case .public:
+ return l10n.everyOne;
+ case .contacts:
+ return l10n.myContacts;
+ case .private:
+ return l10n.nobody;
}
}
bool enableDivider() {
switch (this) {
- case SettingsContactsVisibilityEnum.public:
+ case .public:
return true;
- case SettingsContactsVisibilityEnum.contacts:
+ case .contacts:
return true;
- case SettingsContactsVisibilityEnum.private:
+ case .private:
return false;
}
}
diff --git a/lib/pages/settings_dashboard/settings_contacts_visibility/settings_contacts_visibility_view.dart b/lib/pages/settings_dashboard/settings_contacts_visibility/settings_contacts_visibility_view.dart
index fb8345baa9..96299d2cc0 100644
--- a/lib/pages/settings_dashboard/settings_contacts_visibility/settings_contacts_visibility_view.dart
+++ b/lib/pages/settings_dashboard/settings_contacts_visibility/settings_contacts_visibility_view.dart
@@ -1,10 +1,10 @@
import 'package:fluffychat/domain/model/user_info/user_info_visibility.dart';
+import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:fluffychat/pages/settings_dashboard/settings_contacts_visibility/settings_contacts_visibility.dart';
import 'package:fluffychat/pages/settings_dashboard/settings_contacts_visibility/settings_contacts_visibility_enum.dart';
import 'package:fluffychat/presentation/extensions/settings/user_info_visibility_extension.dart';
import 'package:fluffychat/widgets/app_bars/twake_app_bar.dart';
import 'package:fluffychat/widgets/layouts/max_width_body.dart';
-import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:fluffychat/widgets/twake_components/twake_icon_button.dart';
import 'package:flutter/material.dart';
import 'package:linagora_design_flutter/linagora_design_flutter.dart';
@@ -16,11 +16,16 @@ class SettingsContactsVisibilityView extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ final l10n = L10n.of(context)!;
+ final sysColor = LinagoraSysColors.material();
+ final refColor90 = LinagoraRefColors.material().neutral[90];
+ final textTheme = Theme.of(context).textTheme;
+
return Scaffold(
- backgroundColor: LinagoraSysColors.material().onPrimary,
+ backgroundColor: sysColor.onPrimary,
resizeToAvoidBottomInset: false,
appBar: TwakeAppBar(
- title: L10n.of(context)!.contactsVisibility,
+ title: l10n.contactsVisibility,
centerTitle: true,
withDivider: true,
context: context,
@@ -40,33 +45,31 @@ class SettingsContactsVisibilityView extends StatelessWidget {
child: SizedBox(
width: double.infinity,
child: Padding(
- padding: const EdgeInsets.symmetric(horizontal: 16),
+ padding: const .symmetric(horizontal: 16),
child: Column(
- mainAxisSize: MainAxisSize.max,
+ mainAxisSize: .max,
children: [
Padding(
- padding: const EdgeInsets.only(
+ padding: const .only(
left: 32,
right: 32,
top: 24,
bottom: 16,
),
child: Text(
- L10n.of(context)!.whoCanSeeMyPhoneEmail,
- style: Theme.of(context).textTheme.bodyMedium?.copyWith(
- color: LinagoraSysColors.material().tertiary,
+ l10n.whoCanSeeMyPhoneEmail,
+ style: textTheme.bodyMedium?.copyWith(
+ color: sysColor.tertiary,
),
- textAlign: TextAlign.center,
+ textAlign: .center,
),
),
Container(
width: double.infinity,
decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(16),
- border: Border.all(
- color:
- LinagoraRefColors.material().neutral[90] ??
- Colors.transparent,
+ borderRadius: .circular(16),
+ border: .all(
+ color: refColor90 ?? Colors.transparent,
width: 1,
),
),
@@ -110,35 +113,30 @@ class SettingsContactsVisibilityView extends StatelessWidget {
SettingsContactsVisibilityEnum.private) {
return const SizedBox.shrink();
}
+
return Column(
children: [
Padding(
- padding: const EdgeInsets.only(
+ padding: const .only(
left: 32,
right: 32,
top: 32,
bottom: 8,
),
child: Text(
- L10n.of(
- context,
- )!.chooseWhichDetailsAreVisibleToOtherUsers,
- style: Theme.of(context).textTheme.bodyMedium
- ?.copyWith(
- color:
- LinagoraSysColors.material().tertiary,
- ),
- textAlign: TextAlign.center,
+ l10n.chooseWhichDetailsAreVisibleToOtherUsers,
+ style: textTheme.bodyMedium?.copyWith(
+ color: sysColor.tertiary,
+ ),
+ textAlign: .center,
),
),
Container(
width: double.infinity,
decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(16),
- border: Border.all(
- color:
- LinagoraRefColors.material().neutral[90] ??
- Colors.transparent,
+ borderRadius: .circular(16),
+ border: .all(
+ color: refColor90 ?? Colors.transparent,
width: 1,
),
),
@@ -189,17 +187,14 @@ class SettingsContactsVisibilityView extends StatelessWidget {
required SettingsContactsVisibilityEnum option,
}) {
switch (option) {
- case SettingsContactsVisibilityEnum.public:
- return const BorderRadius.only(
- topLeft: Radius.circular(16),
- topRight: Radius.circular(16),
- );
- case SettingsContactsVisibilityEnum.contacts:
+ case .public:
+ return const .only(topLeft: .circular(16), topRight: .circular(16));
+ case .contacts:
return null;
- case SettingsContactsVisibilityEnum.private:
- return const BorderRadius.only(
- bottomLeft: Radius.circular(16),
- bottomRight: Radius.circular(16),
+ case .private:
+ return const .only(
+ bottomLeft: .circular(16),
+ bottomRight: .circular(16),
);
}
}
@@ -211,6 +206,8 @@ class SettingsContactsVisibilityView extends StatelessWidget {
bool enableDivider = true,
bool isSelected = false,
}) {
+ final sysColor = LinagoraSysColors.material();
+
return InkWell(
key: Key('visibility_option_${option.name}'),
onTap: () => onTap?.call(option),
@@ -219,19 +216,19 @@ class SettingsContactsVisibilityView extends StatelessWidget {
children: [
Expanded(
child: Column(
- mainAxisAlignment: MainAxisAlignment.spaceAround,
- crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: .spaceAround,
+ crossAxisAlignment: .start,
children: [
Padding(
- padding: const EdgeInsets.all(16),
+ padding: const .all(16),
child: Text(
option.title(context),
style: Theme.of(context).textTheme.titleMedium?.copyWith(
- color: LinagoraSysColors.material().onSurface,
+ color: sysColor.onSurface,
),
- overflow: TextOverflow.ellipsis,
+ overflow: .ellipsis,
maxLines: 1,
- textAlign: TextAlign.center,
+ textAlign: .center,
),
),
if (enableDivider)
@@ -243,7 +240,7 @@ class SettingsContactsVisibilityView extends StatelessWidget {
),
),
Padding(
- padding: const EdgeInsets.only(left: 8, right: 16),
+ padding: const .only(left: 8, right: 16),
child: SizedBox(
width: 24,
height: 24,
@@ -251,7 +248,7 @@ class SettingsContactsVisibilityView extends StatelessWidget {
? Icon(
key: Key('visibility_option_selected_${option.name}'),
Icons.check,
- color: LinagoraSysColors.material().primary,
+ color: sysColor.primary,
size: 24,
)
: null,
@@ -264,15 +261,12 @@ class SettingsContactsVisibilityView extends StatelessWidget {
BorderRadius? _buildVisibleFieldBorderRadius({required VisibleEnum option}) {
switch (option) {
- case VisibleEnum.phone:
- return const BorderRadius.only(
- topLeft: Radius.circular(16),
- topRight: Radius.circular(16),
- );
- case VisibleEnum.email:
- return const BorderRadius.only(
- bottomLeft: Radius.circular(16),
- bottomRight: Radius.circular(16),
+ case .phone:
+ return const .only(topLeft: .circular(16), topRight: .circular(16));
+ case .email:
+ return const .only(
+ bottomLeft: .circular(16),
+ bottomRight: .circular(16),
);
}
}
@@ -284,6 +278,9 @@ class SettingsContactsVisibilityView extends StatelessWidget {
bool enableDivider = true,
bool isSelected = false,
}) {
+ final sysColor = LinagoraSysColors.material();
+ final textTheme = Theme.of(context).textTheme;
+
return InkWell(
key: Key('visible_field_option_${option.name}'),
onTap: () => onTap?.call(option),
@@ -292,33 +289,31 @@ class SettingsContactsVisibilityView extends StatelessWidget {
children: [
Expanded(
child: Column(
- mainAxisAlignment: MainAxisAlignment.spaceAround,
- crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: .spaceAround,
+ crossAxisAlignment: .start,
children: [
Padding(
- padding: const EdgeInsets.all(16),
+ padding: const .all(16),
child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
+ crossAxisAlignment: .start,
children: [
Text(
option.title(context),
- style: Theme.of(context).textTheme.titleMedium
- ?.copyWith(
- color: LinagoraSysColors.material().onSurface,
- ),
- overflow: TextOverflow.ellipsis,
+ style: textTheme.titleMedium?.copyWith(
+ color: sysColor.onSurface,
+ ),
+ overflow: .ellipsis,
maxLines: 1,
- textAlign: TextAlign.center,
+ textAlign: .center,
),
Text(
option.subtitle(context),
- style: Theme.of(context).textTheme.labelMedium
- ?.copyWith(
- color: LinagoraSysColors.material().tertiary,
- ),
- overflow: TextOverflow.ellipsis,
+ style: textTheme.labelMedium?.copyWith(
+ color: sysColor.tertiary,
+ ),
+ overflow: .ellipsis,
maxLines: 2,
- textAlign: TextAlign.left,
+ textAlign: .left,
),
],
),
@@ -332,7 +327,7 @@ class SettingsContactsVisibilityView extends StatelessWidget {
),
),
Padding(
- padding: const EdgeInsets.only(left: 8, right: 16),
+ padding: const .only(left: 8, right: 16),
child: SizedBox(
width: 24,
height: 24,
@@ -340,7 +335,7 @@ class SettingsContactsVisibilityView extends StatelessWidget {
? Icon(
key: Key('visible_field_option_selected_${option.name}'),
Icons.check,
- color: LinagoraSysColors.material().primary,
+ color: sysColor.primary,
size: 24,
)
: null,
diff --git a/lib/pages/settings_dashboard/settings_emotes/settings_emotes.dart b/lib/pages/settings_dashboard/settings_emotes/settings_emotes.dart
index da53065a78..49ff838c1d 100644
--- a/lib/pages/settings_dashboard/settings_emotes/settings_emotes.dart
+++ b/lib/pages/settings_dashboard/settings_emotes/settings_emotes.dart
@@ -1,15 +1,14 @@
+import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:collection/collection.dart';
import 'package:file_picker/file_picker.dart';
+import 'package:fluffychat/generated/l10n/app_localizations.dart';
+import 'package:fluffychat/utils/client_manager.dart';
import 'package:fluffychat/utils/dialog/twake_dialog.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/material.dart';
-
-import 'package:adaptive_dialog/adaptive_dialog.dart';
-import 'package:fluffychat/generated/l10n/app_localizations.dart';
-
import 'package:go_router/go_router.dart';
import 'package:matrix/matrix.dart';
-import 'package:fluffychat/utils/client_manager.dart';
+
import 'settings_emotes_view.dart';
class EmotesSettings extends StatefulWidget {
@@ -121,13 +120,14 @@ class EmotesSettingsController extends State {
ImagePackImageContent image,
TextEditingController controller,
) {
+ final l10n = L10n.of(context)!;
if (pack!.images.keys.any((k) => k == imageCode && k != oldImageCode)) {
controller.text = oldImageCode;
showOkAlertDialog(
useRootNavigator: false,
context: context,
- message: L10n.of(context)!.emoteExists,
- okLabel: L10n.of(context)!.ok,
+ message: l10n.emoteExists,
+ okLabel: l10n.ok,
);
return;
}
@@ -136,8 +136,8 @@ class EmotesSettingsController extends State {
showOkAlertDialog(
useRootNavigator: false,
context: context,
- message: L10n.of(context)!.emoteInvalid,
- okLabel: L10n.of(context)!.ok,
+ message: l10n.emoteInvalid,
+ okLabel: l10n.ok,
);
return;
}
@@ -176,13 +176,15 @@ class EmotesSettingsController extends State {
}
void addImageAction() async {
+ final l10n = L10n.of(context)!;
+
if (newImageCodeController.text.isEmpty ||
newImageController.value == null) {
await showOkAlertDialog(
useRootNavigator: false,
context: context,
- message: L10n.of(context)!.emoteWarnNeedToPick,
- okLabel: L10n.of(context)!.ok,
+ message: l10n.emoteWarnNeedToPick,
+ okLabel: l10n.ok,
);
return;
}
@@ -191,8 +193,8 @@ class EmotesSettingsController extends State {
await showOkAlertDialog(
useRootNavigator: false,
context: context,
- message: L10n.of(context)!.emoteExists,
- okLabel: L10n.of(context)!.ok,
+ message: l10n.emoteExists,
+ okLabel: l10n.ok,
);
return;
}
@@ -200,8 +202,8 @@ class EmotesSettingsController extends State {
await showOkAlertDialog(
useRootNavigator: false,
context: context,
- message: L10n.of(context)!.emoteInvalid,
- okLabel: L10n.of(context)!.ok,
+ message: l10n.emoteInvalid,
+ okLabel: l10n.ok,
);
return;
}
diff --git a/lib/pages/settings_dashboard/settings_emotes/settings_emotes_view.dart b/lib/pages/settings_dashboard/settings_emotes/settings_emotes_view.dart
index 03b620de8f..df282076b6 100644
--- a/lib/pages/settings_dashboard/settings_emotes/settings_emotes_view.dart
+++ b/lib/pages/settings_dashboard/settings_emotes/settings_emotes_view.dart
@@ -1,16 +1,15 @@
+import 'package:fluffychat/generated/l10n/app_localizations.dart';
+import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/widgets/app_bars/twake_app_bar.dart';
import 'package:fluffychat/widgets/context_menu_builder_ios_paste_without_permission.dart';
+import 'package:fluffychat/widgets/layouts/max_width_body.dart';
import 'package:fluffychat/widgets/matrix.dart';
+import 'package:fluffychat/widgets/mxc_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
-
-import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:linagora_design_flutter/linagora_design_flutter.dart';
import 'package:matrix/matrix.dart';
-import 'package:fluffychat/utils/platform_infos.dart';
-import 'package:fluffychat/widgets/layouts/max_width_body.dart';
-import 'package:fluffychat/widgets/mxc_image.dart';
import 'settings_emotes.dart';
class EmotesSettingsView extends StatelessWidget {
@@ -22,12 +21,16 @@ class EmotesSettingsView extends StatelessWidget {
Widget build(BuildContext context) {
final client = Matrix.of(context).client;
final imageKeys = controller.pack!.images.keys.toList();
+ final l10n = L10n.of(context)!;
+ final theme = Theme.of(context);
+ final textTheme = TextStyle(
+ color: Theme.of(context).colorScheme.secondary,
+ fontWeight: FontWeight.bold,
+ );
+
return Scaffold(
backgroundColor: LinagoraSysColors.material().onPrimary,
- appBar: TwakeAppBar(
- title: L10n.of(context)!.emoteSettings,
- context: context,
- ),
+ appBar: TwakeAppBar(title: l10n.emoteSettings, context: context),
floatingActionButton: controller.showSave
? FloatingActionButton(
onPressed: controller.saveAction,
@@ -39,15 +42,15 @@ class EmotesSettingsView extends StatelessWidget {
children: [
if (!controller.readonly)
Container(
- padding: const EdgeInsets.symmetric(vertical: 8.0),
+ padding: const .symmetric(vertical: 8.0),
child: ListTile(
leading: Container(
width: 180.0,
height: 38,
- padding: const EdgeInsets.symmetric(horizontal: 8),
+ padding: const .symmetric(horizontal: 8),
decoration: BoxDecoration(
- borderRadius: const BorderRadius.all(Radius.circular(10)),
- color: Theme.of(context).secondaryHeaderColor,
+ borderRadius: const .all(.circular(10)),
+ color: theme.secondaryHeaderColor,
),
child: TextField(
controller: controller.newImageCodeController,
@@ -56,18 +59,12 @@ class EmotesSettingsView extends StatelessWidget {
minLines: 1,
maxLines: 1,
decoration: InputDecoration(
- hintText: L10n.of(context)!.emoteShortcode,
+ hintText: l10n.emoteShortcode,
prefixText: ': ',
suffixText: ':',
- prefixStyle: TextStyle(
- color: Theme.of(context).colorScheme.secondary,
- fontWeight: FontWeight.bold,
- ),
- suffixStyle: TextStyle(
- color: Theme.of(context).colorScheme.secondary,
- fontWeight: FontWeight.bold,
- ),
- border: InputBorder.none,
+ prefixStyle: textTheme,
+ suffixStyle: textTheme,
+ border: .none,
),
),
),
@@ -87,133 +84,126 @@ class EmotesSettingsView extends StatelessWidget {
),
if (controller.room != null)
SwitchListTile.adaptive(
- title: Text(L10n.of(context)!.enableEmotesGlobally),
+ title: Text(l10n.enableEmotesGlobally),
value: controller.isGloballyActive(client),
onChanged: controller.setIsGloballyActive,
),
if (!controller.readonly || controller.room != null)
- Divider(
- height: 2,
- thickness: 2,
- color: Theme.of(context).primaryColor,
- ),
+ Divider(height: 2, thickness: 2, color: theme.primaryColor),
Expanded(
child: imageKeys.isEmpty
? Center(
child: Padding(
- padding: const EdgeInsets.all(16),
+ padding: const .all(16),
child: Text(
- L10n.of(context)!.noEmotesFound,
+ l10n.noEmotesFound,
style: const TextStyle(fontSize: 20),
),
),
)
- : ListView.separated(
- separatorBuilder: (BuildContext context, int i) =>
- Container(),
- itemCount: imageKeys.length + 1,
- itemBuilder: (BuildContext context, int i) {
- if (i >= imageKeys.length) {
- return Container(height: 70);
- }
- final imageCode = imageKeys[i];
- final image = controller.pack!.images[imageCode]!;
- final textEditingController = TextEditingController();
- textEditingController.text = imageCode;
- final useShortCuts =
- (PlatformInfos.isWeb || PlatformInfos.isDesktop);
- return ListTile(
- leading: Container(
- width: 180.0,
- height: 38,
- padding: const EdgeInsets.symmetric(horizontal: 8),
- decoration: BoxDecoration(
- borderRadius: const BorderRadius.all(
- Radius.circular(10),
- ),
- color: Theme.of(context).secondaryHeaderColor,
- ),
- child: Shortcuts(
- shortcuts: !useShortCuts
- ? {}
- : {
- LogicalKeySet(LogicalKeyboardKey.enter):
- SubmitLineIntent(),
- },
- child: Actions(
- actions: !useShortCuts
- ? {}
- : {
- SubmitLineIntent: CallbackAction(
- onInvoke: (i) {
- controller.submitImageAction(
- imageCode,
- textEditingController.text,
- image,
- textEditingController,
- );
- return null;
- },
- ),
- },
- child: TextField(
- readOnly: controller.readonly,
- controller: textEditingController,
- contextMenuBuilder:
- mobileTwakeContextMenuBuilder,
- autocorrect: false,
- minLines: 1,
- maxLines: 1,
- decoration: InputDecoration(
- hintText: L10n.of(context)!.emoteShortcode,
- prefixText: ': ',
- suffixText: ':',
- prefixStyle: TextStyle(
- color: Theme.of(
- context,
- ).colorScheme.secondary,
- fontWeight: FontWeight.bold,
- ),
- suffixStyle: TextStyle(
- color: Theme.of(
- context,
- ).colorScheme.secondary,
- fontWeight: FontWeight.bold,
- ),
- border: InputBorder.none,
- ),
- onSubmitted: (s) =>
- controller.submitImageAction(
- imageCode,
- s,
- image,
- textEditingController,
- ),
- ),
- ),
- ),
- ),
- title: _EmoteImage(image.url),
- trailing: controller.readonly
- ? null
- : InkWell(
- onTap: () =>
- controller.removeImageAction(imageCode),
- child: const Icon(
- Icons.delete_outlined,
- color: Colors.red,
- size: 32.0,
- ),
- ),
- );
- },
- ),
+ : _buildImageKeysNotEmptyResult(imageKeys),
),
],
),
),
);
}
+
+ ListView _buildImageKeysNotEmptyResult(List imageKeys) {
+ return ListView.separated(
+ separatorBuilder: (_, _) => Container(),
+ itemCount: imageKeys.length + 1,
+ itemBuilder: (BuildContext context, int i) {
+ final l10n = L10n.of(context)!;
+ final theme = Theme.of(context);
+ final colorScheme = theme.colorScheme;
+
+ if (i >= imageKeys.length) return Container(height: 70);
+
+ final imageCode = imageKeys[i];
+ final image = controller.pack!.images[imageCode]!;
+ final textEditingController = TextEditingController();
+ textEditingController.text = imageCode;
+ final useShortCuts = (PlatformInfos.isWeb || PlatformInfos.isDesktop);
+
+ return ListTile(
+ leading: Container(
+ width: 180.0,
+ height: 38,
+ padding: const EdgeInsets.symmetric(horizontal: 8),
+ decoration: BoxDecoration(
+ borderRadius: const .all(.circular(10)),
+ color: theme.secondaryHeaderColor,
+ ),
+ child: Shortcuts(
+ shortcuts: !useShortCuts
+ ? {}
+ : {
+ LogicalKeySet(LogicalKeyboardKey.enter):
+ SubmitLineIntent(),
+ },
+ child: Actions(
+ actions: !useShortCuts
+ ? {}
+ : {
+ SubmitLineIntent: CallbackAction(
+ onInvoke: (i) {
+ controller.submitImageAction(
+ imageCode,
+ textEditingController.text,
+ image,
+ textEditingController,
+ );
+ return null;
+ },
+ ),
+ },
+ child: TextField(
+ readOnly: controller.readonly,
+ controller: textEditingController,
+ contextMenuBuilder: mobileTwakeContextMenuBuilder,
+ autocorrect: false,
+ minLines: 1,
+ maxLines: 1,
+ decoration: InputDecoration(
+ hintText: l10n.emoteShortcode,
+ prefixText: ': ',
+ suffixText: ':',
+ prefixStyle: TextStyle(
+ color: colorScheme.secondary,
+ fontWeight: .bold,
+ ),
+ suffixStyle: TextStyle(
+ color: colorScheme.secondary,
+ fontWeight: .bold,
+ ),
+ border: .none,
+ ),
+ onSubmitted: (s) => controller.submitImageAction(
+ imageCode,
+ s,
+ image,
+ textEditingController,
+ ),
+ ),
+ ),
+ ),
+ ),
+ title: _EmoteImage(image.url),
+ trailing: controller.readonly
+ ? null
+ : InkWell(
+ onTap: () => controller.removeImageAction(imageCode),
+ child: const Icon(
+ Icons.delete_outlined,
+ color: Colors.red,
+ size: 32.0,
+ ),
+ ),
+ );
+ },
+ );
+ }
}
class _EmoteImage extends StatelessWidget {
@@ -223,7 +213,7 @@ class _EmoteImage extends StatelessWidget {
@override
Widget build(BuildContext context) {
const size = 38.0;
- return MxcImage(uri: mxc, fit: BoxFit.contain, width: size, height: size);
+ return MxcImage(uri: mxc, fit: .contain, width: size, height: size);
}
}
@@ -246,9 +236,8 @@ class _ImagePickerState extends State<_ImagePicker> {
onPressed: () => widget.onPressed(widget.controller),
child: Text(L10n.of(context)!.pickImage),
);
- } else {
- return _EmoteImage(widget.controller.value!.url);
}
+ return _EmoteImage(widget.controller.value!.url);
}
}
diff --git a/lib/pages/settings_dashboard/settings_multiple_emotes/settings_multiple_emotes_view.dart b/lib/pages/settings_dashboard/settings_multiple_emotes/settings_multiple_emotes_view.dart
index 53ba7b223b..ca64c599dc 100644
--- a/lib/pages/settings_dashboard/settings_multiple_emotes/settings_multiple_emotes_view.dart
+++ b/lib/pages/settings_dashboard/settings_multiple_emotes/settings_multiple_emotes_view.dart
@@ -1,14 +1,12 @@
+import 'package:fluffychat/generated/l10n/app_localizations.dart';
+import 'package:fluffychat/pages/settings_dashboard/settings_multiple_emotes/settings_multiple_emotes.dart';
import 'package:fluffychat/widgets/app_bars/twake_app_bar.dart';
+import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/material.dart';
-
-import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:go_router/go_router.dart';
import 'package:linagora_design_flutter/linagora_design_flutter.dart';
import 'package:matrix/matrix.dart';
-import 'package:fluffychat/pages/settings_dashboard/settings_multiple_emotes/settings_multiple_emotes.dart';
-import 'package:fluffychat/widgets/matrix.dart';
-
class MultipleEmotesSettingsView extends StatelessWidget {
final MultipleEmotesSettingsController controller;
@@ -17,6 +15,7 @@ class MultipleEmotesSettingsView extends StatelessWidget {
@override
Widget build(BuildContext context) {
final room = Matrix.of(context).client.getRoomById(controller.roomId!)!;
+
return Scaffold(
backgroundColor: LinagoraSysColors.material().onPrimary,
appBar: TwakeAppBar(
diff --git a/lib/pages/settings_dashboard/settings_notifications/settings_notifications_view.dart b/lib/pages/settings_dashboard/settings_notifications/settings_notifications_view.dart
index 971ae7e5ce..a86e26075e 100644
--- a/lib/pages/settings_dashboard/settings_notifications/settings_notifications_view.dart
+++ b/lib/pages/settings_dashboard/settings_notifications/settings_notifications_view.dart
@@ -1,14 +1,15 @@
import 'package:fluffychat/di/global/get_it_initializer.dart';
+import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:fluffychat/utils/dialog/twake_dialog.dart';
import 'package:fluffychat/utils/responsive/responsive_utils.dart';
import 'package:fluffychat/widgets/app_bars/twake_app_bar.dart';
import 'package:fluffychat/widgets/app_bars/twake_app_bar_style.dart';
+import 'package:fluffychat/widgets/layouts/max_width_body.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/material.dart';
-import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:go_router/go_router.dart';
import 'package:linagora_design_flutter/linagora_design_flutter.dart';
-import 'package:fluffychat/widgets/layouts/max_width_body.dart';
+
import 'settings_notifications.dart';
class SettingsNotificationsView extends StatelessWidget {
@@ -19,10 +20,16 @@ class SettingsNotificationsView extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ final l10n = L10n.of(context)!;
+ final client = Matrix.of(context).client;
+ final theme = Theme.of(context);
+ final textTheme = theme.textTheme;
+ final colorScheme = theme.colorScheme;
+
return Scaffold(
backgroundColor: LinagoraSysColors.material().onPrimary,
appBar: TwakeAppBar(
- title: L10n.of(context)!.notifications,
+ title: l10n.notifications,
context: context,
centerTitle: true,
withDivider: true,
@@ -30,9 +37,9 @@ class SettingsNotificationsView extends StatelessWidget {
? Padding(
padding: TwakeAppBarStyle.leadingIconPadding,
child: IconButton(
- tooltip: L10n.of(context)!.back,
+ tooltip: l10n.back,
icon: const Icon(Icons.arrow_back_ios),
- onPressed: () => context.pop(),
+ onPressed: context.pop,
iconSize: TwakeAppBarStyle.leadingIconSize,
),
)
@@ -41,39 +48,36 @@ class SettingsNotificationsView extends StatelessWidget {
body: MaxWidthBody(
withScrolling: true,
child: StreamBuilder(
- stream: Matrix.of(context).client.onAccountData.stream.where(
+ stream: client.onAccountData.stream.where(
(event) => event.type == 'm.push_rules',
),
builder: (BuildContext context, _) {
return Column(
children: [
SwitchListTile.adaptive(
- value: !Matrix.of(context).client.allPushNotificationsMuted,
+ value: !client.allPushNotificationsMuted,
title: Text(
- Matrix.of(context).client.allPushNotificationsMuted
- ? L10n.of(context)!.enable_notifications
- : L10n.of(context)!.disable_notifications,
- style: Theme.of(context).textTheme.bodyLarge?.copyWith(
- color: Theme.of(context).colorScheme.onSurface,
+ client.allPushNotificationsMuted
+ ? l10n.enable_notifications
+ : l10n.disable_notifications,
+ style: textTheme.bodyLarge?.copyWith(
+ color: colorScheme.onSurface,
),
),
onChanged: (_) =>
TwakeDialog.showFutureLoadingDialogFullScreen(
- future: () => Matrix.of(context).client
- .setMuteAllPushNotifications(
- !Matrix.of(
- context,
- ).client.allPushNotificationsMuted,
- ),
+ future: () => client.setMuteAllPushNotifications(
+ !client.allPushNotificationsMuted,
+ ),
),
),
- if (!Matrix.of(context).client.allPushNotificationsMuted) ...{
+ if (!client.allPushNotificationsMuted) ...{
const Divider(thickness: 1),
ListTile(
title: Text(
- L10n.of(context)!.pushRules,
- style: Theme.of(context).textTheme.bodyLarge?.copyWith(
- color: Theme.of(context).colorScheme.onSurface,
+ l10n.pushRules,
+ style: textTheme.bodyLarge?.copyWith(
+ color: colorScheme.onSurface,
fontWeight: FontWeight.w700,
),
),
@@ -83,8 +87,8 @@ class SettingsNotificationsView extends StatelessWidget {
value: controller.getNotificationSetting(item) ?? true,
title: Text(
item.title(context),
- style: Theme.of(context).textTheme.bodyLarge?.copyWith(
- color: Theme.of(context).colorScheme.onSurface,
+ style: textTheme.bodyLarge?.copyWith(
+ color: colorScheme.onSurface,
),
),
onChanged: (bool enabled) =>
diff --git a/lib/pages/settings_dashboard/settings_profile/settings_profile.dart b/lib/pages/settings_dashboard/settings_profile/settings_profile.dart
index 26d47c6654..da357c0823 100644
--- a/lib/pages/settings_dashboard/settings_profile/settings_profile.dart
+++ b/lib/pages/settings_dashboard/settings_profile/settings_profile.dart
@@ -4,6 +4,7 @@ import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:dartz/dartz.dart' hide State;
import 'package:fluffychat/app_state/failure.dart';
import 'package:fluffychat/app_state/success.dart';
+import 'package:fluffychat/config/go_routes/app_route_paths.dart';
import 'package:fluffychat/di/global/get_it_initializer.dart';
import 'package:fluffychat/domain/app_state/room/upload_content_state.dart';
import 'package:fluffychat/domain/app_state/settings/update_profile_failure.dart';
@@ -13,19 +14,20 @@ import 'package:fluffychat/domain/usecase/room/upload_content_interactor.dart';
import 'package:fluffychat/domain/usecase/settings/update_profile_interactor.dart';
import 'package:fluffychat/event/twake_event_dispatcher.dart';
import 'package:fluffychat/event/twake_inapp_event_types.dart';
+import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:fluffychat/pages/multiple_accounts/multiple_accounts_picker.dart';
import 'package:fluffychat/pages/settings_dashboard/settings_profile/settings_profile_capability_check.dart';
import 'package:fluffychat/pages/settings_dashboard/settings_profile/settings_profile_context_menu_actions.dart';
import 'package:fluffychat/pages/settings_dashboard/settings_profile/settings_profile_state/get_clients_ui_state.dart';
import 'package:fluffychat/pages/settings_dashboard/settings_profile/settings_profile_view.dart';
-import 'package:fluffychat/presentation/extensions/multiple_accounts/client_profile_extension.dart';
-import 'package:fluffychat/presentation/mixins/pick_avatar_mixin.dart';
-import 'package:fluffychat/presentation/model/pick_avatar_state.dart';
-import 'package:fluffychat/presentation/multiple_account/client_profile_presentation.dart';
import 'package:fluffychat/presentation/enum/settings/settings_profile_enum.dart';
import 'package:fluffychat/presentation/extensions/client_extension.dart';
+import 'package:fluffychat/presentation/extensions/multiple_accounts/client_profile_extension.dart';
import 'package:fluffychat/presentation/mixins/common_media_picker_mixin.dart';
+import 'package:fluffychat/presentation/mixins/pick_avatar_mixin.dart';
import 'package:fluffychat/presentation/mixins/single_image_picker_mixin.dart';
+import 'package:fluffychat/presentation/model/pick_avatar_state.dart';
+import 'package:fluffychat/presentation/multiple_account/client_profile_presentation.dart';
import 'package:fluffychat/presentation/multiple_account/twake_chat_presentation_account.dart';
import 'package:fluffychat/utils/client_manager.dart';
import 'package:fluffychat/utils/dialog/twake_dialog.dart';
@@ -43,7 +45,6 @@ import 'package:go_router/go_router.dart';
import 'package:linagora_design_flutter/images_picker/asset_counter.dart';
import 'package:linagora_design_flutter/linagora_design_flutter.dart';
import 'package:matrix/matrix.dart';
-import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:wechat_camera_picker/wechat_camera_picker.dart';
class SettingsProfile extends StatefulWidget {
@@ -138,9 +139,9 @@ class SettingsProfileController extends State
SettingsProfileEnum settingsProfileEnum,
) {
switch (settingsProfileEnum) {
- case SettingsProfileEnum.displayName:
+ case .displayName:
return displayNameEditingController;
- case SettingsProfileEnum.matrixId:
+ case .matrixId:
return matrixIdEditingController;
default:
return null;
@@ -149,7 +150,7 @@ class SettingsProfileController extends State
FocusNode? getFocusNode(SettingsProfileEnum settingsProfileEnum) {
switch (settingsProfileEnum) {
- case SettingsProfileEnum.displayName:
+ case .displayName:
return displayNameFocusNode;
default:
return null;
@@ -221,7 +222,7 @@ class SettingsProfileController extends State
actions: actions(),
);
if (action == null) return;
- if (action == AvatarAction.remove) {
+ if (action == .remove) {
_handleRemoveAvatarAction();
return;
}
@@ -229,10 +230,8 @@ class SettingsProfileController extends State
}
List listContextMenuBuilder(BuildContext context) {
- final listAction = [
- SettingsProfileContextMenuActions.edit,
- SettingsProfileContextMenuActions.delete,
- ];
+ final List listAction = [.edit, .delete];
+
final items = listAction.map((action) {
return popupItemByTwakeAppRouter(
context,
@@ -261,10 +260,10 @@ class SettingsProfileController extends State
void _handleActionContextMenu(SettingsProfileContextMenuActions action) {
switch (action) {
- case SettingsProfileContextMenuActions.edit:
+ case .edit:
_showImagesPickerAction();
break;
- case SettingsProfileContextMenuActions.delete:
+ case .delete:
pickAvatarUIState.value = Right(
GetAvatarInitialUIState(),
);
@@ -487,7 +486,7 @@ class SettingsProfileController extends State
void copyEventsAction(SettingsProfileEnum settingsProfileEnum) {
switch (settingsProfileEnum) {
- case SettingsProfileEnum.matrixId:
+ case .matrixId:
Clipboard.setData(ClipboardData(text: client.mxid(context)));
TwakeSnackBar.show(
context,
@@ -556,7 +555,7 @@ class SettingsProfileController extends State
).showMultipleAccountsPicker(
client,
onGoToAccountSettings: () {
- context.go('/rooms/profile');
+ context.go(AppRoutePaths.profileFull);
},
);
}
@@ -663,8 +662,9 @@ class SettingsProfileController extends State
}
void updateNewProfileForAccount() {
+ final client = Matrix.of(context).client;
listenOnProfileChangeStream(
- client: Matrix.of(context).client,
+ client: client,
currentProfile: currentProfile.value,
onProfileChanged: (newProfile) {
final indexOldAccount = _multipleAccounts.indexWhere(
@@ -674,9 +674,9 @@ class SettingsProfileController extends State
return;
}
final newAccount = ClientProfilePresentation(
- client: Matrix.of(context).client,
+ client: client,
profile: newProfile,
- ).toTwakeChatPresentationAccount(Matrix.of(context).client);
+ ).toTwakeChatPresentationAccount(client);
_multipleAccounts[indexOldAccount] = newAccount;
settingsMultiAccountsUIState.value = Right(
GetClientsSuccessUIState(multipleAccounts: _multipleAccounts),
diff --git a/lib/pages/settings_dashboard/settings_profile/settings_profile_context_menu_actions.dart b/lib/pages/settings_dashboard/settings_profile/settings_profile_context_menu_actions.dart
index 2369327b1c..daa423f114 100644
--- a/lib/pages/settings_dashboard/settings_profile/settings_profile_context_menu_actions.dart
+++ b/lib/pages/settings_dashboard/settings_profile/settings_profile_context_menu_actions.dart
@@ -1,24 +1,25 @@
-import 'package:flutter/material.dart';
import 'package:fluffychat/generated/l10n/app_localizations.dart';
+import 'package:flutter/material.dart';
enum SettingsProfileContextMenuActions {
edit,
delete;
String getTitle(BuildContext context) {
+ final l10n = L10n.of(context)!;
switch (this) {
- case SettingsProfileContextMenuActions.edit:
- return L10n.of(context)!.changeProfileAvatar;
- case SettingsProfileContextMenuActions.delete:
- return L10n.of(context)!.removeYourAvatar;
+ case .edit:
+ return l10n.changeProfileAvatar;
+ case .delete:
+ return l10n.removeYourAvatar;
}
}
IconData getIcon() {
switch (this) {
- case SettingsProfileContextMenuActions.edit:
+ case .edit:
return Icons.camera_alt_outlined;
- case SettingsProfileContextMenuActions.delete:
+ case .delete:
return Icons.delete;
}
}
diff --git a/lib/pages/settings_dashboard/settings_profile/settings_profile_item.dart b/lib/pages/settings_dashboard/settings_profile/settings_profile_item.dart
index 296ad8b06b..06d20aa52f 100644
--- a/lib/pages/settings_dashboard/settings_profile/settings_profile_item.dart
+++ b/lib/pages/settings_dashboard/settings_profile/settings_profile_item.dart
@@ -32,6 +32,10 @@ class SettingsProfileItemBuilder extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ final sysColor = LinagoraSysColors.material();
+ final refColor = LinagoraRefColors.material();
+ final textTheme = Theme.of(context).textTheme;
+
return Column(
children: [
Row(
@@ -42,22 +46,22 @@ class SettingsProfileItemBuilder extends StatelessWidget {
child: Icon(
leadingIcon,
size: SettingsProfileItemStyle.iconSize,
- color: LinagoraSysColors.material().tertiary,
+ color: sysColor.tertiary,
),
),
Expanded(
child: Padding(
padding: SettingsProfileItemStyle.textPadding,
child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
+ crossAxisAlignment: .start,
children: [
Text(
title,
- style: Theme.of(context).textTheme.labelMedium?.copyWith(
- color: LinagoraRefColors.material().neutral[40],
+ style: textTheme.labelMedium?.copyWith(
+ color: refColor.neutral[40],
),
maxLines: 1,
- overflow: TextOverflow.ellipsis,
+ overflow: .ellipsis,
),
if (textEditingController != null)
ValueListenableBuilder(
@@ -65,12 +69,11 @@ class SettingsProfileItemBuilder extends StatelessWidget {
builder: (context, value, _) {
return Text(
value.text,
- style: Theme.of(context).textTheme.bodyLarge
- ?.copyWith(
- color: LinagoraSysColors.material().onSurface,
- ),
+ style: textTheme.bodyLarge?.copyWith(
+ color: sysColor.onSurface,
+ ),
maxLines: 1,
- overflow: TextOverflow.ellipsis,
+ overflow: .ellipsis,
);
},
),
@@ -86,7 +89,7 @@ class SettingsProfileItemBuilder extends StatelessWidget {
icon: Icon(
suffixIcon,
size: SettingsProfileItemStyle.copyIconSize,
- color: LinagoraRefColors.material().tertiary[40],
+ color: refColor.tertiary[40],
),
),
],
@@ -94,12 +97,10 @@ class SettingsProfileItemBuilder extends StatelessWidget {
const SizedBox(height: 8),
if (enableDivider)
Container(
- width: double.infinity,
+ width: .infinity,
height: 1,
- margin: const EdgeInsets.only(left: 40),
- color: LinagoraStateLayer(
- LinagoraSysColors.material().surfaceTint,
- ).opacityLayer3,
+ margin: const .only(left: 40),
+ color: LinagoraStateLayer(sysColor.surfaceTint).opacityLayer3,
),
],
);
@@ -107,7 +108,7 @@ class SettingsProfileItemBuilder extends StatelessWidget {
bool get hasSuffixIcon {
return switch (settingsProfileEnum) {
- SettingsProfileEnum.displayName => canEditDisplayName,
+ .displayName => canEditDisplayName,
_ => true,
};
}
diff --git a/lib/pages/settings_dashboard/settings_profile/settings_profile_item_style.dart b/lib/pages/settings_dashboard/settings_profile/settings_profile_item_style.dart
index 48c2e62c77..31196b2c56 100644
--- a/lib/pages/settings_dashboard/settings_profile/settings_profile_item_style.dart
+++ b/lib/pages/settings_dashboard/settings_profile/settings_profile_item_style.dart
@@ -4,10 +4,7 @@ class SettingsProfileItemStyle {
static const double iconSize = 24.0;
static const double copyIconSize = 20.0;
- static const EdgeInsetsDirectional itemBuilderPadding =
- EdgeInsetsDirectional.only(end: 8.0);
+ static const EdgeInsetsDirectional itemBuilderPadding = .only(end: 8.0);
- static const EdgeInsetsGeometry textPadding = EdgeInsets.symmetric(
- horizontal: 8.0,
- );
+ static const EdgeInsetsGeometry textPadding = .symmetric(horizontal: 8.0);
}
diff --git a/lib/pages/settings_dashboard/settings_profile/settings_profile_redirection_edit_button.dart b/lib/pages/settings_dashboard/settings_profile/settings_profile_redirection_edit_button.dart
index 27ad190055..1f4a7fd1f1 100644
--- a/lib/pages/settings_dashboard/settings_profile/settings_profile_redirection_edit_button.dart
+++ b/lib/pages/settings_dashboard/settings_profile/settings_profile_redirection_edit_button.dart
@@ -19,6 +19,7 @@ class SettingsProfileRedirectionEditButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
+ final sysColor = LinagoraSysColors.material();
final matrix = Matrix.of(context);
final userId = matrix.client.userID;
final commonSettingsInformation = matrix
@@ -40,14 +41,12 @@ class SettingsProfileRedirectionEditButton extends StatelessWidget {
padding: const EdgeInsetsDirectional.only(end: 16),
child: TextButton(
style: TextButton.styleFrom(
- padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 12),
- overlayColor: LinagoraSysColors.material().shadow.withValues(
- alpha: 0.2,
- ),
+ padding: const .symmetric(vertical: 10, horizontal: 12),
+ overlayColor: sysColor.shadow.withValues(alpha: 0.2),
textStyle: textTheme.labelLarge?.copyWith(
fontSize: 14,
height: 20 / 14,
- color: LinagoraSysColors.material().primary,
+ color: sysColor.primary,
),
),
onPressed: () {
diff --git a/lib/pages/settings_dashboard/settings_profile/settings_profile_state/settings_profile_ui_state.dart b/lib/pages/settings_dashboard/settings_profile/settings_profile_state/settings_profile_ui_state.dart
deleted file mode 100644
index 54f00f7e64..0000000000
--- a/lib/pages/settings_dashboard/settings_profile/settings_profile_state/settings_profile_ui_state.dart
+++ /dev/null
@@ -1,3 +0,0 @@
-import 'package:fluffychat/presentation/state/success.dart';
-
-abstract class SettingsProfileUIState extends UIState {}
diff --git a/lib/pages/settings_dashboard/settings_profile/settings_profile_view.dart b/lib/pages/settings_dashboard/settings_profile/settings_profile_view.dart
index 314e29adcb..84c252164d 100644
--- a/lib/pages/settings_dashboard/settings_profile/settings_profile_view.dart
+++ b/lib/pages/settings_dashboard/settings_profile/settings_profile_view.dart
@@ -1,5 +1,7 @@
+import 'package:fluffychat/config/go_routes/app_route_paths.dart';
import 'package:fluffychat/di/global/get_it_initializer.dart';
import 'package:fluffychat/domain/model/capabilities/capabilities_extension.dart';
+import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:fluffychat/pages/settings_dashboard/settings_profile/settings_profile.dart';
import 'package:fluffychat/pages/settings_dashboard/settings_profile/settings_profile_item.dart';
import 'package:fluffychat/pages/settings_dashboard/settings_profile/settings_profile_redirection_edit_button.dart';
@@ -13,7 +15,6 @@ import 'package:fluffychat/widgets/app_bars/twake_app_bar.dart';
import 'package:fluffychat/widgets/twake_components/twake_icon_button.dart';
import 'package:flutter/material.dart';
import 'package:flutter_adaptive_scaffold/flutter_adaptive_scaffold.dart';
-import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:go_router/go_router.dart';
import 'package:linagora_design_flutter/colors/linagora_sys_colors.dart';
import 'package:matrix/matrix.dart';
@@ -39,16 +40,18 @@ class SettingsProfileView extends StatelessWidget {
@override
Widget build(BuildContext context) {
final responsive = getIt.get();
+ final l10n = L10n.of(context)!;
+
return Scaffold(
appBar: TwakeAppBar(
- title: L10n.of(context)!.profile,
+ title: l10n.profile,
leading: responsive.isMobile(context)
? IconButton(
icon: const Icon(
Icons.arrow_back_ios,
size: SettingsProfileViewStyle.sizeIcon,
),
- onPressed: () => context.pop(),
+ onPressed: context.pop,
)
: const SizedBox.shrink(),
actions: [
@@ -56,7 +59,7 @@ class SettingsProfileView extends StatelessWidget {
TwakeIconButton(
icon: Icons.qr_code,
iconColor: LinagoraSysColors.material().primary,
- onTap: () => context.go('/rooms/profile/qr'),
+ onTap: () => context.go(AppRoutePaths.profileQrFull),
),
ValueListenableBuilder(
valueListenable: controller.isEditedProfileNotifier,
@@ -69,14 +72,14 @@ class SettingsProfileView extends StatelessWidget {
return Padding(
padding: SettingsProfileViewStyle.actionButtonPadding,
child: InkWell(
- borderRadius: BorderRadius.circular(
+ borderRadius: .circular(
SettingsProfileViewStyle.borderRadius,
),
onTap: () => controller.onUploadProfileAction(),
child: Padding(
padding: SettingsProfileViewStyle.paddingTextButton,
child: Text(
- L10n.of(context)!.done,
+ l10n.done,
style: Theme.of(context).textTheme.labelLarge?.copyWith(
color: Theme.of(context).colorScheme.primary,
),
@@ -118,40 +121,36 @@ class SettingsProfileView extends StatelessWidget {
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
+ final settingsProfile =
+ controller.getListProfileMobile[index];
+
return SettingsProfileItemBuilder(
- settingsProfileEnum:
- controller.getListProfileMobile[index],
- title: controller.getListProfileMobile[index].getTitle(
- context,
- ),
+ settingsProfileEnum: settingsProfile,
+ title: settingsProfile.getTitle(context),
settingsProfilePresentation: SettingsProfilePresentation(
- settingsProfileType: controller
- .getListProfileMobile[index]
+ settingsProfileType: settingsProfile
.getSettingsProfileType(),
),
- suffixIcon: controller.getListProfileMobile[index]
- .getTrailingIcon(),
- leadingIcon: controller.getListProfileMobile[index]
- .getLeadingIcon(),
+ suffixIcon: settingsProfile.getTrailingIcon(),
+ leadingIcon: settingsProfile.getLeadingIcon(),
onEditRequested: () {
final focusNode = controller.getFocusNode(
- controller.getListProfileMobile[index],
+ settingsProfile,
);
focusNode?.requestFocus();
},
textEditingController: controller.getController(
- controller.getListProfileMobile[index],
- ),
- onCopyAction: () => controller.copyEventsAction(
- controller.getListProfileMobile[index],
+ settingsProfile,
),
+ onCopyAction: () =>
+ controller.copyEventsAction(settingsProfile),
canEditDisplayName:
capabilities?.canEditDisplayName == true,
enableDivider:
index != (controller.getListProfileMobile.length - 1),
);
},
- separatorBuilder: (context, index) {
+ separatorBuilder: (_, _) {
return const SizedBox(height: 8);
},
itemCount: controller.getListProfileMobile.length,
@@ -177,33 +176,31 @@ class SettingsProfileView extends StatelessWidget {
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
+ final settingsProfile =
+ controller.getListProfileBasicInfo[index];
+
return SettingsProfileItemBuilder(
- settingsProfileEnum:
- controller.getListProfileBasicInfo[index],
- title: controller.getListProfileBasicInfo[index].getTitle(
- context,
- ),
+ settingsProfileEnum: settingsProfile,
+ title: settingsProfile.getTitle(context),
settingsProfilePresentation: SettingsProfilePresentation(
- settingsProfileType: controller
- .getListProfileBasicInfo[index]
+ settingsProfileType: settingsProfile
.getSettingsProfileType(),
),
- suffixIcon: controller.getListProfileBasicInfo[index]
- .getTrailingIcon(),
+ suffixIcon: settingsProfile.getTrailingIcon(),
onEditRequested: () {
final focusNode = controller.getFocusNode(
- controller.getListProfileBasicInfo[index],
+ settingsProfile,
);
focusNode?.requestFocus();
},
textEditingController: controller.getController(
- controller.getListProfileBasicInfo[index],
+ settingsProfile,
),
canEditDisplayName:
capabilities?.canEditDisplayName == true,
);
},
- separatorBuilder: (context, index) {
+ separatorBuilder: (_, _) {
return const SizedBox(height: 16);
},
itemCount: controller.getListProfileBasicInfo.length,
@@ -213,36 +210,33 @@ class SettingsProfileView extends StatelessWidget {
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
+ final workIdentityInfo =
+ controller.getListProfileWorkIdentitiesInfo[index];
+
return SettingsProfileItemBuilder(
- settingsProfileEnum:
- controller.getListProfileWorkIdentitiesInfo[index],
- title: controller.getListProfileWorkIdentitiesInfo[index]
- .getTitle(context),
+ settingsProfileEnum: workIdentityInfo,
+ title: workIdentityInfo.getTitle(context),
settingsProfilePresentation: SettingsProfilePresentation(
- settingsProfileType: controller
- .getListProfileWorkIdentitiesInfo[index]
+ settingsProfileType: workIdentityInfo
.getSettingsProfileType(),
),
- suffixIcon: controller
- .getListProfileWorkIdentitiesInfo[index]
- .getTrailingIcon(),
+ suffixIcon: workIdentityInfo.getTrailingIcon(),
onEditRequested: () {
final focusNode = controller.getFocusNode(
- controller.getListProfileWorkIdentitiesInfo[index],
+ workIdentityInfo,
);
focusNode?.requestFocus();
},
textEditingController: controller.getController(
- controller.getListProfileWorkIdentitiesInfo[index],
- ),
- onCopyAction: () => controller.copyEventsAction(
- controller.getListProfileWorkIdentitiesInfo[index],
+ workIdentityInfo,
),
+ onCopyAction: () =>
+ controller.copyEventsAction(workIdentityInfo),
canEditDisplayName:
capabilities?.canEditDisplayName == true,
);
},
- separatorBuilder: (context, index) {
+ separatorBuilder: (_, _) {
return const SizedBox(height: 16);
},
itemCount: controller.getListProfileWorkIdentitiesInfo.length,
@@ -257,11 +251,13 @@ class SettingsProfileView extends StatelessWidget {
}
Color backgroundColor(ResponsiveUtils responsive, BuildContext context) {
+ final colorScheme = Theme.of(context).colorScheme;
+
if (PlatformInfos.isMobile) {
- return Theme.of(context).colorScheme.surface;
+ return colorScheme.surface;
} else {
return responsive.isWebDesktop(context)
- ? Theme.of(context).colorScheme.surface
+ ? colorScheme.surface
: LinagoraSysColors.material().onPrimary;
}
}
diff --git a/lib/pages/settings_dashboard/settings_profile/settings_profile_view_mobile.dart b/lib/pages/settings_dashboard/settings_profile/settings_profile_view_mobile.dart
index 779e5da845..1f28ddbdcf 100644
--- a/lib/pages/settings_dashboard/settings_profile/settings_profile_view_mobile.dart
+++ b/lib/pages/settings_dashboard/settings_profile/settings_profile_view_mobile.dart
@@ -1,6 +1,7 @@
import 'package:dartz/dartz.dart' hide State;
import 'package:fluffychat/app_state/failure.dart';
import 'package:fluffychat/app_state/success.dart';
+import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:fluffychat/pages/settings_dashboard/settings_profile/settings_profile_state/get_clients_ui_state.dart';
import 'package:fluffychat/pages/settings_dashboard/settings_profile/settings_profile_view_mobile_style.dart';
import 'package:fluffychat/presentation/extensions/client_extension.dart';
@@ -12,7 +13,6 @@ import 'package:fluffychat/widgets/mixins/popup_menu_widget_style.dart';
import 'package:flutter/material.dart';
import 'package:linagora_design_flutter/linagora_design_flutter.dart';
import 'package:matrix/matrix.dart';
-import 'package:fluffychat/generated/l10n/app_localizations.dart';
typedef OnTapMultipleAccountsButton =
void Function(List multipleAccounts);
@@ -63,6 +63,10 @@ class _SettingsProfileViewMobileState extends State {
@override
Widget build(BuildContext context) {
+ final colorScheme = Theme.of(context).colorScheme;
+ final textTheme = Theme.of(context).textTheme;
+ final l10n = L10n.of(context)!;
+
return Column(
children: [
Column(
@@ -75,9 +79,9 @@ class _SettingsProfileViewMobileState extends State {
builder: (context, _) {
return Stack(
children: [
- Positioned.fill(child: _buildAvatarBackground(context)),
- Positioned.fill(child: _buildGradientOverlay(context)),
- Column(children: [_buildProfileInformation(context)]),
+ Positioned.fill(child: _buildAvatarBackground()),
+ Positioned.fill(child: _buildGradientOverlay()),
+ Column(children: [_buildProfileInformation()]),
if (widget.canEditAvatar && !isExpanded)
Positioned(
bottom: SettingsProfileViewMobileStyle
@@ -87,9 +91,7 @@ class _SettingsProfileViewMobileState extends State {
child: MenuAnchor(
controller: widget.menuController,
style: MenuStyle(
- padding: const WidgetStatePropertyAll(
- EdgeInsets.zero,
- ),
+ padding: const WidgetStatePropertyAll(.zero),
backgroundColor: WidgetStatePropertyAll(
PopupMenuWidgetStyle.defaultMenuColor(
context,
@@ -107,7 +109,7 @@ class _SettingsProfileViewMobileState extends State {
(
BuildContext context,
MenuController menuController,
- Widget? child,
+ _,
) {
return GestureDetector(
onTap: () {
@@ -121,17 +123,13 @@ class _SettingsProfileViewMobileState extends State {
},
child: Container(
decoration: BoxDecoration(
- color: Theme.of(
- context,
- ).colorScheme.primary,
- borderRadius: BorderRadius.circular(
+ color: colorScheme.primary,
+ borderRadius: .circular(
SettingsProfileViewMobileStyle
.avatarSize,
),
- border: Border.all(
- color: Theme.of(
- context,
- ).colorScheme.onPrimary,
+ border: .all(
+ color: colorScheme.onPrimary,
width:
SettingsProfileViewMobileStyle
.iconEditBorderWidth,
@@ -143,9 +141,7 @@ class _SettingsProfileViewMobileState extends State {
Icons.edit,
size: SettingsProfileViewMobileStyle
.iconEditSize,
- color: Theme.of(
- context,
- ).colorScheme.onPrimary,
+ color: colorScheme.onPrimary,
),
),
);
@@ -160,16 +156,16 @@ class _SettingsProfileViewMobileState extends State {
},
),
Container(
- margin: const EdgeInsets.only(left: 12, right: 12, top: 12),
- padding: const EdgeInsets.all(8),
+ margin: const .only(left: 12, right: 12, top: 12),
+ padding: const .all(8),
decoration: BoxDecoration(
- borderRadius: const BorderRadius.all(Radius.circular(8)),
- border: Border.all(
+ borderRadius: const .all(.circular(8)),
+ border: .all(
color:
LinagoraRefColors.material().neutral[90] ?? Colors.black,
),
color: widget.responsive.isWebDesktop(context)
- ? Theme.of(context).colorScheme.surface
+ ? colorScheme.surface
: LinagoraSysColors.material().onPrimary,
),
child: widget.settingsProfileOptions,
@@ -185,35 +181,34 @@ class _SettingsProfileViewMobileState extends State {
(success) {
if (success is GetClientsLoadingUIState) {
return Container(
- width: double.infinity,
+ width: .infinity,
height: SettingsProfileViewMobileStyle.bottomButtonHeight,
padding: SettingsProfileViewMobileStyle.paddingBottomButton,
margin: SettingsProfileViewMobileStyle.marginBottomButton,
decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(
+ borderRadius: .circular(
SettingsProfileViewMobileStyle.bottomButtonRadius,
),
- color: Theme.of(context).colorScheme.primary,
+ color: colorScheme.primary,
),
- alignment: Alignment.center,
+ alignment: .center,
child: Row(
- mainAxisAlignment: MainAxisAlignment.center,
+ mainAxisAlignment: .center,
children: [
Transform.scale(
scale: SettingsProfileViewMobileStyle.indicatorScale,
child: CircularProgressIndicator(
- color: Theme.of(context).colorScheme.onPrimary,
+ color: colorScheme.onPrimary,
strokeWidth: SettingsProfileViewMobileStyle
.indicatorStrokeWidth,
),
),
SettingsProfileViewMobileStyle.paddingIconAndText,
Text(
- L10n.of(context)!.loadingPleaseWait,
- style: Theme.of(context).textTheme.labelLarge
- ?.copyWith(
- color: Theme.of(context).colorScheme.onPrimary,
- ),
+ l10n.loadingPleaseWait,
+ style: textTheme.labelLarge?.copyWith(
+ color: colorScheme.onPrimary,
+ ),
),
],
),
@@ -229,39 +224,36 @@ class _SettingsProfileViewMobileState extends State {
splashColor: Colors.transparent,
hoverColor: Colors.transparent,
child: Container(
- width: double.infinity,
+ width: .infinity,
height: SettingsProfileViewMobileStyle.bottomButtonHeight,
padding:
SettingsProfileViewMobileStyle.paddingBottomButton,
margin: SettingsProfileViewMobileStyle.marginBottomButton,
decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(
+ borderRadius: .circular(
SettingsProfileViewMobileStyle.bottomButtonRadius,
),
- color: Theme.of(context).colorScheme.primary,
+ color: colorScheme.primary,
),
- alignment: Alignment.center,
+ alignment: .center,
child: Row(
- mainAxisAlignment: MainAxisAlignment.center,
+ mainAxisAlignment: .center,
children: [
Icon(
success.haveMultipleAccounts
? Icons.group_outlined
: Icons.person_add_alt_outlined,
size: SettingsProfileViewMobileStyle.iconSize,
- color: Theme.of(context).colorScheme.onPrimary,
+ color: colorScheme.onPrimary,
),
SettingsProfileViewMobileStyle.paddingIconAndText,
Text(
success.haveMultipleAccounts
- ? L10n.of(context)!.switchAccounts
- : L10n.of(context)!.addAnotherAccount,
- style: Theme.of(context).textTheme.labelLarge
- ?.copyWith(
- color: Theme.of(
- context,
- ).colorScheme.onPrimary,
- ),
+ ? l10n.switchAccounts
+ : l10n.addAnotherAccount,
+ style: textTheme.labelLarge?.copyWith(
+ color: colorScheme.onPrimary,
+ ),
),
],
),
@@ -278,7 +270,7 @@ class _SettingsProfileViewMobileState extends State {
);
}
- Widget _buildAvatarBackground(BuildContext context) {
+ Widget _buildAvatarBackground() {
return ValueListenableBuilder(
valueListenable: widget.currentProfile,
builder: (context, profile, _) {
@@ -296,16 +288,15 @@ class _SettingsProfileViewMobileState extends State {
);
}
- Widget _buildGradientOverlay(BuildContext context) {
- final sysColor = LinagoraSysColors.material();
+ Widget _buildGradientOverlay() {
return DecoratedBox(
decoration: BoxDecoration(
gradient: LinearGradient(
- begin: Alignment.topCenter,
- end: Alignment.bottomCenter,
+ begin: .topCenter,
+ end: .bottomCenter,
colors: [
Colors.transparent,
- sysColor.onTertiaryContainer.withValues(
+ LinagoraSysColors.material().onTertiaryContainer.withValues(
alpha: widget.animationController.value,
),
],
@@ -314,10 +305,10 @@ class _SettingsProfileViewMobileState extends State {
);
}
- Widget _buildProfileInformation(BuildContext context) {
+ Widget _buildProfileInformation() {
return ValueListenableBuilder(
valueListenable: widget.currentProfile,
- builder: (context, profile, _) {
+ builder: (context, Profile? profile, _) {
final displayName =
profile?.displayName ??
widget.client.mxid(context).localpart ??
@@ -332,13 +323,12 @@ class _SettingsProfileViewMobileState extends State {
}
},
child: GestureDetector(
- behavior: HitTestBehavior.opaque,
+ behavior: .opaque,
onTap: () {
if (!isTextSelected) {
widget.onAvatarInfoTap.call();
return;
}
-
FocusScope.of(context).unfocus();
},
child: Container(
@@ -346,9 +336,9 @@ class _SettingsProfileViewMobileState extends State {
begin: SettingsProfileViewMobileStyle.minAvatarBackgroundHeight,
end: SettingsProfileViewMobileStyle.maxAvatarBackgroundHeight,
).transform(widget.animationController.value),
- padding: const EdgeInsets.symmetric(horizontal: 12),
+ padding: const .symmetric(horizontal: 12),
child: Column(
- mainAxisAlignment: MainAxisAlignment.end,
+ mainAxisAlignment: .end,
children: [
const SizedBox(
height: SettingsProfileViewMobileStyle.avatarSize,
@@ -357,8 +347,8 @@ class _SettingsProfileViewMobileState extends State {
const SizedBox(height: 8),
Align(
alignment: Tween(
- begin: Alignment.center,
- end: Alignment.centerLeft,
+ begin: .center,
+ end: .centerLeft,
).transform(widget.animationController.value),
child: Text(
displayName,
@@ -367,10 +357,10 @@ class _SettingsProfileViewMobileState extends State {
begin: sysColors.onSurface,
end: sysColors.onPrimary,
).transform(widget.animationController.value),
- fontWeight: FontWeight.bold,
+ fontWeight: .bold,
),
maxLines: 2,
- overflow: TextOverflow.ellipsis,
+ overflow: .ellipsis,
),
),
const SizedBox(height: 12),
diff --git a/lib/pages/settings_dashboard/settings_profile/settings_profile_view_mobile_style.dart b/lib/pages/settings_dashboard/settings_profile/settings_profile_view_mobile_style.dart
index a8d1eb1ce3..67f9038d47 100644
--- a/lib/pages/settings_dashboard/settings_profile/settings_profile_view_mobile_style.dart
+++ b/lib/pages/settings_dashboard/settings_profile/settings_profile_view_mobile_style.dart
@@ -13,12 +13,11 @@ class SettingsProfileViewMobileStyle {
static const double dividerHeight = 2;
static const int thumbnailSize = 28;
- static EdgeInsetsDirectional editIconPadding =
- const EdgeInsetsDirectional.all(8);
+ static EdgeInsetsDirectional editIconPadding = const .all(8);
static const bottomButtonHeight = 48.0;
- static const paddingBottomButton = EdgeInsets.only(left: 16.0, right: 16.0);
- static const marginBottomButton = EdgeInsets.only(
+ static const EdgeInsets paddingBottomButton = .only(left: 16.0, right: 16.0);
+ static const EdgeInsets marginBottomButton = .only(
bottom: 32.0,
left: 16,
right: 16,
diff --git a/lib/pages/settings_dashboard/settings_profile/settings_profile_view_style.dart b/lib/pages/settings_dashboard/settings_profile/settings_profile_view_style.dart
index fa2b32a241..a39c4025a5 100644
--- a/lib/pages/settings_dashboard/settings_profile/settings_profile_view_style.dart
+++ b/lib/pages/settings_dashboard/settings_profile/settings_profile_view_style.dart
@@ -4,10 +4,10 @@ class SettingsProfileViewStyle {
static const sizeIcon = 24.0;
static const borderRadius = 20.0;
- static const EdgeInsetsDirectional paddingTextButton =
- EdgeInsetsDirectional.symmetric(horizontal: 12);
+ static const EdgeInsetsDirectional paddingTextButton = .symmetric(
+ horizontal: 12,
+ );
- static const EdgeInsetsDirectional paddingBody =
- EdgeInsetsDirectional.symmetric(horizontal: 16);
- static const actionButtonPadding = EdgeInsets.only(top: 8);
+ static const EdgeInsetsDirectional paddingBody = .symmetric(horizontal: 16);
+ static const EdgeInsets actionButtonPadding = .only(top: 8);
}
diff --git a/lib/pages/settings_dashboard/settings_profile/settings_profile_view_web.dart b/lib/pages/settings_dashboard/settings_profile/settings_profile_view_web.dart
index 688f7fd573..5c150178d2 100644
--- a/lib/pages/settings_dashboard/settings_profile/settings_profile_view_web.dart
+++ b/lib/pages/settings_dashboard/settings_profile/settings_profile_view_web.dart
@@ -1,6 +1,7 @@
import 'package:dartz/dartz.dart';
import 'package:fluffychat/app_state/failure.dart';
import 'package:fluffychat/app_state/success.dart';
+import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:fluffychat/pages/settings_dashboard/settings_profile/settings_profile_view_web_style.dart';
import 'package:fluffychat/presentation/extensions/client_extension.dart';
import 'package:fluffychat/presentation/model/pick_avatar_state.dart';
@@ -10,7 +11,6 @@ import 'package:fluffychat/widgets/mixins/popup_menu_widget_style.dart';
import 'package:fluffychat/widgets/stream_image_view.dart';
import 'package:flutter/material.dart';
import 'package:linagora_design_flutter/linagora_design_flutter.dart';
-import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:matrix/matrix.dart';
class SettingsProfileViewWeb extends StatelessWidget {
@@ -39,6 +39,10 @@ class SettingsProfileViewWeb extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ final l10n = L10n.of(context)!;
+ final theme = Theme.of(context);
+ final textTheme = theme.textTheme;
+
return Padding(
padding: SettingsProfileViewWebStyle.paddingBody,
child: Align(
@@ -46,233 +50,268 @@ class SettingsProfileViewWeb extends StatelessWidget {
child: SingleChildScrollView(
physics: const NeverScrollableScrollPhysics(),
child: Column(
- mainAxisSize: MainAxisSize.min,
- crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisSize: .min,
+ crossAxisAlignment: .start,
children: [
- Container(
- width: SettingsProfileViewWebStyle.bodyWidth,
- padding: SettingsProfileViewWebStyle.paddingWidgetBasicInfo,
- clipBehavior: Clip.antiAlias,
- decoration: ShapeDecoration(
- color: Colors.white,
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(
- SettingsProfileViewWebStyle.radiusCircular,
- ),
- ),
- ),
- child: Column(
- mainAxisSize: MainAxisSize.min,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Padding(
- padding:
- SettingsProfileViewWebStyle.paddingBasicInfoTitle,
- child: Text(
- L10n.of(context)!.basicInfo,
- style: Theme.of(context).textTheme.labelLarge?.copyWith(
- color: Theme.of(context).colorScheme.onSurface,
- ),
- ),
- ),
- Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Padding(
- padding: SettingsProfileViewWebStyle
- .paddingWidgetBasicInfo,
- child: Stack(
- alignment: AlignmentDirectional.center,
- children: [
- const SizedBox(
- width: SettingsProfileViewWebStyle.widthSize,
- ),
- ValueListenableBuilder(
- valueListenable: settingsProfileUIState,
- builder: (context, uiState, child) => uiState
- .fold((failure) => child!, (success) {
- if (success
- is GetAvatarOnWebUIStateSuccess) {
- return ClipOval(
- child: SizedBox.fromSize(
- size: const Size.fromRadius(
- SettingsProfileViewWebStyle
- .radiusImageMemory,
- ),
- child: StreamImageViewer(
- matrixFile: success.matrixFile!,
- onImageLoaded: onImageLoaded,
- ),
- ),
- );
- }
- return child!;
- }),
- child: ValueListenableBuilder(
- valueListenable: currentProfile,
- builder: (context, profile, _) {
- final displayName =
- profile?.displayName ??
- client.mxid(context).localpart ??
- client.mxid(context);
- return Material(
- elevation:
- Theme.of(context)
- .appBarTheme
- .scrolledUnderElevation ??
- 4,
- shadowColor: Theme.of(
- context,
- ).appBarTheme.shadowColor,
- shape: RoundedRectangleBorder(
- side: BorderSide(
- color: Theme.of(context).dividerColor,
- ),
- borderRadius: BorderRadius.circular(
- AvatarStyle.defaultSize,
- ),
- ),
- child: Avatar(
- mxContent: profile?.avatarUrl,
- name: displayName,
- size: SettingsProfileViewWebStyle
- .avatarSize,
- fontSize: SettingsProfileViewWebStyle
- .avatarFontSize,
- ),
- );
- },
- ),
- ),
- if (canEditAvatar)
- Positioned(
- bottom: SettingsProfileViewWebStyle
- .positionedBottomSize,
- right: SettingsProfileViewWebStyle
- .positionedRightSize,
- child: MenuAnchor(
- controller: menuController,
- style: MenuStyle(
- padding: const WidgetStatePropertyAll(
- EdgeInsets.zero,
- ),
- shape: WidgetStatePropertyAll(
- RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(
- PopupMenuWidgetStyle
- .menuBorderRadius,
- ),
- ),
- ),
- backgroundColor: WidgetStatePropertyAll(
- PopupMenuWidgetStyle.defaultMenuColor(
- context,
- ),
- ),
- ),
- builder:
- (
- BuildContext context,
- MenuController menuController,
- Widget? child,
- ) {
- return GestureDetector(
- onTap: () => menuController.isOpen
- ? menuController.close()
- : menuController.open(),
- child: Container(
- decoration: BoxDecoration(
- color: Theme.of(
- context,
- ).colorScheme.primary,
- borderRadius:
- BorderRadius.circular(
- SettingsProfileViewWebStyle
- .avatarSize,
- ),
- border: Border.all(
- color: Theme.of(
- context,
- ).colorScheme.onPrimary,
- width:
- SettingsProfileViewWebStyle
- .iconEditBorderWidth,
- ),
- ),
- padding:
- SettingsProfileViewWebStyle
- .paddingEditIcon,
- child: Icon(
- Icons.edit,
- size:
- SettingsProfileViewWebStyle
- .iconEditSize,
- color: Theme.of(
- context,
- ).colorScheme.onPrimary,
- ),
- ),
- );
- },
- menuChildren: menuChildren ?? [],
- ),
- ),
- ],
- ),
- ),
- Expanded(child: basicInfoWidget),
- ],
- ),
- ],
- ),
+ AvatarAndNameRow(
+ settingsProfileUIState: settingsProfileUIState,
+ onImageLoaded: onImageLoaded,
+ currentProfile: currentProfile,
+ client: client,
+ canEditAvatar: canEditAvatar,
+ menuController: menuController,
+ menuChildren: menuChildren,
+ basicInfoWidget: basicInfoWidget,
),
Padding(
padding:
SettingsProfileViewWebStyle.paddingWidgetEditProfileInfo,
child: Text(
- L10n.of(context)!.editProfileDescriptions,
- style: Theme.of(context).textTheme.labelLarge?.copyWith(
+ l10n.editProfileDescriptions,
+ style: textTheme.labelLarge?.copyWith(
color: LinagoraRefColors.material().tertiary[30],
),
),
),
- Container(
- width: SettingsProfileViewWebStyle.bodyWidth,
+ PersonalInfosColumn(
+ workIdentitiesInfoWidget: workIdentitiesInfoWidget,
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+}
+
+class PersonalInfosColumn extends StatelessWidget {
+ const PersonalInfosColumn({
+ super.key,
+ required this.workIdentitiesInfoWidget,
+ });
+
+ final Widget workIdentitiesInfoWidget;
+
+ @override
+ Widget build(BuildContext context) {
+ final l10n = L10n.of(context)!;
+ final theme = Theme.of(context);
+
+ return Container(
+ width: SettingsProfileViewWebStyle.bodyWidth,
+ padding: SettingsProfileViewWebStyle.paddingWidgetBasicInfo,
+ clipBehavior: .antiAlias,
+ decoration: ShapeDecoration(
+ color: Colors.white,
+ shape: RoundedRectangleBorder(
+ borderRadius: .circular(SettingsProfileViewWebStyle.radiusCircular),
+ ),
+ ),
+ child: Column(
+ mainAxisSize: .min,
+ crossAxisAlignment: .start,
+ children: [
+ Padding(
+ padding: SettingsProfileViewWebStyle.paddingBasicInfoTitle,
+ child: Text(
+ l10n.workIdentitiesInfo,
+ style: theme.textTheme.labelLarge?.copyWith(
+ color: theme.colorScheme.onSurface,
+ ),
+ ),
+ ),
+ Padding(
+ padding:
+ SettingsProfileViewWebStyle.paddingWorkIdentitiesInfoWidget,
+ child: workIdentitiesInfoWidget,
+ ),
+ ],
+ ),
+ );
+ }
+}
+
+class AvatarAndNameRow extends StatelessWidget {
+ const AvatarAndNameRow({
+ super.key,
+ required this.settingsProfileUIState,
+ required this.onImageLoaded,
+ required this.currentProfile,
+ required this.client,
+ required this.canEditAvatar,
+ required this.menuController,
+ required this.menuChildren,
+ required this.basicInfoWidget,
+ });
+
+ final ValueNotifier> settingsProfileUIState;
+ final Function(MatrixFile) onImageLoaded;
+ final ValueNotifier currentProfile;
+ final Client client;
+ final bool canEditAvatar;
+ final MenuController? menuController;
+ final List? menuChildren;
+ final Widget basicInfoWidget;
+
+ @override
+ Widget build(BuildContext context) {
+ final l10n = L10n.of(context)!;
+ final theme = Theme.of(context);
+ final appBarTheme = theme.appBarTheme;
+ final colorScheme = theme.colorScheme;
+ final textTheme = theme.textTheme;
+
+ return Container(
+ width: SettingsProfileViewWebStyle.bodyWidth,
+ padding: SettingsProfileViewWebStyle.paddingWidgetBasicInfo,
+ clipBehavior: .antiAlias,
+ decoration: ShapeDecoration(
+ color: Colors.white,
+ shape: RoundedRectangleBorder(
+ borderRadius: .circular(SettingsProfileViewWebStyle.radiusCircular),
+ ),
+ ),
+ child: Column(
+ mainAxisSize: .min,
+ crossAxisAlignment: .start,
+ children: [
+ Padding(
+ padding: SettingsProfileViewWebStyle.paddingBasicInfoTitle,
+ child: Text(
+ l10n.basicInfo,
+ style: textTheme.labelLarge?.copyWith(
+ color: colorScheme.onSurface,
+ ),
+ ),
+ ),
+ Row(
+ crossAxisAlignment: .start,
+ children: [
+ Padding(
padding: SettingsProfileViewWebStyle.paddingWidgetBasicInfo,
- clipBehavior: Clip.antiAlias,
- decoration: ShapeDecoration(
- color: Colors.white,
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(
- SettingsProfileViewWebStyle.radiusCircular,
- ),
- ),
- ),
- child: Column(
- mainAxisSize: MainAxisSize.min,
- crossAxisAlignment: CrossAxisAlignment.start,
+ child: Stack(
+ alignment: AlignmentDirectional.center,
children: [
- Padding(
- padding:
- SettingsProfileViewWebStyle.paddingBasicInfoTitle,
- child: Text(
- L10n.of(context)!.workIdentitiesInfo,
- style: Theme.of(context).textTheme.labelLarge?.copyWith(
- color: Theme.of(context).colorScheme.onSurface,
- ),
- ),
+ const SizedBox(
+ width: SettingsProfileViewWebStyle.widthSize,
),
- Padding(
- padding: SettingsProfileViewWebStyle
- .paddingWorkIdentitiesInfoWidget,
- child: workIdentitiesInfoWidget,
+ ValueListenableBuilder(
+ valueListenable: settingsProfileUIState,
+ builder: (context, uiState, child) => uiState.fold(
+ (failure) => child!,
+ (success) {
+ if (success is GetAvatarOnWebUIStateSuccess) {
+ return ClipOval(
+ child: SizedBox.fromSize(
+ size: const .fromRadius(
+ SettingsProfileViewWebStyle.radiusImageMemory,
+ ),
+ child: StreamImageViewer(
+ matrixFile: success.matrixFile!,
+ onImageLoaded: onImageLoaded,
+ ),
+ ),
+ );
+ }
+ return child!;
+ },
+ ),
+ child: ValueListenableBuilder(
+ valueListenable: currentProfile,
+ builder: (context, profile, _) {
+ final displayName =
+ profile?.displayName ??
+ client.mxid(context).localpart ??
+ client.mxid(context);
+ return Material(
+ elevation: appBarTheme.scrolledUnderElevation ?? 4,
+ shadowColor: appBarTheme.shadowColor,
+ shape: RoundedRectangleBorder(
+ side: BorderSide(color: theme.dividerColor),
+ borderRadius: .circular(AvatarStyle.defaultSize),
+ ),
+ child: Avatar(
+ mxContent: profile?.avatarUrl,
+ name: displayName,
+ size: SettingsProfileViewWebStyle.avatarSize,
+ fontSize:
+ SettingsProfileViewWebStyle.avatarFontSize,
+ ),
+ );
+ },
+ ),
),
+ if (canEditAvatar)
+ EditMenuBtn(
+ menuController: menuController,
+ menuChildren: menuChildren,
+ ),
],
),
),
+ Expanded(child: basicInfoWidget),
],
),
+ ],
+ ),
+ );
+ }
+}
+
+class EditMenuBtn extends StatelessWidget {
+ const EditMenuBtn({
+ super.key,
+ required this.menuController,
+ required this.menuChildren,
+ });
+
+ final MenuController? menuController;
+ final List? menuChildren;
+
+ @override
+ Widget build(BuildContext context) {
+ final colorScheme = Theme.of(context).colorScheme;
+
+ return Positioned(
+ bottom: SettingsProfileViewWebStyle.positionedBottomSize,
+ right: SettingsProfileViewWebStyle.positionedRightSize,
+ child: MenuAnchor(
+ controller: menuController,
+ style: MenuStyle(
+ padding: const WidgetStatePropertyAll(EdgeInsets.zero),
+ shape: WidgetStatePropertyAll(
+ RoundedRectangleBorder(
+ borderRadius: .circular(PopupMenuWidgetStyle.menuBorderRadius),
+ ),
+ ),
+ backgroundColor: WidgetStatePropertyAll(
+ PopupMenuWidgetStyle.defaultMenuColor(context),
+ ),
),
+ builder: (_, MenuController menuController, _) {
+ return GestureDetector(
+ onTap: () => menuController.isOpen
+ ? menuController.close()
+ : menuController.open(),
+ child: Container(
+ decoration: BoxDecoration(
+ color: colorScheme.primary,
+ borderRadius: .circular(SettingsProfileViewWebStyle.avatarSize),
+ border: .all(
+ color: colorScheme.onPrimary,
+ width: SettingsProfileViewWebStyle.iconEditBorderWidth,
+ ),
+ ),
+ padding: SettingsProfileViewWebStyle.paddingEditIcon,
+ child: Icon(
+ Icons.edit,
+ size: SettingsProfileViewWebStyle.iconEditSize,
+ color: colorScheme.onPrimary,
+ ),
+ ),
+ );
+ },
+ menuChildren: menuChildren ?? [],
),
);
}
diff --git a/lib/pages/settings_dashboard/settings_profile/settings_profile_view_web_style.dart b/lib/pages/settings_dashboard/settings_profile/settings_profile_view_web_style.dart
index 6728cdf2c8..93dd3bcd9c 100644
--- a/lib/pages/settings_dashboard/settings_profile/settings_profile_view_web_style.dart
+++ b/lib/pages/settings_dashboard/settings_profile/settings_profile_view_web_style.dart
@@ -13,22 +13,19 @@ class SettingsProfileViewWebStyle {
static const double radiusCircular = 16;
static const double radiusImageMemory = 48;
- static const EdgeInsetsDirectional paddingBody = EdgeInsetsDirectional.all(
- 32,
- );
+ static const EdgeInsetsDirectional paddingBody = .all(32);
- static const EdgeInsetsDirectional paddingWidgetBasicInfo =
- EdgeInsetsDirectional.all(16);
+ static const EdgeInsetsDirectional paddingWidgetBasicInfo = .all(16);
- static const EdgeInsetsDirectional paddingBasicInfoTitle =
- EdgeInsetsDirectional.only(bottom: 32);
+ static const EdgeInsetsDirectional paddingBasicInfoTitle = .only(bottom: 32);
- static const EdgeInsetsDirectional paddingEditIcon =
- EdgeInsetsDirectional.all(8);
+ static const EdgeInsetsDirectional paddingEditIcon = .all(8);
- static const EdgeInsetsDirectional paddingWidgetEditProfileInfo =
- EdgeInsetsDirectional.symmetric(vertical: 16);
+ static const EdgeInsetsDirectional paddingWidgetEditProfileInfo = .symmetric(
+ vertical: 16,
+ );
- static const EdgeInsetsDirectional paddingWorkIdentitiesInfoWidget =
- EdgeInsetsDirectional.only(bottom: 16);
+ static const EdgeInsetsDirectional paddingWorkIdentitiesInfoWidget = .only(
+ bottom: 16,
+ );
}
diff --git a/lib/pages/settings_dashboard/settings_security/settings_security.dart b/lib/pages/settings_dashboard/settings_security/settings_security.dart
index 747333d80f..25617a270a 100644
--- a/lib/pages/settings_dashboard/settings_security/settings_security.dart
+++ b/lib/pages/settings_dashboard/settings_security/settings_security.dart
@@ -1,25 +1,26 @@
import 'dart:async';
import 'dart:convert';
+import 'package:adaptive_dialog/adaptive_dialog.dart';
+import 'package:fluffychat/config/setting_keys.dart';
+import 'package:fluffychat/di/global/get_it_initializer.dart';
+import 'package:fluffychat/domain/usecase/recovery/get_recovery_words_interactor.dart';
+import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:fluffychat/pages/bootstrap/bootstrap_dialog.dart';
import 'package:fluffychat/presentation/extensions/client_extension.dart';
import 'package:fluffychat/utils/beautify_string_extension.dart';
+import 'package:fluffychat/utils/clipboard.dart';
import 'package:fluffychat/utils/dialog/twake_dialog.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_file_extension.dart';
import 'package:fluffychat/utils/twake_snackbar.dart';
+import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/material.dart';
-
-import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:flutter/services.dart';
import 'package:flutter_app_lock/flutter_app_lock.dart';
-import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
-
import 'package:intl/intl.dart';
import 'package:matrix/matrix.dart';
-import 'package:fluffychat/config/setting_keys.dart';
-import 'package:fluffychat/widgets/matrix.dart';
import 'settings_security_view.dart';
class SettingsSecurity extends StatefulWidget {
@@ -32,57 +33,117 @@ class SettingsSecurity extends StatefulWidget {
class SettingsSecurityController extends State {
StreamSubscription? ignoredUsersStreamSub;
- ValueNotifier> ignoredUsersNotifier =
- ValueNotifier>([]);
+ final ignoredUsersNotifier = ValueNotifier>([]);
Client get client => Matrix.read(context).client;
+ /// Future that fetches the recovery key, created once in [initState]
+ /// and consumed by a [FutureBuilder] in the view.
+ late final Future recoveryKeyFuture;
+
+ /// Cached recovery key value for the copy action.
+ String? _recoveryKey;
+
+ @override
+ void initState() {
+ listenIgnoredUser();
+ recoveryKeyFuture = _fetchRecoveryKey();
+ super.initState();
+ }
+
+ @override
+ void dispose() {
+ ignoredUsersStreamSub?.cancel();
+ ignoredUsersNotifier.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) => SettingsSecurityView(this);
+
+ /// Fetches the recovery key from the ToM server via [GetRecoveryWordsInteractor].
+ /// Returns the key string or null on failure.
+ Future _fetchRecoveryKey() async {
+ final result = await getIt.get().execute();
+ return result.fold((failure) => null, (success) {
+ _recoveryKey = success.words.words;
+ return _recoveryKey;
+ });
+ }
+
+ /// Copies the recovery key to clipboard after showing a security warning dialog.
+ /// The warning informs the user that this secret grants access to all
+ /// encrypted messages.
+ Future copyRecoveryKey() async {
+ final key = _recoveryKey;
+ if (key == null) return;
+
+ final l10n = L10n.of(context)!;
+ final confirmed = await showOkCancelAlertDialog(
+ context: context,
+ title: l10n.recoveryKey,
+ message: l10n.recoveryKeyWarningMessage,
+ okLabel: l10n.copy,
+ cancelLabel: l10n.cancel,
+ isDestructiveAction: true,
+ );
+ if (!mounted || confirmed != OkCancelResult.ok) return;
+
+ TwakeClipboard.instance.copyText(key);
+ TwakeSnackBar.show(context, l10n.recoveryKeyCopiedToClipboard);
+ }
+
void changePasswordAccountAction() async {
+ final l10n = L10n.of(context)!;
final input = await showTextInputDialog(
useRootNavigator: false,
context: context,
- title: L10n.of(context)!.changePassword,
- okLabel: L10n.of(context)!.ok,
- cancelLabel: L10n.of(context)!.cancel,
+ title: l10n.changePassword,
+ okLabel: l10n.ok,
+ cancelLabel: l10n.cancel,
textFields: [
DialogTextField(
- hintText: L10n.of(context)!.chooseAStrongPassword,
+ hintText: l10n.chooseAStrongPassword,
obscureText: true,
minLines: 1,
maxLines: 1,
),
DialogTextField(
- hintText: L10n.of(context)!.repeatPassword,
+ hintText: l10n.repeatPassword,
obscureText: true,
minLines: 1,
maxLines: 1,
),
],
);
- if (input == null) return;
+ if (!mounted || input == null) return;
final success = await TwakeDialog.showFutureLoadingDialogFullScreen(
- future: () => Matrix.of(
- context,
- ).client.changePassword(input.last, oldPassword: input.first),
+ future: () => client.changePassword(input.last, oldPassword: input.first),
);
+ if (!mounted) return;
if (success.error == null) {
- TwakeSnackBar.show(context, L10n.of(context)!.passwordHasBeenChanged);
+ TwakeSnackBar.show(context, l10n.passwordHasBeenChanged);
}
}
void setAppLockAction() async {
+ final l10n = L10n.of(context)!;
final currentLock = await const FlutterSecureStorage().read(
key: SettingKeys.appLockKey,
);
+ final appLock = AppLock.of(context)!;
+
+ if (!mounted) return;
if (currentLock?.isNotEmpty ?? false) {
- await AppLock.of(context)!.showLockScreen();
+ await appLock.showLockScreen();
}
+ if (!mounted) return;
final newLock = await showTextInputDialog(
useRootNavigator: false,
context: context,
- title: L10n.of(context)!.pleaseChooseAPasscode,
- message: L10n.of(context)!.pleaseEnter4Digits,
- cancelLabel: L10n.of(context)!.cancel,
+ title: l10n.pleaseChooseAPasscode,
+ message: l10n.pleaseEnter4Digits,
+ cancelLabel: l10n.cancel,
textFields: [
DialogTextField(
validator: (text) {
@@ -90,44 +151,44 @@ class SettingsSecurityController extends State {
(text.length == 4 && int.tryParse(text)! >= 0)) {
return null;
}
- return L10n.of(context)!.pleaseEnter4Digits;
+ return l10n.pleaseEnter4Digits;
},
- keyboardType: TextInputType.number,
+ keyboardType: .number,
obscureText: true,
maxLines: 1,
minLines: 1,
),
],
);
- if (newLock != null) {
- await const FlutterSecureStorage().write(
- key: SettingKeys.appLockKey,
- value: newLock.single,
- );
- if (newLock.single.isEmpty) {
- AppLock.of(context)!.disable();
- } else {
- AppLock.of(context)!.enable();
- }
+ if (!mounted || newLock == null) return;
+ await const FlutterSecureStorage().write(
+ key: SettingKeys.appLockKey,
+ value: newLock.single,
+ );
+ if (!mounted) return;
+ if (newLock.single.isEmpty) {
+ appLock.disable();
+ } else {
+ appLock.enable();
}
}
- void showBootstrapDialog(BuildContext context) async {
- await BootstrapDialog(client: Matrix.of(context).client).show();
+ void showBootstrapDialog() async {
+ await BootstrapDialog(client: client).show();
}
Future dehydrateAction() => dehydrateDevice(context);
static Future dehydrateDevice(BuildContext context) async {
+ final l10n = L10n.of(context)!;
final response = await showOkCancelAlertDialog(
context: context,
isDestructiveAction: true,
- title: L10n.of(context)!.dehydrate,
- message: L10n.of(context)!.dehydrateWarning,
+ title: l10n.dehydrate,
+ message: l10n.dehydrateWarning,
);
- if (response != OkCancelResult.ok) {
- return;
- }
+ if (response != OkCancelResult.ok) return;
+
final file = await TwakeDialog.showFutureLoadingDialogFullScreen(
future: () async {
final export = await Matrix.of(context).client.exportDump();
@@ -148,9 +209,7 @@ class SettingsSecurityController extends State {
}
Future copyPublicKey() async {
- Clipboard.setData(
- ClipboardData(text: Matrix.of(context).client.fingerprintKey.beautified),
- );
+ TwakeClipboard.instance.copyText(client.fingerprintKey.beautified);
TwakeSnackBar.show(context, L10n.of(context)!.copiedPublicKeyToClipboard);
}
@@ -160,20 +219,4 @@ class SettingsSecurityController extends State {
ignoredUsersNotifier.value = client.ignoredUsers;
});
}
-
- @override
- void initState() {
- listenIgnoredUser();
- super.initState();
- }
-
- @override
- void dispose() {
- ignoredUsersStreamSub?.cancel();
- ignoredUsersNotifier.dispose();
- super.dispose();
- }
-
- @override
- Widget build(BuildContext context) => SettingsSecurityView(this);
}
diff --git a/lib/pages/settings_dashboard/settings_security/settings_security_view.dart b/lib/pages/settings_dashboard/settings_security/settings_security_view.dart
index a89e77da4e..086dcb1b05 100644
--- a/lib/pages/settings_dashboard/settings_security/settings_security_view.dart
+++ b/lib/pages/settings_dashboard/settings_security/settings_security_view.dart
@@ -1,20 +1,21 @@
import 'package:fluffychat/config/go_routes/app_route_paths.dart';
import 'package:fluffychat/di/global/get_it_initializer.dart';
+import 'package:fluffychat/generated/l10n/app_localizations.dart';
import 'package:fluffychat/pages/settings_dashboard/settings/settings_item_builder.dart';
import 'package:fluffychat/pages/settings_dashboard/settings/settings_view_style.dart';
import 'package:fluffychat/resource/image_paths.dart';
+import 'package:fluffychat/utils/beautify_string_extension.dart';
+import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/utils/responsive/responsive_utils.dart';
import 'package:fluffychat/widgets/app_bars/twake_app_bar.dart';
import 'package:fluffychat/widgets/app_bars/twake_app_bar_style.dart';
-import 'package:flutter/material.dart';
-import 'package:fluffychat/generated/l10n/app_localizations.dart';
-import 'package:fluffychat/utils/beautify_string_extension.dart';
-import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/widgets/layouts/max_width_body.dart';
import 'package:fluffychat/widgets/matrix.dart';
+import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:go_router/go_router.dart';
import 'package:linagora_design_flutter/linagora_design_flutter.dart';
+
import 'settings_security.dart';
class SettingsSecurityView extends StatelessWidget {
@@ -25,10 +26,17 @@ class SettingsSecurityView extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ final l10n = L10n.of(context)!;
+ final colorScheme = Theme.of(context).colorScheme;
+ final refColorTertiary30 = LinagoraRefColors.material().tertiary[30];
+ final sysColor = LinagoraSysColors.material();
+ final linagoraTextStyleBodyMedium = LinagoraTextStyle.material().bodyMedium;
+ final client = Matrix.of(context).client;
+
return Scaffold(
- backgroundColor: LinagoraSysColors.material().onPrimary,
+ backgroundColor: sysColor.onPrimary,
appBar: TwakeAppBar(
- title: L10n.of(context)!.security,
+ title: l10n.security,
context: context,
centerTitle: true,
withDivider: true,
@@ -36,9 +44,9 @@ class SettingsSecurityView extends StatelessWidget {
? Padding(
padding: TwakeAppBarStyle.leadingIconPadding,
child: IconButton(
- tooltip: L10n.of(context)!.back,
+ tooltip: l10n.back,
icon: const Icon(Icons.arrow_back_ios),
- onPressed: () => context.pop(),
+ onPressed: context.pop,
iconSize: TwakeAppBarStyle.leadingIconSize,
),
)
@@ -47,30 +55,22 @@ class SettingsSecurityView extends StatelessWidget {
body: ListTileTheme(
// TODO: remove when the color scheme is updated
// ignore: deprecated_member_use
- iconColor: Theme.of(context).colorScheme.onBackground,
+ iconColor: colorScheme.onBackground,
child: MaxWidthBody(
withScrolling: true,
child: Column(
children: [
- // #869 Hide privacy settings for now
- // ListTile(
- // leading: const Icon(Icons.camera_outlined),
- // trailing: const Icon(Icons.chevron_right_outlined),
- // title: Text(L10n.of(context)!.whoCanSeeMyStories),
- // onTap: () => context.go('/stories'),
- // ),
Column(
children: [
Padding(
padding: SettingsViewStyle.bodySettingsScreenPadding,
child: SettingsItemBuilder(
key: const Key('contacts_visibility_settings_item'),
- title: L10n.of(context)!.contactsVisibility,
- titleColor: Theme.of(context).colorScheme.onBackground,
- subtitle: L10n.of(context)!.whoCanFindMeByMyContacts,
+ title: l10n.contactsVisibility,
+ titleColor: colorScheme.onBackground,
+ subtitle: l10n.whoCanFindMeByMyContacts,
leading: Icons.phone_outlined,
- leadingIconColor:
- LinagoraRefColors.material().tertiary[30],
+ leadingIconColor: refColorTertiary30,
onTap: () {
context.push(AppRoutePaths.contactsVisibilityFull);
},
@@ -80,9 +80,9 @@ class SettingsSecurityView extends StatelessWidget {
padding: SettingsViewStyle.settingsItemDividerPadding(),
child: Divider(
color: LinagoraStateLayer(
- LinagoraSysColors.material().surfaceTint,
+ sysColor.surfaceTint,
).opacityLayer3,
- thickness: SettingsViewStyle.settingsItemDividerThikness,
+ thickness: SettingsViewStyle.settingsItemDividerThickness,
height: SettingsViewStyle.settingsItemDividerHeight,
),
),
@@ -92,24 +92,23 @@ class SettingsSecurityView extends StatelessWidget {
valueListenable: controller.ignoredUsersNotifier,
builder: (context, ignoredUsers, _) {
return SettingsItemBuilder(
- title: L10n.of(context)!.blockedUsers,
- titleColor: Theme.of(
- context,
- ).colorScheme.onBackground,
+ title: l10n.blockedUsers,
+ titleColor: colorScheme.onBackground,
subtitle: ignoredUsers.isEmpty
? null
: ignoredUsers.length.toString(),
leadingWidget: SvgPicture.asset(
ImagePaths.icFrontHand,
- colorFilter: ColorFilter.mode(
- LinagoraRefColors.material().tertiary[30] ??
- LinagoraSysColors.material().onSurface,
+ colorFilter: .mode(
+ refColorTertiary30 ?? sysColor.onSurface,
BlendMode.srcIn,
),
),
onTap: () {
if (ignoredUsers.isNotEmpty) {
- context.push('/rooms/security/blockedUsers');
+ context.push(
+ AppRoutePaths.securityBlockedUsersFull,
+ );
}
},
);
@@ -120,53 +119,87 @@ class SettingsSecurityView extends StatelessWidget {
padding: SettingsViewStyle.settingsItemDividerPadding(),
child: Divider(
color: LinagoraStateLayer(
- LinagoraSysColors.material().surfaceTint,
+ sysColor.surfaceTint,
).opacityLayer3,
- thickness: SettingsViewStyle.settingsItemDividerThikness,
+ thickness: SettingsViewStyle.settingsItemDividerThickness,
height: SettingsViewStyle.settingsItemDividerHeight,
),
),
],
),
- // ListTile(
- // leading: const Icon(Icons.password_outlined),
- // trailing: const Icon(Icons.chevron_right_outlined),
- // title: Text(
- // L10n.of(context)!.changePassword,
- // ),
- // onTap: controller.changePasswordAccountAction,
- // ),
- // ListTile(
- // leading: const Icon(Icons.mail_outlined),
- // trailing: const Icon(Icons.chevron_right_outlined),
- // title: Text(L10n.of(context)!.passwordRecovery),
- // onTap: () => context.go('/3pid'),
- // ),
- if (Matrix.of(context).client.encryption != null) ...{
+ // Recovery Key section - fetched from ToM server
+ FutureBuilder(
+ future: controller.recoveryKeyFuture,
+ builder: (context, snapshot) {
+ if (!snapshot.hasData || snapshot.data == null) {
+ return const SizedBox.shrink();
+ }
+ return Column(
+ children: [
+ Padding(
+ padding: SettingsViewStyle.bodySettingsScreenPadding,
+ child: SettingsItemBuilder(
+ key: const Key('recovery_key_settings_item'),
+ title: l10n.recoveryKey,
+ titleColor: colorScheme.onBackground,
+ subtitle: '\u2022' * 32,
+ subtitleStyle: linagoraTextStyleBodyMedium.copyWith(
+ color: refColorTertiary30,
+ letterSpacing: 2,
+ ),
+ leadingWidget: SvgPicture.asset(
+ ImagePaths.icRecoveryKey,
+ colorFilter: ColorFilter.mode(
+ refColorTertiary30 ?? sysColor.onSurface,
+ .srcIn,
+ ),
+ ),
+ isHideTrailingIcon: true,
+ trailingWidget: InkWell(
+ key: const Key('recovery_key_copy_button'),
+ onTap: controller.copyRecoveryKey,
+ child: const Icon(Icons.content_copy),
+ ),
+ onTap: controller.copyRecoveryKey,
+ ),
+ ),
+ Padding(
+ padding: SettingsViewStyle.settingsItemDividerPadding(),
+ child: Divider(
+ color: LinagoraStateLayer(
+ sysColor.surfaceTint,
+ ).opacityLayer3,
+ thickness:
+ SettingsViewStyle.settingsItemDividerThickness,
+ height: SettingsViewStyle.settingsItemDividerHeight,
+ ),
+ ),
+ ],
+ );
+ },
+ ),
+ if (client.encryption != null) ...{
if (PlatformInfos.isMobile)
Column(
children: [
Padding(
padding: SettingsViewStyle.bodySettingsScreenPadding,
child: SettingsItemBuilder(
- title: L10n.of(context)!.appLock,
- titleColor: Theme.of(
- context,
- ).colorScheme.onBackground,
+ title: l10n.appLock,
+ titleColor: colorScheme.onBackground,
leading: Icons.lock_outlined,
onTap: controller.setAppLockAction,
- leadingIconColor:
- LinagoraRefColors.material().tertiary[30],
+ leadingIconColor: refColorTertiary30,
),
),
Padding(
padding: SettingsViewStyle.settingsItemDividerPadding(),
child: Divider(
color: LinagoraStateLayer(
- LinagoraSysColors.material().surfaceTint,
+ sysColor.surfaceTint,
).opacityLayer3,
thickness:
- SettingsViewStyle.settingsItemDividerThikness,
+ SettingsViewStyle.settingsItemDividerThickness,
height: SettingsViewStyle.settingsItemDividerHeight,
),
),
@@ -176,19 +209,16 @@ class SettingsSecurityView extends StatelessWidget {
padding: SettingsViewStyle.bodySettingsScreenPadding,
child: SettingsItemBuilder(
height: 116,
- title: L10n.of(context)!.yourPublicKey,
- titleColor: Theme.of(context).colorScheme.onBackground,
- subtitle: Matrix.of(
- context,
- ).client.fingerprintKey.beautified,
- subtitleStyle: LinagoraTextStyle.material().bodyMedium
- .copyWith(
- color: LinagoraRefColors.material().tertiary[30],
- fontFamily: 'monospace',
- ),
+ title: l10n.yourPublicKey,
+ titleColor: colorScheme.onBackground,
+ subtitle: client.fingerprintKey.beautified,
+ subtitleStyle: linagoraTextStyleBodyMedium.copyWith(
+ color: refColorTertiary30,
+ fontFamily: 'monospace',
+ ),
leading: Icons.notifications_outlined,
onTap: controller.copyPublicKey,
- leadingIconColor: LinagoraRefColors.material().tertiary[30],
+ leadingIconColor: refColorTertiary30,
trailingWidget: InkWell(
onTap: controller.copyPublicKey,
child: const Icon(Icons.content_copy),
@@ -196,25 +226,6 @@ class SettingsSecurityView extends StatelessWidget {
),
),
},
- //TODO #1734: Remove dehydrate and delete account
- // ListTile(
- // leading: const Icon(Icons.tap_and_play),
- // trailing: const Icon(Icons.chevron_right_outlined),
- // title: Text(
- // L10n.of(context)!.dehydrate,
- // style: const TextStyle(color: Colors.red),
- // ),
- // onTap: controller.dehydrateAction,
- // ),
- // ListTile(
- // leading: const Icon(Icons.delete_outlined),
- // trailing: const Icon(Icons.chevron_right_outlined),
- // title: Text(
- // L10n.of(context)!.deleteAccount,
- // style: const TextStyle(color: Colors.red),
- // ),
- // onTap: controller.deleteAccountAction,
- // ),
],
),
),
diff --git a/lib/pages/settings_dashboard/settings_stories/settings_stories.dart b/lib/pages/settings_dashboard/settings_stories/settings_stories.dart
index 10e6e67c5d..c42a03a6a3 100644
--- a/lib/pages/settings_dashboard/settings_stories/settings_stories.dart
+++ b/lib/pages/settings_dashboard/settings_stories/settings_stories.dart
@@ -1,10 +1,9 @@
+import 'package:fluffychat/pages/settings_dashboard/settings_stories/settings_stories_view.dart';
import 'package:fluffychat/utils/dialog/twake_dialog.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/client_stories_extension.dart';
+import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/material.dart';
-
import 'package:matrix/matrix.dart';
-import 'package:fluffychat/pages/settings_dashboard/settings_stories/settings_stories_view.dart';
-import 'package:fluffychat/widgets/matrix.dart';
class SettingsStories extends StatefulWidget {
const SettingsStories({super.key});
@@ -34,9 +33,7 @@ class SettingsStoriesController extends State {
future: () async {
await user.kick();
await room.client.setStoriesBlockList(blockList.toSet().toList());
- setState(() {
- users[user] = false;
- });
+ setState(() => users[user] = false);
},
);
return;
@@ -49,27 +46,25 @@ class SettingsStoriesController extends State {
future: () async {
await room.client.setStoriesBlockList(blockList);
await room.invite(user.id);
- setState(() {
- users[user] = true;
- });
+ setState(() => users[user] = true);
},
);
return;
}
Future _loadUsers() async {
- final room = _storiesRoom = await Matrix.of(
- context,
- ).client.getStoriesRoom(context);
+ final client = Matrix.of(context).client;
+
+ final room = _storiesRoom = await client.getStoriesRoom(context);
if (room == null) {
noStoriesRoom = true;
return;
}
final users = await room.requestParticipants();
users.removeWhere((u) => u.id == room.client.userID);
- final contacts = Matrix.of(
- context,
- ).client.contacts.where((contact) => !users.any((u) => u.id == contact.id));
+ final contacts = client.contacts.where(
+ (contact) => !users.any((u) => u.id == contact.id),
+ );
for (final user in contacts) {
this.users[user] = false;
}
@@ -83,12 +78,10 @@ class SettingsStoriesController extends State {
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
- setState(() {
- loadUsers = _loadUsers();
- });
+ setState(() => loadUsers = _loadUsers());
});
}
@override
- Widget build(BuildContext context) => SettingsStoriesView(this);
+ Widget build(_) => SettingsStoriesView(this);
}
diff --git a/lib/pages/settings_dashboard/settings_stories/settings_stories_view.dart b/lib/pages/settings_dashboard/settings_stories/settings_stories_view.dart
index 763bf92aef..48dc1844c3 100644
--- a/lib/pages/settings_dashboard/settings_stories/settings_stories_view.dart
+++ b/lib/pages/settings_dashboard/settings_stories/settings_stories_view.dart
@@ -1,10 +1,8 @@
-import 'package:flutter/material.dart';
-
import 'package:fluffychat/generated/l10n/app_localizations.dart';
-
import 'package:fluffychat/pages/settings_dashboard/settings_stories/settings_stories.dart';
import 'package:fluffychat/utils/localized_exception_extension.dart';
import 'package:fluffychat/widgets/avatar/avatar.dart';
+import 'package:flutter/material.dart';
import 'package:linagora_design_flutter/linagora_design_flutter.dart';
class SettingsStoriesView extends StatelessWidget {
@@ -13,20 +11,24 @@ class SettingsStoriesView extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ final onPrimary = LinagoraSysColors.material().onPrimary;
+ final l10n = L10n.of(context)!;
+ final theme = Theme.of(context);
+
return Scaffold(
- backgroundColor: LinagoraSysColors.material().onPrimary,
+ backgroundColor: onPrimary,
appBar: AppBar(
- backgroundColor: LinagoraSysColors.material().onPrimary,
- title: Text(L10n.of(context)!.whoCanSeeMyStories),
+ backgroundColor: onPrimary,
+ title: Text(l10n.whoCanSeeMyStories),
elevation: 0,
),
body: Column(
children: [
ListTile(
- title: Text(L10n.of(context)!.whoCanSeeMyStoriesDesc),
+ title: Text(l10n.whoCanSeeMyStoriesDesc),
leading: CircleAvatar(
- backgroundColor: Theme.of(context).secondaryHeaderColor,
- foregroundColor: Theme.of(context).colorScheme.secondary,
+ backgroundColor: theme.secondaryHeaderColor,
+ foregroundColor: theme.colorScheme.secondary,
child: const Icon(Icons.lock),
),
),
@@ -39,14 +41,14 @@ class SettingsStoriesView extends StatelessWidget {
if (error != null) {
return Center(child: Text(error.toLocalizedString(context)));
}
- if (snapshot.connectionState != ConnectionState.done) {
+ if (snapshot.connectionState != .done) {
return const Center(
child: CircularProgressIndicator.adaptive(strokeWidth: 2),
);
}
return ListView.builder(
itemCount: controller.users.length,
- itemBuilder: (context, i) {
+ itemBuilder: (_, i) {
final user = controller.users.keys.toList()[i];
return SwitchListTile.adaptive(
value: controller.users[user] ?? false,
diff --git a/lib/pages/settings_dashboard/settings_style/settings_style.dart b/lib/pages/settings_dashboard/settings_style/settings_style.dart
index 445c76aedd..0bf90d8845 100644
--- a/lib/pages/settings_dashboard/settings_style/settings_style.dart
+++ b/lib/pages/settings_dashboard/settings_style/settings_style.dart
@@ -1,10 +1,11 @@
import 'package:collection/collection.dart';
import 'package:file_picker/file_picker.dart';
-import 'package:fluffychat/widgets/matrix.dart';
-import 'package:flutter/material.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
+import 'package:fluffychat/widgets/matrix.dart';
import 'package:fluffychat/widgets/theme_builder.dart';
+import 'package:flutter/material.dart';
+
import 'settings_style_view.dart';
class SettingsStyle extends StatefulWidget {
@@ -16,31 +17,30 @@ class SettingsStyle extends StatefulWidget {
class SettingsStyleController extends State {
void setWallpaperAction() async {
- final picked = await FilePicker.platform.pickFiles(type: FileType.image);
+ final picked = await FilePicker.platform.pickFiles(type: .image);
final pickedFile = picked?.files.firstOrNull;
if (pickedFile == null) return;
- await Matrix.of(
- context,
- ).store.setItem(SettingKeys.wallpaper, pickedFile.path);
+ await matrix.store.setItem(SettingKeys.wallpaper, pickedFile.path);
setState(() {});
}
void deleteWallpaperAction() async {
- Matrix.of(context).wallpaper = null;
- await Matrix.of(context).store.deleteItem(SettingKeys.wallpaper);
+ matrix.wallpaper = null;
+ await matrix.store.deleteItem(SettingKeys.wallpaper);
setState(() {});
}
void setChatColor(Color? color) async {
- if (color != null) {
- AppConfig.colorSchemeSeed = color;
- ThemeController.of(context).setPrimaryColor(color);
- }
+ if (color == null) return;
+ AppConfig.colorSchemeSeed = color;
+ controller.setPrimaryColor(color);
}
- ThemeMode get currentTheme => ThemeController.of(context).themeMode;
- Color? get currentColor => ThemeController.of(context).primaryColor;
+ MatrixState get matrix => Matrix.of(context);
+ ThemeController get controller => ThemeController.of(context);
+ ThemeMode get currentTheme => controller.themeMode;
+ Color? get currentColor => controller.primaryColor;
static final List customColors = [
AppConfig.chatColor,
@@ -55,14 +55,14 @@ class SettingsStyleController extends State {
void switchTheme(ThemeMode? newTheme) {
if (newTheme == null) return;
switch (newTheme) {
- case ThemeMode.light:
- ThemeController.of(context).setThemeMode(ThemeMode.light);
+ case .light:
+ controller.setThemeMode(.light);
break;
- case ThemeMode.dark:
- ThemeController.of(context).setThemeMode(ThemeMode.dark);
+ case .dark:
+ controller.setThemeMode(.dark);
break;
- case ThemeMode.system:
- ThemeController.of(context).setThemeMode(ThemeMode.system);
+ case .system:
+ controller.setThemeMode(.system);
break;
}
setState(() {});
@@ -70,7 +70,7 @@ class SettingsStyleController extends State {
void changeFontSizeFactor(double d) {
setState(() => AppConfig.fontSizeFactor = d);
- Matrix.of(context).store.setItem(
+ matrix.store.setItem(
SettingKeys.fontSizeFactor,
AppConfig.fontSizeFactor.toString(),
);
@@ -78,12 +78,12 @@ class SettingsStyleController extends State {
void changeBubbleSizeFactor(double d) {
setState(() => AppConfig.bubbleSizeFactor = d);
- Matrix.of(context).store.setItem(
+ matrix.store.setItem(
SettingKeys.bubbleSizeFactor,
AppConfig.bubbleSizeFactor.toString(),
);
}
@override
- Widget build(BuildContext context) => SettingsStyleView(this);
+ Widget build(_) => SettingsStyleView(this);
}
diff --git a/lib/pages/settings_dashboard/settings_style/settings_style_view.dart b/lib/pages/settings_dashboard/settings_style/settings_style_view.dart
index a1c8f01adf..f93ef3f0d7 100644
--- a/lib/pages/settings_dashboard/settings_style/settings_style_view.dart
+++ b/lib/pages/settings_dashboard/settings_style/settings_style_view.dart
@@ -1,11 +1,10 @@
import 'package:fluffychat/config/app_config.dart';
-import 'package:fluffychat/widgets/matrix.dart';
-import 'package:flutter/material.dart';
-
import 'package:fluffychat/generated/l10n/app_localizations.dart';
-
import 'package:fluffychat/widgets/layouts/max_width_body.dart';
+import 'package:fluffychat/widgets/matrix.dart';
+import 'package:flutter/material.dart';
import 'package:linagora_design_flutter/linagora_design_flutter.dart';
+
import 'settings_style.dart';
class SettingsStyleView extends StatelessWidget {
@@ -17,12 +16,17 @@ class SettingsStyleView extends StatelessWidget {
Widget build(BuildContext context) {
const colorPickerSize = 32.0;
final wallpaper = Matrix.of(context).wallpaper;
+ final onPrimary = LinagoraSysColors.material().onPrimary;
+ final l10n = L10n.of(context)!;
+ final theme = Theme.of(context);
+ final colorScheme = theme.colorScheme;
+
return Scaffold(
- backgroundColor: LinagoraSysColors.material().onPrimary,
+ backgroundColor: onPrimary,
appBar: AppBar(
- backgroundColor: LinagoraSysColors.material().onPrimary,
+ backgroundColor: onPrimary,
leading: const BackButton(),
- title: Text(L10n.of(context)!.changeTheme),
+ title: Text(l10n.changeTheme),
),
body: MaxWidthBody(
withScrolling: true,
@@ -32,20 +36,18 @@ class SettingsStyleView extends StatelessWidget {
height: colorPickerSize + 24,
child: ListView(
shrinkWrap: true,
- scrollDirection: Axis.horizontal,
+ scrollDirection: .horizontal,
children: SettingsStyleController.customColors
.map(
(color) => Padding(
- padding: const EdgeInsets.all(12.0),
+ padding: const .all(12.0),
child: InkWell(
- borderRadius: BorderRadius.circular(colorPickerSize),
+ borderRadius: .circular(colorPickerSize),
onTap: () => controller.setChatColor(color),
child: color == null
? Material(
elevation: 0,
- borderRadius: BorderRadius.circular(
- colorPickerSize,
- ),
+ borderRadius: .circular(colorPickerSize),
child: Image.asset(
'assets/colors.png',
width: colorPickerSize,
@@ -55,9 +57,7 @@ class SettingsStyleView extends StatelessWidget {
: Material(
color: color,
elevation: 6,
- borderRadius: BorderRadius.circular(
- colorPickerSize,
- ),
+ borderRadius: .circular(colorPickerSize),
child: SizedBox(
width: colorPickerSize,
height: colorPickerSize,
@@ -81,45 +81,45 @@ class SettingsStyleView extends StatelessWidget {
const Divider(height: 1),
RadioListTile(
groupValue: controller.currentTheme,
- value: ThemeMode.system,
- title: Text(L10n.of(context)!.systemTheme),
+ value: .system,
+ title: Text(l10n.systemTheme),
onChanged: controller.switchTheme,
),
RadioListTile(
groupValue: controller.currentTheme,
- value: ThemeMode.light,
- title: Text(L10n.of(context)!.lightTheme),
+ value: .light,
+ title: Text(l10n.lightTheme),
onChanged: controller.switchTheme,
),
RadioListTile(
groupValue: controller.currentTheme,
- value: ThemeMode.dark,
- title: Text(L10n.of(context)!.darkTheme),
+ value: .dark,
+ title: Text(l10n.darkTheme),
onChanged: controller.switchTheme,
),
const Divider(height: 1),
ListTile(
title: Text(
- L10n.of(context)!.wallpaper,
+ l10n.wallpaper,
style: TextStyle(
- color: Theme.of(context).colorScheme.secondary,
- fontWeight: FontWeight.bold,
+ color: colorScheme.secondary,
+ fontWeight: .bold,
),
),
),
if (wallpaper != null)
ListTile(
- title: Image.file(wallpaper, height: 38, fit: BoxFit.cover),
+ title: Image.file(wallpaper, height: 38, fit: .cover),
trailing: const Icon(Icons.delete_outlined, color: Colors.red),
onTap: controller.deleteWallpaperAction,
),
Builder(
builder: (context) {
return ListTile(
- title: Text(L10n.of(context)!.changeWallpaper),
+ title: Text(l10n.changeWallpaper),
trailing: Icon(
Icons.photo_outlined,
- color: Theme.of(context).textTheme.bodyLarge?.color,
+ color: theme.textTheme.bodyLarge?.color,
),
onTap: controller.setWallpaperAction,
);
@@ -128,29 +128,27 @@ class SettingsStyleView extends StatelessWidget {
const Divider(height: 1),
ListTile(
title: Text(
- L10n.of(context)!.messages,
+ l10n.messages,
style: TextStyle(
- color: Theme.of(context).colorScheme.secondary,
- fontWeight: FontWeight.bold,
+ color: colorScheme.secondary,
+ fontWeight: .bold,
),
),
),
Container(
- alignment: Alignment.centerLeft,
- padding: const EdgeInsets.symmetric(horizontal: 12),
+ alignment: .centerLeft,
+ padding: const .symmetric(horizontal: 12),
child: Material(
- color: Theme.of(context).colorScheme.primary,
+ color: colorScheme.primary,
elevation: 6,
- shadowColor: Theme.of(
- context,
- ).secondaryHeaderColor.withAlpha(100),
- borderRadius: BorderRadius.circular(AppConfig.borderRadius),
+ shadowColor: theme.secondaryHeaderColor.withAlpha(100),
+ borderRadius: .circular(AppConfig.borderRadius),
child: Padding(
- padding: EdgeInsets.all(16 * AppConfig.bubbleSizeFactor),
+ padding: .all(16 * AppConfig.bubbleSizeFactor),
child: Text(
'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor',
style: TextStyle(
- color: Theme.of(context).colorScheme.onPrimary,
+ color: colorScheme.onPrimary,
fontSize:
AppConfig.messageFontSize * AppConfig.fontSizeFactor,
),
@@ -159,7 +157,7 @@ class SettingsStyleView extends StatelessWidget {
),
),
ListTile(
- title: Text(L10n.of(context)!.fontSize),
+ title: Text(l10n.fontSize),
trailing: Text('× ${AppConfig.fontSizeFactor}'),
),
Slider.adaptive(
@@ -171,7 +169,7 @@ class SettingsStyleView extends StatelessWidget {
onChanged: controller.changeFontSizeFactor,
),
ListTile(
- title: Text(L10n.of(context)!.bubbleSize),
+ title: Text(l10n.bubbleSize),
trailing: Text('× ${AppConfig.bubbleSizeFactor}'),
),
Slider.adaptive(
diff --git a/lib/pages/twake_welcome/twake_welcome.dart b/lib/pages/twake_welcome/twake_welcome.dart
index 8ed9719466..1ff0dd78f1 100644
--- a/lib/pages/twake_welcome/twake_welcome.dart
+++ b/lib/pages/twake_welcome/twake_welcome.dart
@@ -1,6 +1,7 @@
import 'dart:async';
import 'package:fluffychat/config/app_config.dart';
+import 'package:fluffychat/config/go_routes/app_route_paths.dart';
import 'package:equatable/equatable.dart';
import 'package:fluffychat/presentation/mixins/connect_page_mixin.dart';
import 'package:fluffychat/pages/twake_welcome/twake_welcome_view.dart';
@@ -40,7 +41,7 @@ class TwakeWelcome extends StatefulWidget {
class TwakeWelcomeController extends State with ConnectPageMixin {
void goToHomeserverPicker() {
if (widget.arg != null && widget.arg?.isAddAnotherAccount == true) {
- context.push('/rooms/addaccount/homeserverpicker');
+ context.push(AppRoutePaths.addAccountHomeserverPickerFull);
} else {
context.push('/home/homeserverpicker');
}
diff --git a/lib/resource/image_paths.dart b/lib/resource/image_paths.dart
index 89d3042575..69988e5459 100644
--- a/lib/resource/image_paths.dart
+++ b/lib/resource/image_paths.dart
@@ -63,6 +63,8 @@ class ImagePaths {
static String get icShieldLockFill =>
_getImagePath('ic_shield_lock_fill.svg');
+ static String get icRecoveryKey => _getImagePath('ic_recovery_key.svg');
+
static String get icBrandingPng => _getAssetPath('branding.png');
static String get lottieChat => _getAssetPath('lottie-chat.json');
static String get icGhost => _getImagePath('ic_ghost.svg');
diff --git a/lib/widgets/layouts/adaptive_layout/adaptive_scaffold_primary_navigation_view.dart b/lib/widgets/layouts/adaptive_layout/adaptive_scaffold_primary_navigation_view.dart
index 47c97b99c4..8d08375c3f 100644
--- a/lib/widgets/layouts/adaptive_layout/adaptive_scaffold_primary_navigation_view.dart
+++ b/lib/widgets/layouts/adaptive_layout/adaptive_scaffold_primary_navigation_view.dart
@@ -1,3 +1,4 @@
+import 'package:fluffychat/config/go_routes/app_route_paths.dart';
import 'package:fluffychat/pages/chat_list/client_chooser_button_style.dart';
import 'package:fluffychat/widgets/avatar/avatar.dart';
import 'package:fluffychat/widgets/layouts/adaptive_layout/adaptive_scaffold_primary_navigation_style.dart';
@@ -73,7 +74,7 @@ class AdaptiveScaffoldPrimaryNavigationView extends StatelessWidget {
size: AdaptiveScaffoldPrimaryNavigationStyle.avatarSize,
fontSize:
ClientChooserButtonStyle.avatarFontSizeInAppBar,
- onTap: () => context.go('/rooms/profile'),
+ onTap: () => context.go(AppRoutePaths.profileFull),
);
},
),