From 26feae4485d9465a206120e557c8ec8d44b388af Mon Sep 17 00:00:00 2001 From: istalri Date: Tue, 2 Jun 2026 21:43:14 +0200 Subject: [PATCH] CleanUp Autoformat for better readable code, using autofocus instead of useState and focus element --- lib/controllers/client_controller.dart | 4 +- lib/main.dart | 2 +- lib/pages/login_page.dart | 59 ++--- lib/pages/select_server_page.dart | 295 +++++++++++++------------ 4 files changed, 182 insertions(+), 178 deletions(-) diff --git a/lib/controllers/client_controller.dart b/lib/controllers/client_controller.dart index f1ff6a6..fc4a31f 100644 --- a/lib/controllers/client_controller.dart +++ b/lib/controllers/client_controller.dart @@ -263,12 +263,12 @@ class ClientController extends AsyncNotifier { } } - Future discoverHomeserver(Uri homeserver) async { + Future discoverHomeserver(Uri homeserver) async { try { final response = await _sendCommand("discover_homeserver", { "user_id": "@fake-user:${homeserver.host}", }); - return response["m.homeserver"]?["base_url"]; + return Uri.parse(response["m.homeserver"]?["base_url"]); } catch (error) { return null; } diff --git a/lib/main.dart b/lib/main.dart index cb1e53d..dab4e16 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -123,7 +123,7 @@ class App extends StatelessWidget { return Loading(); } - if (!clientState.isLoggedIn) { + if (!clientState.isLoggedIn) { return SelectServerPage(); } else if (!clientState.isVerified) { return VerifyPage(); diff --git a/lib/pages/login_page.dart b/lib/pages/login_page.dart index 5d12d00..a321944 100644 --- a/lib/pages/login_page.dart +++ b/lib/pages/login_page.dart @@ -15,17 +15,8 @@ class LoginPage extends HookConsumerWidget { final client = ref.watch(ClientController.provider.notifier); final isLoggingIn = useState(false); final hasError = useState(false); - final userNameFocusNode = useFocusNode(); final passwordFocusNode = useFocusNode(); - //This is the safe way to request things directly after page load. - useEffect(() { - WidgetsBinding.instance.addPostFrameCallback((_) { - userNameFocusNode.requestFocus(); - }); - return null; - }, []); - final theme = Theme.of(context); final username = useTextEditingController(); @@ -40,8 +31,8 @@ class LoginPage extends HookConsumerWidget { LoginRequest( username: username.text, password: password.text, - homeserverUrl: homeserver.origin - ) + homeserverUrl: homeserver.origin, + ), ); if (!context.mounted) return; @@ -52,16 +43,13 @@ class LoginPage extends HookConsumerWidget { SnackBar( content: Text( "Login failed. Is your password right?\nError: $error", - style: TextStyle( - color: theme.colorScheme.onErrorContainer, - ), + style: TextStyle(color: theme.colorScheme.onErrorContainer), ), backgroundColor: theme.colorScheme.errorContainer, ), ); isLoggingIn.value = false; - } - else{ + } else { Navigator.pop(context); } passwordFocusNode.requestFocus(); @@ -72,8 +60,8 @@ class LoginPage extends HookConsumerWidget { appBar: Appbar( leading: IconButton( icon: Icon(Icons.arrow_back), - onPressed: () => Navigator.pop(context) - ), + onPressed: () => Navigator.pop(context), + ), ), body: AlertDialog( title: Text("Login to ${homeserver.host}"), @@ -81,12 +69,10 @@ class LoginPage extends HookConsumerWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - "Enter your login credentials:", - ), + Text("Enter your login credentials:"), SizedBox(height: 12), TextField( - focusNode: userNameFocusNode, + autofocus: true, textInputAction: TextInputAction.next, onChanged: (newVal) { if (hasError.value) { @@ -98,11 +84,11 @@ class LoginPage extends HookConsumerWidget { enabledBorder: OutlineInputBorder( borderSide: BorderSide( width: hasError.value ? 4 : 2, - color: hasError.value - ? theme.colorScheme.error - : theme.colorScheme.primary + color: hasError.value + ? theme.colorScheme.error + : theme.colorScheme.primary, ), - ) + ), ), controller: username, ), @@ -123,29 +109,26 @@ class LoginPage extends HookConsumerWidget { borderSide: BorderSide( width: hasError.value ? 4 : 2, color: hasError.value - ? theme.colorScheme.error - : theme.colorScheme.primary - ) + ? theme.colorScheme.error + : theme.colorScheme.primary, + ), ), enabledBorder: OutlineInputBorder( borderSide: BorderSide( width: hasError.value ? 4 : 2, - color: hasError.value - ? theme.colorScheme.error - : theme.colorScheme.primary + color: hasError.value + ? theme.colorScheme.error + : theme.colorScheme.primary, ), - ) + ), ), controller: password, obscureText: true, - ), + ), ], ), actions: [ - TextButton( - onPressed: () => tryLogin(), - child: Text("Sign In"), - ), + TextButton(onPressed: () => tryLogin(), child: Text("Sign In")), ], ), ); diff --git a/lib/pages/select_server_page.dart b/lib/pages/select_server_page.dart index af9be91..c9f4f37 100644 --- a/lib/pages/select_server_page.dart +++ b/lib/pages/select_server_page.dart @@ -20,14 +20,14 @@ class SelectServerPage extends HookConsumerWidget { final hasError = useState(false); final isLoading = useState(false); final homeserverFocusNode = useFocusNode(); - + final launch = ref.watch(LaunchHelper.provider).launchUrl; final homeserverUrl = useTextEditingController(); Future setHomeserver(Uri? newHomeserver) async { isLoading.value = true; - if(newHomeserver?.hasScheme == false){ + if (newHomeserver?.hasScheme == false) { newHomeserver = Uri.https(newHomeserver!.path); } @@ -49,159 +49,180 @@ class SelectServerPage extends HookConsumerWidget { ); } else { homeserverUrl.text = newHomeserver!.origin; - Navigator.push(context, MaterialPageRoute(builder: (_) => LoginPage(homeserver: Uri.parse(newUrl)))); + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => LoginPage(homeserver: Uri.parse(newUrl)), + ), + ); } } - homeserverFocusNode.requestFocus(); - isLoading.value = false; + if (context.mounted) { + homeserverFocusNode.requestFocus(); + isLoading.value = false; + } } return Scaffold( appBar: Appbar(), - body: isLoading.value - ? const Loading() - : Center( - child: ConstrainedBox( - constraints: BoxConstraints(maxWidth: 600), - child: Column( - children: [ - Row( - children: [ - SvgPicture.asset("assets/icon.svg", width: 128), - SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + body: isLoading.value + ? const Loading() + : Center( + child: ConstrainedBox( + constraints: BoxConstraints(maxWidth: 600), + child: Column( + children: [ + Row( children: [ - Text("Nexus", style: theme.textTheme.displayMedium), - Text( - "A Simple Matrix Client", - style: theme.textTheme.headlineMedium, - overflow: TextOverflow.ellipsis, + SvgPicture.asset("assets/icon.svg", width: 128), + SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Nexus", + style: theme.textTheme.displayMedium, + ), + Text( + "A Simple Matrix Client", + style: theme.textTheme.headlineMedium, + overflow: TextOverflow.ellipsis, + ), + ], + ), ), ], ), - ), - ], - ), - Padding( - padding: EdgeInsetsGeometry.symmetric(vertical: 12), - child: Divider(), - ), - DividerText("Enter a homeserver domain:"), - Row( - spacing: 8, - children: [ - Expanded( - child: TextField( - focusNode: homeserverFocusNode, - textInputAction: TextInputAction.done, - onSubmitted: (_) => setHomeserver(Uri.tryParse(homeserverUrl.text)), - onChanged: (newVal) { - if (hasError.value) { - hasError.value = false; - } - }, - controller: homeserverUrl, - decoration: InputDecoration( - labelText: "Homeserver URL (e.g. matrix.org)", - hintText: "e.g. matrix.org", - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - width: hasError.value ? 4 : 2, - color: hasError.value - ? theme.colorScheme.error - : theme.colorScheme.primary - ) - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - width: hasError.value ? 4 : 2, - color: hasError.value - ? theme.colorScheme.error - : theme.colorScheme.primary - ) - ), - ), + Padding( + padding: EdgeInsetsGeometry.symmetric(vertical: 12), + child: Divider(), ), - ), - IconButton.filled( - tooltip: "Confirm homeserver choice", - onPressed: isLoading.value - ? null - : () => setHomeserver(Uri.tryParse(homeserverUrl.text)), - icon: Icon(Icons.check), - ), - ], - ), - Expanded( - child: ListView( - padding: EdgeInsets.only(top: 12), - children: [ - DividerText("Or, choose from some popular homeservers:"), - ...([ - Homeserver( - name: "Matrix.org", - description: - "The Matrix.org Foundation offers the matrix.org homeserver as an easy entry point for anyone wanting to try out Matrix.", - url: Uri.https("matrix.org"), - iconUrl: - "https://raw.githubusercontent.com/element-hq/logos/refs/heads/master/matrix/matrix-favicon${Theme.brightnessOf(context) == Brightness.dark ? "-white" : ""}.png", - ), - Homeserver( - name: "Federated Nexus", - description: - "Federated Nexus is a community resource hosting multiple FOSS (especially federated) services, including Matrix and Forgejo. By the same developers who made Nexus client.", - url: Uri.https("federated.nexus"), - iconUrl: "https://federated.nexus/images/icon.png", - ), - Homeserver( - name: "Unredacted", - description: - "Unredacted is a 501(c)(3) non-profit organization that builds Internet infrastructure and services to help people evade censorship and protect their right to privacy.", - url: Uri.https("unredacted.org", "services/si/matrix"), - iconUrl: "https://unredacted.org/favicon.ico", - ), - Homeserver( - name: "Lorem ipsum", - description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", - url: Uri.https("loremipsum.io"), - iconUrl: "https://loremipsum.io/favicon.ico" - ), - ].map( - (homeserver) => Card( - child: ListTile( - title: Text(homeserver.name), - leading: Image.network( - homeserver.iconUrl, - errorBuilder: (_, _, _) => SizedBox.shrink(), - height: 32, - ), - subtitle: Text(homeserver.description), - onTap: isLoading.value - ? null - : () => setHomeserver(homeserver.url), - trailing: IconButton( - tooltip: "Launch homeserver info page", - onPressed: () => launch(homeserver.url), - icon: Icon(Icons.info_outline), + DividerText("Enter a homeserver domain:"), + Row( + spacing: 8, + children: [ + Expanded( + child: TextField( + focusNode: homeserverFocusNode, + textInputAction: TextInputAction.done, + onSubmitted: (_) => + setHomeserver(Uri.tryParse(homeserverUrl.text)), + onChanged: (newVal) { + if (hasError.value) { + hasError.value = false; + } + }, + controller: homeserverUrl, + decoration: InputDecoration( + labelText: "Homeserver URL (e.g. matrix.org)", + hintText: "e.g. matrix.org", + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + width: hasError.value ? 4 : 2, + color: hasError.value + ? theme.colorScheme.error + : theme.colorScheme.primary, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + width: hasError.value ? 4 : 2, + color: hasError.value + ? theme.colorScheme.error + : theme.colorScheme.primary, + ), + ), ), ), ), - )), + IconButton.filled( + tooltip: "Confirm homeserver choice", + onPressed: isLoading.value + ? null + : () => setHomeserver( + Uri.tryParse(homeserverUrl.text), + ), + icon: Icon(Icons.check), + ), + ], + ), + Expanded( + child: ListView( + padding: EdgeInsets.only(top: 12), + children: [ + DividerText( + "Or, choose from some popular homeservers:", + ), + ...([ + Homeserver( + name: "Matrix.org", + description: + "The Matrix.org Foundation offers the matrix.org homeserver as an easy entry point for anyone wanting to try out Matrix.", + url: Uri.https("matrix.org"), + iconUrl: + "https://raw.githubusercontent.com/element-hq/logos/refs/heads/master/matrix/matrix-favicon${Theme.brightnessOf(context) == Brightness.dark ? "-white" : ""}.png", + ), + Homeserver( + name: "Federated Nexus", + description: + "Federated Nexus is a community resource hosting multiple FOSS (especially federated) services, including Matrix and Forgejo. By the same developers who made Nexus client.", + url: Uri.https("federated.nexus"), + iconUrl: + "https://federated.nexus/images/icon.png", + ), + Homeserver( + name: "Unredacted", + description: + "Unredacted is a 501(c)(3) non-profit organization that builds Internet infrastructure and services to help people evade censorship and protect their right to privacy.", + url: Uri.https( + "unredacted.org", + "services/si/matrix", + ), + iconUrl: "https://unredacted.org/favicon.ico", + ), + Homeserver( + name: "Lorem ipsum", + description: + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", + url: Uri.https("loremipsum.io"), + iconUrl: "https://loremipsum.io/favicon.ico", + ), + ].map( + (homeserver) => Card( + child: ListTile( + title: Text(homeserver.name), + leading: Image.network( + homeserver.iconUrl, + errorBuilder: (_, _, _) => SizedBox.shrink(), + height: 32, + ), + subtitle: Text(homeserver.description), + onTap: isLoading.value + ? null + : () => setHomeserver(homeserver.url), + trailing: IconButton( + tooltip: "Launch homeserver info page", + onPressed: () => launch(homeserver.url), + icon: Icon(Icons.info_outline), + ), + ), + ), + )), + ], + ), + ), + SizedBox(height: 5), + TextButton( + onPressed: () => + launch(Uri.https("servers.joinmatrix.org")), + child: Text("See more homeservers..."), + ), ], ), ), - SizedBox(height: 5), - TextButton( - onPressed: () => launch(Uri.https("servers.joinmatrix.org")), - child: Text("See more homeservers..."), - ), - ], - ), - ), - ), + ), ); } }