import 'package:feet/api/api.dart'; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; class LoginPage extends StatefulWidget { final FeverAPI api; const LoginPage({ super.key, required this.api }); @override State createState() => _LoginPageState(); } class _LoginPageState extends State { bool? _validAPI; final _urlController = TextEditingController(); final _usernameController = TextEditingController(); final _passwordController = TextEditingController(); final _urlFocus = FocusNode(); Future 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(); } @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, children: [ const Text("Fever compatible API URL"), TextField( controller: _urlController, focusNode: _urlFocus, decoration: InputDecoration( border: const OutlineInputBorder(), contentPadding: const EdgeInsets.all(8.0), hintText: 'https://among-us.morbius.sus/api/fever.php', errorText: _validAPI == false ? 'Invalid or unsupported API' : null, ) ), ], ), ), 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, )), ], ), ], ), ), 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; } final prefs = await SharedPreferences.getInstance(); await prefs.setString('apiUrl', _urlController.text); await prefs.setString('apiKey', apiKey); widget.api.apiUrl = _urlController.text; widget.api.apiKey = apiKey; // ignore: use_build_context_synchronously Navigator.of(context).pop(); }, child: const Text('Continue'), ), ], ), ); } }