From 85cf7cdf13484ca34f1c7d9b2e57451599e3c5c9 Mon Sep 17 00:00:00 2001 From: Bernd Steckmeister Date: Sun, 19 Apr 2026 20:22:30 +0200 Subject: [PATCH] fix: server page empty by default, https prefix non-editable, StateProvider for instant redirect --- lib/core/router.dart | 3 +- lib/features/auth/login_notifier.dart | 15 +++--- lib/features/auth/login_page.dart | 4 +- lib/features/auth/server_page.dart | 66 ++++++++++++--------------- lib/main.dart | 15 +++--- 5 files changed, 50 insertions(+), 53 deletions(-) diff --git a/lib/core/router.dart b/lib/core/router.dart index 7f95ef1..5f2a8d7 100644 --- a/lib/core/router.dart +++ b/lib/core/router.dart @@ -10,8 +10,7 @@ import 'package:pyramid/layout/shell_page.dart'; final routerProvider = Provider((ref) { final isLoggedIn = ref.watch(isLoggedInProvider); - final homeserverAsync = ref.watch(homeserverProvider); - final hasServer = homeserverAsync.valueOrNull != null; + final hasServer = ref.watch(homeserverProvider) != null; return GoRouter( initialLocation: '/rooms', diff --git a/lib/features/auth/login_notifier.dart b/lib/features/auth/login_notifier.dart index b79b4a8..9ad0ede 100644 --- a/lib/features/auth/login_notifier.dart +++ b/lib/features/auth/login_notifier.dart @@ -5,15 +5,18 @@ import 'package:shared_preferences/shared_preferences.dart'; const _prefHomeserver = 'homeserver_url'; -// Gespeicherter Homeserver aus SharedPreferences -final homeserverProvider = FutureProvider((ref) async { - final prefs = await SharedPreferences.getInstance(); - return prefs.getString(_prefHomeserver); -}); +final homeserverProvider = StateProvider((ref) => null); -Future saveHomeserver(String url) async { +Future initHomeserver(WidgetRef ref) async { + final prefs = await SharedPreferences.getInstance(); + final saved = prefs.getString(_prefHomeserver); + ref.read(homeserverProvider.notifier).state = saved; +} + +Future saveHomeserver(WidgetRef ref, String url) async { final prefs = await SharedPreferences.getInstance(); await prefs.setString(_prefHomeserver, url); + ref.read(homeserverProvider.notifier).state = url; } enum LoginStatus { idle, loading, error } diff --git a/lib/features/auth/login_page.dart b/lib/features/auth/login_page.dart index 0554e01..c65abf1 100644 --- a/lib/features/auth/login_page.dart +++ b/lib/features/auth/login_page.dart @@ -26,7 +26,7 @@ class _LoginPageState extends ConsumerState { Future _submit() async { if (!_formKey.currentState!.validate()) return; - final homeserver = ref.read(homeserverProvider).valueOrNull ?? 'matrix.org'; + final homeserver = ref.read(homeserverProvider) ?? 'matrix.org'; await ref.read(loginNotifierProvider.notifier).login( username: _userCtrl.text.trim(), @@ -45,7 +45,7 @@ class _LoginPageState extends ConsumerState { final theme = Theme.of(context); final loginState = ref.watch(loginNotifierProvider); final loading = loginState.status == LoginStatus.loading; - final homeserver = ref.watch(homeserverProvider).valueOrNull ?? 'matrix.org'; + final homeserver = ref.watch(homeserverProvider) ?? 'matrix.org'; return Scaffold( body: Center( diff --git a/lib/features/auth/server_page.dart b/lib/features/auth/server_page.dart index 684647a..5562ac8 100644 --- a/lib/features/auth/server_page.dart +++ b/lib/features/auth/server_page.dart @@ -12,18 +12,18 @@ class ServerPage extends ConsumerStatefulWidget { class _ServerPageState extends ConsumerState { final _formKey = GlobalKey(); - final _ctrl = TextEditingController(text: 'matrix.org'); + final _ctrl = TextEditingController(); bool _loading = false; String? _error; @override void initState() { super.initState(); - ref.read(homeserverProvider.future).then((saved) { - if (saved != null && mounted) { - _ctrl.text = saved.replaceAll(RegExp(r'^https?://'), ''); - } - }); + // Gespeicherten Server vorausfüllen (falls vorhanden) + final saved = ref.read(homeserverProvider); + if (saved != null) { + _ctrl.text = saved.replaceAll(RegExp(r'^https?://'), ''); + } } @override @@ -38,7 +38,7 @@ class _ServerPageState extends ConsumerState { final input = _ctrl.text.trim().replaceAll(RegExp(r'^https?://'), ''); try { - await saveHomeserver(input); + await saveHomeserver(ref, input); if (mounted) context.go('/login'); } catch (e) { setState(() => _error = e.toString()); @@ -63,11 +63,8 @@ class _ServerPageState extends ConsumerState { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Icon( - Icons.change_history_rounded, - size: 72, - color: theme.colorScheme.primary, - ), + Icon(Icons.change_history_rounded, + size: 72, color: theme.colorScheme.primary), const SizedBox(height: 8), Text( 'Pyramid', @@ -76,45 +73,42 @@ class _ServerPageState extends ConsumerState { ?.copyWith(fontWeight: FontWeight.bold), ), const SizedBox(height: 32), - Text( - 'Server', - style: theme.textTheme.titleMedium, - ), + Text('Server', style: theme.textTheme.titleMedium), const SizedBox(height: 8), TextFormField( controller: _ctrl, - decoration: const InputDecoration( - hintText: 'matrix.org', - prefixText: 'https://', - prefixIcon: Icon(Icons.dns_outlined), - border: OutlineInputBorder(), + autofocus: true, + decoration: InputDecoration( + hintText: 'dein-server.de', + prefixIcon: const Icon(Icons.dns_outlined), + border: const OutlineInputBorder(), + // https:// als nicht-editierbares Prefix + prefix: Text( + 'https://', + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), + ), ), keyboardType: TextInputType.url, - validator: (v) { - if (v == null || v.trim().isEmpty) { - return 'Server-Adresse eingeben'; - } - return null; - }, + validator: (v) => (v == null || v.trim().isEmpty) + ? 'Server-Adresse eingeben' + : null, onFieldSubmitted: (_) => _continue(), ), if (_error != null) ...[ const SizedBox(height: 12), - Text( - _error!, - style: TextStyle(color: theme.colorScheme.error), - textAlign: TextAlign.center, - ), + Text(_error!, + style: TextStyle(color: theme.colorScheme.error), + textAlign: TextAlign.center), ], const SizedBox(height: 24), FilledButton( onPressed: _loading ? null : _continue, child: _loading ? const SizedBox( - height: 20, - width: 20, - child: CircularProgressIndicator(strokeWidth: 2), - ) + height: 20, width: 20, + child: CircularProgressIndicator(strokeWidth: 2)) : const Text('Weiter'), ), ], diff --git a/lib/main.dart b/lib/main.dart index bb6b432..e2067a2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:pyramid/core/app.dart'; import 'package:pyramid/core/matrix_client.dart'; +import 'package:pyramid/features/auth/login_notifier.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -17,16 +18,16 @@ class PyramidBootstrap extends ConsumerWidget { return clientAsync.when( loading: () => const MaterialApp( - home: Scaffold( - body: Center(child: CircularProgressIndicator()), - ), + home: Scaffold(body: Center(child: CircularProgressIndicator())), ), error: (e, _) => MaterialApp( - home: Scaffold( - body: Center(child: Text('Fehler: $e')), - ), + home: Scaffold(body: Center(child: Text('Fehler: $e'))), ), - data: (_) => const PyramidApp(), + data: (_) { + // Homeserver einmalig aus SharedPreferences laden + initHomeserver(ref); + return const PyramidApp(); + }, ); } }