[client] Extract password login fragment

This commit is contained in:
Abhishek Shroff
2025-05-24 21:24:35 +05:30
parent 935a9423f6
commit 7813830ea5
4 changed files with 99 additions and 64 deletions

View File

@@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:js_interop';
import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:offtheline/offtheline.dart';
import 'package:phylum/libphylum/phylum_account.dart';
@@ -79,7 +80,7 @@ class _AccountSelectorState extends State<AccountSelector> {
context.select<AccountManagerState<PhylumAccount>, PhylumAccount?>((state) => state.selectedAccount);
if (account == null) {
return const LoginPage();
return kDebugMode ? const LoginPage() : LoginPage(fixedInstanceUrl: Uri());
}
return AppLayout.create(account);
}

View File

@@ -0,0 +1,33 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class InstanceUrlFragment extends StatefulWidget {
final Function(Uri) onSubmitted;
const InstanceUrlFragment({super.key, required this.onSubmitted});
@override
State<InstanceUrlFragment> createState() => _InstanceUrlFragmentState();
}
class _InstanceUrlFragmentState extends State<InstanceUrlFragment> {
Uri? _url;
@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
decoration: InputDecoration(
label: const Text('Instance URL'),
hintText: 'http://localhost:2448/',
),
keyboardType: TextInputType.url,
onChanged: (value) => setState(() => _url = kIsWeb && value == '' ? Uri() : Uri.tryParse(value)),
onSubmitted: _url == null ? null : (value) => widget.onSubmitted(_url!),
),
ElevatedButton(onPressed: _url == null ? null : () => widget.onSubmitted(_url!), child: Text('Next'))
],
);
}
}

View File

@@ -1,25 +1,27 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:phylum/ui/common/logo_row.dart';
import 'package:phylum/ui/login/instance_url_fragment.dart';
import 'package:phylum/ui/login/password_login_fragment.dart';
import 'login_request.dart';
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
final Uri? fixedInstanceUrl;
const LoginPage({super.key, this.fixedInstanceUrl});
@override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
String _email = '';
String _password = '';
Uri? serverUrl = kIsWeb ? Uri() : null;
String? urlError;
String? emailError;
Uri? _instanceUrl;
bool get serverUrlValid =>
(kIsWeb && serverUrl == Uri()) || (serverUrl?.hasScheme == true && serverUrl?.hasAuthority == true);
@override
void initState() {
super.initState();
_instanceUrl = widget.fixedInstanceUrl;
}
@override
Widget build(BuildContext context) {
@@ -38,60 +40,7 @@ class _LoginPageState extends State<LoginPage> {
padding: EdgeInsets.only(bottom: 12.0),
child: LogoRow(),
),
if (kDebugMode || !kIsWeb)
TextField(
decoration: InputDecoration(
label: const Text('Server URL'),
hintText: 'http://localhost:2448/',
errorText: urlError,
),
keyboardType: TextInputType.url,
onChanged: (value) {
setState(() {
serverUrl = kIsWeb && value == '' ? Uri() : Uri.tryParse(value);
urlError = serverUrl == null ? 'Invalid URL' : null;
});
},
),
TextField(
decoration: const InputDecoration(
label: Text('Email'),
),
keyboardType: TextInputType.emailAddress,
onChanged: (value) {
setState(() {
_email = value.trim();
});
},
),
TextField(
decoration: const InputDecoration(
label: Text('Password'),
),
obscureText: true,
keyboardType: TextInputType.visiblePassword,
onChanged: (value) {
setState(() {
_password = value.trim();
});
},
onSubmitted: serverUrlValid
? (value) {
performLogin(context, serverUrl ?? Uri(), _email, _password);
}
: null,
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: ElevatedButton(
onPressed: serverUrlValid && _email.isNotEmpty
? () async {
performLogin(context, serverUrl ?? Uri(), _email, _password);
}
: null,
child: const Text('Login'),
),
),
_buildBody(context),
],
),
),
@@ -100,4 +49,12 @@ class _LoginPageState extends State<LoginPage> {
),
);
}
Widget _buildBody(BuildContext context) {
final instanceUrl = _instanceUrl;
if (instanceUrl == null) {
return InstanceUrlFragment(onSubmitted: (url) => setState(() => _instanceUrl = url));
}
return PasswordLoginFragment(onSubmitted: (email, password) => performLogin(context, instanceUrl, email, password));
}
}

View File

@@ -0,0 +1,44 @@
import 'package:flutter/material.dart';
class PasswordLoginFragment extends StatefulWidget {
final Function(String, String) onSubmitted;
const PasswordLoginFragment({super.key, required this.onSubmitted});
@override
State<PasswordLoginFragment> createState() => _PasswordLoginFragmentState();
}
class _PasswordLoginFragmentState extends State<PasswordLoginFragment> {
String _email = '';
String _password = '';
@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
decoration: const InputDecoration(
label: Text('Email'),
),
keyboardType: TextInputType.emailAddress,
onChanged: (value) => setState(() => _email = value.trim()),
),
TextField(
decoration: const InputDecoration(
label: Text('Password'),
),
obscureText: true,
keyboardType: TextInputType.visiblePassword,
onChanged: (value) => setState(() => _password = value),
onSubmitted: _email.isNotEmpty ? (value) => widget.onSubmitted(_email, _password) : null,
),
TextButton(onPressed: () {}, child: Text('Forgot Password')),
ElevatedButton(
onPressed: _email.isEmpty || _password.isEmpty ? null : () => widget.onSubmitted(_email, _password),
child: Text('Login'),
)
],
);
}
}