2022-12-29 20:05:14 +00:00
|
|
|
import 'package:feet/api/api.dart';
|
2022-12-29 18:16:46 +00:00
|
|
|
import 'package:flutter/material.dart';
|
2022-12-29 20:43:02 +00:00
|
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
2022-12-29 18:16:46 +00:00
|
|
|
|
|
|
|
class LoginPage extends StatefulWidget {
|
2022-12-29 20:05:14 +00:00
|
|
|
final FeverAPI api;
|
|
|
|
const LoginPage({ super.key, required this.api });
|
2022-12-29 18:16:46 +00:00
|
|
|
|
|
|
|
@override
|
|
|
|
State<LoginPage> createState() => _LoginPageState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class _LoginPageState extends State<LoginPage> {
|
2022-12-29 20:05:14 +00:00
|
|
|
bool? _validAPI;
|
|
|
|
|
|
|
|
final _urlController = TextEditingController();
|
|
|
|
final _usernameController = TextEditingController();
|
|
|
|
final _passwordController = TextEditingController();
|
|
|
|
|
|
|
|
final _urlFocus = FocusNode();
|
|
|
|
|
|
|
|
Future<bool> checkUrl() async {
|
|
|
|
if (_urlController.text.isNotEmpty) {
|
|
|
|
var value = await FeverAPI.isValidAPI(_urlController.text);
|
|
|
|
setState(() {
|
|
|
|
_validAPI = value;
|
|
|
|
});
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void initState() {
|
|
|
|
super.initState();
|
|
|
|
_urlFocus.addListener(() {
|
|
|
|
if (!_urlFocus.hasFocus) {
|
|
|
|
checkUrl();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void dispose() {
|
|
|
|
_urlController.dispose();
|
|
|
|
_usernameController.dispose();
|
|
|
|
_passwordController.dispose();
|
|
|
|
_urlFocus.dispose();
|
|
|
|
super.dispose();
|
|
|
|
}
|
|
|
|
|
2022-12-29 18:16:46 +00:00
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return Scaffold(
|
|
|
|
appBar: AppBar(
|
|
|
|
title: const Text('Log in'),
|
|
|
|
),
|
|
|
|
body: Column(
|
|
|
|
children: [
|
|
|
|
Container(
|
|
|
|
padding: const EdgeInsets.all(8.0),
|
|
|
|
child: Column(
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
2022-12-29 20:05:14 +00:00
|
|
|
children: [
|
|
|
|
const Text("Fever compatible API URL"),
|
2022-12-29 18:16:46 +00:00
|
|
|
TextField(
|
2022-12-29 20:05:14 +00:00
|
|
|
controller: _urlController,
|
|
|
|
focusNode: _urlFocus,
|
2022-12-29 18:16:46 +00:00
|
|
|
decoration: InputDecoration(
|
2022-12-29 20:05:14 +00:00
|
|
|
border: const OutlineInputBorder(),
|
|
|
|
contentPadding: const EdgeInsets.all(8.0),
|
2022-12-29 18:16:46 +00:00
|
|
|
hintText: 'https://among-us.morbius.sus/api/fever.php',
|
2022-12-29 20:05:14 +00:00
|
|
|
errorText: _validAPI == false ? 'Invalid or unsupported API' : null,
|
2022-12-29 18:16:46 +00:00
|
|
|
)
|
2022-12-29 20:05:14 +00:00
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
Container(
|
|
|
|
padding: const EdgeInsets.all(8.0),
|
|
|
|
child: Column(
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
children: [
|
|
|
|
const Text("Authentication"),
|
|
|
|
Row(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
|
|
children: [
|
|
|
|
Flexible(child: TextField(
|
|
|
|
controller: _usernameController,
|
|
|
|
decoration: const InputDecoration(
|
|
|
|
border: OutlineInputBorder(),
|
|
|
|
contentPadding: EdgeInsets.all(8.0),
|
|
|
|
hintText: 'Username',
|
|
|
|
),
|
|
|
|
)),
|
|
|
|
const SizedBox(width: 8),
|
|
|
|
Flexible(child: TextField(
|
|
|
|
controller: _passwordController,
|
|
|
|
decoration: const InputDecoration(
|
|
|
|
border: OutlineInputBorder(),
|
|
|
|
contentPadding: EdgeInsets.all(8.0),
|
|
|
|
hintText: 'Password',
|
|
|
|
),
|
|
|
|
obscureText: true,
|
|
|
|
)),
|
|
|
|
],
|
|
|
|
),
|
2022-12-29 18:16:46 +00:00
|
|
|
],
|
|
|
|
),
|
2022-12-29 20:05:14 +00:00
|
|
|
),
|
|
|
|
ElevatedButton(
|
|
|
|
onPressed: () async {
|
|
|
|
if (_urlController.text.isEmpty) return;
|
|
|
|
_validAPI ??= await checkUrl();
|
|
|
|
if (_validAPI != true || _usernameController.text.isEmpty || _passwordController.text.isEmpty) return;
|
|
|
|
|
|
|
|
var apiKey = FeverAPI.generateApiKey(_usernameController.text, _passwordController.text);
|
|
|
|
var isAuthenticated = await FeverAPI.isAuthenticated(_urlController.text, apiKey);
|
|
|
|
|
|
|
|
if (!isAuthenticated) {
|
|
|
|
// ignore: use_build_context_synchronously
|
|
|
|
showDialog(
|
|
|
|
context: context,
|
|
|
|
builder: (BuildContext context) {
|
|
|
|
return AlertDialog(
|
|
|
|
title: const Text('Authentication failed'),
|
|
|
|
content: const Text('The API URL seems to be valid, but the provided credentials appear to be incorrect.'),
|
|
|
|
actions: [
|
|
|
|
TextButton(onPressed: () => Navigator.of(context).pop(), child: const Text('Got it!')),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-12-29 20:43:02 +00:00
|
|
|
final prefs = await SharedPreferences.getInstance();
|
|
|
|
await prefs.setString('apiUrl', _urlController.text);
|
|
|
|
await prefs.setString('apiKey', apiKey);
|
|
|
|
|
2022-12-29 20:05:14 +00:00
|
|
|
widget.api.apiUrl = _urlController.text;
|
|
|
|
widget.api.apiKey = apiKey;
|
|
|
|
// ignore: use_build_context_synchronously
|
|
|
|
Navigator.of(context).pop();
|
|
|
|
},
|
|
|
|
child: const Text('Continue'),
|
|
|
|
),
|
2022-12-29 18:16:46 +00:00
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|