diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index e9146f2cf..8c0c677f9 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -2760,5 +2760,6 @@ "loginWithMatrixId": "Login with Matrix-ID", "discoverHomeservers": "Discover homeservers", "whatIsAHomeserver": "What is a homeserver?", - "homeserverDescription": "All your data is stored on the homeserver, just like an email provider. You can choose which homeserver you want to use, while you can still communicate with everyone. Learn more at at https://matrix.org." + "homeserverDescription": "All your data is stored on the homeserver, just like an email provider. You can choose which homeserver you want to use, while you can still communicate with everyone. Learn more at at https://matrix.org.", + "doesNotSeemToBeAValidHomeserver": "Doesn't seem to be a compatible homeserver. Wrong URL?" } diff --git a/lib/pages/chat_members/chat_members_view.dart b/lib/pages/chat_members/chat_members_view.dart index b699fcef0..daa681a52 100644 --- a/lib/pages/chat_members/chat_members_view.dart +++ b/lib/pages/chat_members/chat_members_view.dart @@ -34,6 +34,7 @@ class ChatMembersView extends StatelessWidget { (room.summary.mInvitedMemberCount ?? 0); final error = controller.error; + final theme = Theme.of(context); return Scaffold( appBar: AppBar( @@ -90,6 +91,16 @@ class ChatMembersView extends StatelessWidget { controller: controller.filterController, onChanged: controller.setFilter, decoration: InputDecoration( + filled: true, + fillColor: theme.colorScheme.secondaryContainer, + border: OutlineInputBorder( + borderSide: BorderSide.none, + borderRadius: BorderRadius.circular(99), + ), + hintStyle: TextStyle( + color: theme.colorScheme.onPrimaryContainer, + fontWeight: FontWeight.normal, + ), prefixIcon: const Icon(Icons.search_outlined), hintText: L10n.of(context)!.search, ), diff --git a/lib/pages/chat_search/chat_search_view.dart b/lib/pages/chat_search/chat_search_view.dart index e08f25a2b..e29fa1d01 100644 --- a/lib/pages/chat_search/chat_search_view.dart +++ b/lib/pages/chat_search/chat_search_view.dart @@ -31,6 +31,8 @@ class ChatSearchView extends StatelessWidget { ); } + final theme = Theme.of(context); + return Scaffold( appBar: AppBar( leading: const Center(child: BackButton()), @@ -59,6 +61,16 @@ class ChatSearchView extends StatelessWidget { decoration: InputDecoration( hintText: L10n.of(context)!.search, suffixIcon: const Icon(Icons.search_outlined), + filled: true, + fillColor: theme.colorScheme.secondaryContainer, + border: OutlineInputBorder( + borderSide: BorderSide.none, + borderRadius: BorderRadius.circular(99), + ), + hintStyle: TextStyle( + color: theme.colorScheme.onPrimaryContainer, + fontWeight: FontWeight.normal, + ), ), ), ), diff --git a/lib/pages/homeserver_picker/homeserver_picker.dart b/lib/pages/homeserver_picker/homeserver_picker.dart index 32f1356d7..955aa3c56 100644 --- a/lib/pages/homeserver_picker/homeserver_picker.dart +++ b/lib/pages/homeserver_picker/homeserver_picker.dart @@ -86,7 +86,17 @@ class HomeserverPickerController extends State { Future checkHomeserverAction([_]) async { homeserverController.text = homeserverController.text.trim().toLowerCase().replaceAll(' ', '-'); - if (homeserverController.text == _lastCheckedUrl) return; + + if (homeserverController.text.isEmpty) { + setState(() { + error = loginFlows = null; + isLoading = false; + Matrix.of(context).getLoginClient().homeserver = null; + }); + return; + } + if (_lastCheckedUrl == homeserverController.text) return; + _lastCheckedUrl = homeserverController.text; setState(() { error = loginFlows = null; @@ -102,7 +112,12 @@ class HomeserverPickerController extends State { final (_, _, loginFlows) = await client.checkHomeserver(homeserver); this.loginFlows = loginFlows; } catch (e) { - setState(() => error = (e).toLocalizedString(context)); + setState( + () => error = (e).toLocalizedString( + context, + ExceptionContext.checkHomeserver, + ), + ); } finally { if (mounted) { setState(() => isLoading = false); diff --git a/lib/pages/homeserver_picker/homeserver_picker_view.dart b/lib/pages/homeserver_picker/homeserver_picker_view.dart index f99f949b9..f381cfd51 100644 --- a/lib/pages/homeserver_picker/homeserver_picker_view.dart +++ b/lib/pages/homeserver_picker/homeserver_picker_view.dart @@ -76,6 +76,8 @@ class HomeserverPickerView extends StatelessWidget { controller.tryCheckHomeserverActionWithoutCooldown, onTap: controller.tryCheckHomeserverActionWithCooldown, controller: controller.homeserverController, + autocorrect: false, + keyboardType: TextInputType.url, decoration: InputDecoration( prefixIcon: controller.isLoading ? Container( diff --git a/lib/pages/invitation_selection/invitation_selection_view.dart b/lib/pages/invitation_selection/invitation_selection_view.dart index 795334e04..6ea03d8ed 100644 --- a/lib/pages/invitation_selection/invitation_selection_view.dart +++ b/lib/pages/invitation_selection/invitation_selection_view.dart @@ -29,6 +29,7 @@ class InvitationSelectionView extends StatelessWidget { } final groupName = room.name.isEmpty ? L10n.of(context)!.group : room.name; + final theme = Theme.of(context); return Scaffold( appBar: AppBar( leading: const Center(child: BackButton()), @@ -44,6 +45,16 @@ class InvitationSelectionView extends StatelessWidget { child: TextField( textInputAction: TextInputAction.search, decoration: InputDecoration( + filled: true, + fillColor: theme.colorScheme.secondaryContainer, + border: OutlineInputBorder( + borderSide: BorderSide.none, + borderRadius: BorderRadius.circular(99), + ), + hintStyle: TextStyle( + color: theme.colorScheme.onPrimaryContainer, + fontWeight: FontWeight.normal, + ), hintText: L10n.of(context)!.inviteContactToGroup(groupName), prefixIcon: controller.loading ? const Padding( diff --git a/lib/pages/new_group/new_group_view.dart b/lib/pages/new_group/new_group_view.dart index 0f86efb45..54c9a1286 100644 --- a/lib/pages/new_group/new_group_view.dart +++ b/lib/pages/new_group/new_group_view.dart @@ -61,12 +61,13 @@ class NewGroupView extends StatelessWidget { readOnly: controller.loading, decoration: InputDecoration( prefixIcon: const Icon(Icons.people_outlined), - hintText: L10n.of(context)!.groupName, + labelText: L10n.of(context)!.groupName, ), ), ), const SizedBox(height: 16), SwitchListTile.adaptive( + contentPadding: const EdgeInsets.symmetric(horizontal: 32), secondary: const Icon(Icons.public_outlined), title: Text(L10n.of(context)!.groupIsPublic), value: controller.publicGroup, @@ -76,6 +77,8 @@ class NewGroupView extends StatelessWidget { duration: FluffyThemes.animationDuration, child: controller.publicGroup ? SwitchListTile.adaptive( + contentPadding: + const EdgeInsets.symmetric(horizontal: 32), secondary: const Icon(Icons.search_outlined), title: Text(L10n.of(context)!.groupCanBeFoundViaSearch), value: controller.groupCanBeFound, @@ -86,6 +89,7 @@ class NewGroupView extends StatelessWidget { : const SizedBox.shrink(), ), SwitchListTile.adaptive( + contentPadding: const EdgeInsets.symmetric(horizontal: 32), secondary: Icon( Icons.lock_outlined, color: theme.colorScheme.onSurface, @@ -108,16 +112,7 @@ class NewGroupView extends StatelessWidget { controller.loading ? null : controller.submitAction, child: controller.loading ? const LinearProgressIndicator() - : Row( - children: [ - Expanded( - child: Text( - L10n.of(context)!.createGroupAndInviteUsers, - ), - ), - Icon(Icons.adaptive.arrow_forward_outlined), - ], - ), + : Text(L10n.of(context)!.createGroupAndInviteUsers), ), ), ), diff --git a/lib/pages/new_private_chat/new_private_chat_view.dart b/lib/pages/new_private_chat/new_private_chat_view.dart index ceee0ef45..f46e8a4c8 100644 --- a/lib/pages/new_private_chat/new_private_chat_view.dart +++ b/lib/pages/new_private_chat/new_private_chat_view.dart @@ -54,6 +54,16 @@ class NewPrivateChatView extends StatelessWidget { onChanged: controller.searchUsers, decoration: InputDecoration( hintText: L10n.of(context)!.searchForUsers, + filled: true, + fillColor: theme.colorScheme.secondaryContainer, + border: OutlineInputBorder( + borderSide: BorderSide.none, + borderRadius: BorderRadius.circular(99), + ), + hintStyle: TextStyle( + color: theme.colorScheme.onPrimaryContainer, + fontWeight: FontWeight.normal, + ), prefixIcon: searchResponse == null ? const Icon(Icons.search_outlined) : FutureBuilder( diff --git a/lib/pages/new_space/new_space_view.dart b/lib/pages/new_space/new_space_view.dart index 2f46e5e73..ed60d670d 100644 --- a/lib/pages/new_space/new_space_view.dart +++ b/lib/pages/new_space/new_space_view.dart @@ -51,18 +51,20 @@ class NewSpaceView extends StatelessWidget { readOnly: controller.loading, decoration: InputDecoration( prefixIcon: const Icon(Icons.people_outlined), - hintText: L10n.of(context)!.spaceName, + labelText: L10n.of(context)!.spaceName, errorText: controller.nameError, ), ), ), const SizedBox(height: 16), SwitchListTile.adaptive( + contentPadding: const EdgeInsets.symmetric(horizontal: 32), title: Text(L10n.of(context)!.spaceIsPublic), value: controller.publicGroup, onChanged: controller.setPublicGroup, ), ListTile( + contentPadding: const EdgeInsets.symmetric(horizontal: 32), trailing: const Padding( padding: EdgeInsets.symmetric(horizontal: 16.0), child: Icon(Icons.info_outlined), @@ -78,16 +80,7 @@ class NewSpaceView extends StatelessWidget { controller.loading ? null : controller.submitAction, child: controller.loading ? const LinearProgressIndicator() - : Row( - children: [ - Expanded( - child: Text( - L10n.of(context)!.createNewSpace, - ), - ), - Icon(Icons.adaptive.arrow_forward_outlined), - ], - ), + : Text(L10n.of(context)!.createNewSpace), ), ), ), diff --git a/lib/pages/settings_ignore_list/settings_ignore_list_view.dart b/lib/pages/settings_ignore_list/settings_ignore_list_view.dart index e66387503..63466ddbb 100644 --- a/lib/pages/settings_ignore_list/settings_ignore_list_view.dart +++ b/lib/pages/settings_ignore_list/settings_ignore_list_view.dart @@ -46,7 +46,7 @@ class SettingsIgnoreListView extends StatelessWidget { labelText: L10n.of(context)!.blockUsername, suffixIcon: IconButton( tooltip: L10n.of(context)!.block, - icon: const Icon(Icons.send_outlined), + icon: const Icon(Icons.add), onPressed: () => controller.ignoreUser(context), ), ), diff --git a/lib/pages/settings_password/settings_password_view.dart b/lib/pages/settings_password/settings_password_view.dart index ee80e9361..3e9b64f33 100644 --- a/lib/pages/settings_password/settings_password_view.dart +++ b/lib/pages/settings_password/settings_password_view.dart @@ -17,12 +17,6 @@ class SettingsPasswordView extends StatelessWidget { return Scaffold( appBar: AppBar( title: Text(L10n.of(context)!.changePassword), - actions: [ - TextButton( - child: Text(L10n.of(context)!.passwordRecoverySettings), - onPressed: () => context.go('/rooms/settings/security/3pid'), - ), - ], ), body: ListTileTheme( iconColor: theme.colorScheme.onSurface, @@ -31,13 +25,6 @@ class SettingsPasswordView extends StatelessWidget { padding: const EdgeInsets.all(16.0), child: Column( children: [ - Center( - child: Icon( - Icons.key_outlined, - color: theme.dividerColor, - size: 80, - ), - ), const SizedBox(height: 16), TextField( controller: controller.oldPasswordController, @@ -46,18 +33,22 @@ class SettingsPasswordView extends StatelessWidget { autofocus: true, readOnly: controller.loading, decoration: InputDecoration( - hintText: L10n.of(context)!.pleaseEnterYourCurrentPassword, + prefixIcon: const Icon(Icons.lock_outlined), + hintText: '********', + labelText: L10n.of(context)!.pleaseEnterYourCurrentPassword, errorText: controller.oldPasswordError, ), ), - const Divider(height: 32), + const Divider(height: 64), TextField( controller: controller.newPassword1Controller, obscureText: true, autocorrect: false, readOnly: controller.loading, decoration: InputDecoration( - hintText: L10n.of(context)!.newPassword, + prefixIcon: const Icon(Icons.lock_reset_outlined), + hintText: '********', + labelText: L10n.of(context)!.newPassword, errorText: controller.newPassword1Error, ), ), @@ -68,22 +59,28 @@ class SettingsPasswordView extends StatelessWidget { autocorrect: false, readOnly: controller.loading, decoration: InputDecoration( - hintText: L10n.of(context)!.repeatPassword, + prefixIcon: const Icon(Icons.repeat_outlined), + hintText: '********', + labelText: L10n.of(context)!.repeatPassword, errorText: controller.newPassword2Error, ), ), - const SizedBox(height: 16), + const SizedBox(height: 32), SizedBox( width: double.infinity, - child: ElevatedButton.icon( + child: ElevatedButton( onPressed: controller.loading ? null : controller.changePassword, - icon: const Icon(Icons.send_outlined), - label: controller.loading + child: controller.loading ? const LinearProgressIndicator() : Text(L10n.of(context)!.changePassword), ), ), + const SizedBox(height: 16), + TextButton( + child: Text(L10n.of(context)!.passwordRecoverySettings), + onPressed: () => context.go('/rooms/settings/security/3pid'), + ), ], ), ), diff --git a/lib/pages/settings_security/settings_security_view.dart b/lib/pages/settings_security/settings_security_view.dart index 76ea243a0..a805a6e33 100644 --- a/lib/pages/settings_security/settings_security_view.dart +++ b/lib/pages/settings_security/settings_security_view.dart @@ -87,9 +87,7 @@ class SettingsSecurityView extends StatelessWidget { onTap: controller.setAppLockAction, ), }, - Divider( - color: theme.dividerColor, - ), + Divider(color: theme.dividerColor), ListTile( title: Text( L10n.of(context)!.account, @@ -118,13 +116,14 @@ class SettingsSecurityView extends StatelessWidget { ), ListTile( iconColor: Colors.orange, - leading: const Icon(Icons.tap_and_play), + leading: const Icon(Icons.delete_sweep_outlined), title: Text( L10n.of(context)!.dehydrate, style: const TextStyle(color: Colors.orange), ), onTap: controller.dehydrateAction, ), + Divider(color: theme.dividerColor), ListTile( iconColor: Colors.red, leading: const Icon(Icons.delete_outlined), diff --git a/lib/utils/localized_exception_extension.dart b/lib/utils/localized_exception_extension.dart index f9473c3f5..0dfbe3dce 100644 --- a/lib/utils/localized_exception_extension.dart +++ b/lib/utils/localized_exception_extension.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; +import 'package:http/http.dart'; import 'package:matrix/encryption.dart'; import 'package:matrix/matrix.dart'; @@ -69,9 +70,14 @@ extension LocalizedExceptionExtension on Object { } if (this is IOException || this is SocketException || - this is SyncConnectionException) { + this is SyncConnectionException || + this is ClientException) { return L10n.of(context)!.noConnectionToTheServer; } + if (this is FormatException && + exceptionContext == ExceptionContext.checkHomeserver) { + return L10n.of(context)!.doesNotSeemToBeAValidHomeserver; + } if (this is String) return toString(); if (this is UiaException) return toString(); Logs().w('Something went wrong: ', this); @@ -81,4 +87,5 @@ extension LocalizedExceptionExtension on Object { enum ExceptionContext { changePassword, + checkHomeserver, }