Files
sheetless/lib/login_page.dart

130 lines
3.8 KiB
Dart

import 'package:flutter/material.dart';
import 'package:jwt_decoder/jwt_decoder.dart';
import 'package:sheetless/api.dart';
import 'package:sheetless/home_page.dart';
import 'package:sheetless/storage_helper.dart';
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
@override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final TextEditingController _urlController = TextEditingController(
text: "https://sheetable.julian-mutter.de",
);
final TextEditingController _emailController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
final StorageHelper _storageHelper = StorageHelper();
String? _error;
@override
void initState() {
super.initState();
_checkJwtValidity();
}
Future<void> _checkJwtValidity() async {
final jwt = await _storageHelper.readSecure(SecureStorageKey.jwt);
if (jwt != null) {
final isValid = await _validateJwt(jwt);
if (isValid) {
_navigateToMainPage();
return;
} else {
final url = await _storageHelper.readSecure(SecureStorageKey.url);
final email = await _storageHelper.readSecure(SecureStorageKey.email);
final password = await _storageHelper.readSecure(
SecureStorageKey.password,
);
if (url != null && email != null && password != null) {
_login(url, email, password);
}
}
}
}
Future<bool> _validateJwt(String jwt) async {
try {
bool expired = JwtDecoder.isExpired(jwt);
return !expired;
} on FormatException {
return false;
}
}
Future<void> _login(String serverUrl, String email, String password) async {
setState(() {
_error = null;
});
serverUrl = "$serverUrl/api";
final apiClient = ApiClient(baseUrl: serverUrl);
final loginSuccessful = await apiClient.login(email, password);
if (loginSuccessful) {
await _storageHelper.writeSecure(SecureStorageKey.url, serverUrl);
await _storageHelper.writeSecure(SecureStorageKey.jwt, apiClient.token!);
await _storageHelper.writeSecure(SecureStorageKey.email, email);
await _storageHelper.writeSecure(SecureStorageKey.password, password);
_navigateToMainPage();
} else {
// TODO: give more varied error messages
setState(() {
_error = "Login failed.";
});
}
}
void _navigateToMainPage() {
Navigator.of(
context,
).pushReplacement(MaterialPageRoute(builder: (_) => MyHomePage()));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Login')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: _urlController,
decoration: InputDecoration(labelText: 'Url'),
),
TextField(
controller: _emailController,
decoration: InputDecoration(labelText: 'Email'),
),
TextField(
controller: _passwordController,
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
),
if (_error != null)
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(_error!, style: TextStyle(color: Colors.red)),
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () {
_login(
_urlController.text,
_emailController.text,
_passwordController.text,
);
},
child: Text('Login'),
),
],
),
),
);
}
}