diff options
Diffstat (limited to 'lib/screens')
-rw-r--r-- | lib/screens/home.dart | 26 | ||||
-rw-r--r-- | lib/screens/login.dart | 200 | ||||
-rw-r--r-- | lib/screens/signup.dart | 140 |
3 files changed, 366 insertions, 0 deletions
diff --git a/lib/screens/home.dart b/lib/screens/home.dart new file mode 100644 index 0000000..474fc48 --- /dev/null +++ b/lib/screens/home.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import "login.dart"; + +class HomeScreen extends StatelessWidget { + const HomeScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Home Page") + ), + body: Center( + child: ElevatedButton( + child: const Text("Log In"), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const LoginScreen()) + ); + }, + ), + ), + ); + } +} diff --git a/lib/screens/login.dart b/lib/screens/login.dart new file mode 100644 index 0000000..1a0db55 --- /dev/null +++ b/lib/screens/login.dart @@ -0,0 +1,200 @@ +import "package:flutter/material.dart"; +import "package:flutter_secure_storage/flutter_secure_storage.dart"; + +import "package:openbills/models/login.dart"; +import "package:openbills/widgets/input_box.dart"; +import "package:openbills/widgets/snackbar.dart"; +import "package:openbills/screens/signup.dart"; + +class LoginScreen extends StatelessWidget { + const LoginScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + centerTitle: true, + title: const Image( + height: 50, + image: AssetImage("assets/images/logo.png"), + ), + ), + body: const Center( + child: SizedBox( + width: 500, + child: Body(), + ) + ), + ); + } +} + +class Body extends StatefulWidget { + const Body({super.key}); + + @override + State<Body> createState() => _BodyState(); +} + +class _BodyState extends State<Body> { + final accountNameController = TextEditingController(); + final passwordController = TextEditingController(); + LoginMethod? _method = LoginMethod.username; + + final _storage = const FlutterSecureStorage(); + + @override + void dispose() { + accountNameController.dispose(); + passwordController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + Size size = MediaQuery.sizeOf(context); + MainAxisAlignment alignment = MainAxisAlignment.center; + + if (size.width < 700) { + alignment = MainAxisAlignment.spaceBetween; + } + + if (size.height < 700) { + alignment = MainAxisAlignment.center; + } + + return Column ( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: alignment, + children: <Widget> [ + const Padding( + padding: EdgeInsets.symmetric(horizontal: 8, vertical: 16), + child: Text( + "OpenBills Log In", + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 30, + ), + ), + ), + + Column( + children: <Widget>[ + FormInputBox( + controller: accountNameController, + hintText: _method == LoginMethod.email ? "E-Mail" : "Username", + ), + + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16), + child: Column( + children: <Widget>[ + const Text( + "Log in with:", + textAlign: TextAlign.left, + style: TextStyle( + fontSize: 18, + ), + ), + + Row( + children: <Widget>[ + Flexible( + child: RadioListTile<LoginMethod>( + title: const Text("username"), + value: LoginMethod.username, + groupValue: _method, + onChanged: (LoginMethod? value) { + setState(() { + _method = value; + }); + }, + ), + ), + + Flexible( + child: RadioListTile<LoginMethod>( + title: const Text("email"), + value: LoginMethod.email, + groupValue: _method, + onChanged: (LoginMethod? value) { + setState(() { + _method = value; + }); + }, + ), + ), + ], + ), + ], + ) + ), + + FormInputBox( + controller: passwordController, + hintText: "Password", + obscureText: true, + ), + ], + ), + + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: <Widget> [ + TextButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const SignupScreen()) + ); + }, + child: const Text("Don't have an account? Sign up.") + ), + + ElevatedButton( + onPressed: () async { + String name = accountNameController.text; + String? method = _method?.value; + String password = passwordController.text; + + try { + LoginRes res = await userSignIn(name, method, password); + String? username = res.user.username; + + await _storage.write( + key: "auth_token", + value: res.authToken, + aOptions: const AndroidOptions( + encryptedSharedPreferences: true, + ), + ); + + await _storage.write( + key: "refresh_token", + value: res.refreshToken, + aOptions: const AndroidOptions( + encryptedSharedPreferences: true, + ), + ); + + if (context.mounted) { + MySnackBar.show(context, "Hello, $username! Please restart the app to see the homepage."); + } + } on String catch(e) { + if (context.mounted) { + MySnackBar.show(context, "Error: $e"); + } + } + }, + child: const Text("Log In") + ), + ], + ), + ), + ], + ); + } +}
\ No newline at end of file diff --git a/lib/screens/signup.dart b/lib/screens/signup.dart new file mode 100644 index 0000000..b155d8e --- /dev/null +++ b/lib/screens/signup.dart @@ -0,0 +1,140 @@ +import "package:flutter/material.dart"; + +import "package:openbills/models/user.dart"; +import "package:openbills/widgets/input_box.dart"; +import "package:openbills/widgets/snackbar.dart"; + +class SignupScreen extends StatelessWidget { + const SignupScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + centerTitle: true, + title: const Image( + height: 50, + image: AssetImage("assets/images/logo.png"), + ), + ), + body: const Center( + child: SizedBox( + width: 500, + child: Body(), + ) + ), + ); + } +} + +class Body extends StatefulWidget { + const Body({super.key}); + + @override + State<Body> createState() => _BodyState(); +} + +class _BodyState extends State<Body> { + final usernameController = TextEditingController(); + final emailController = TextEditingController(); + final passwordController = TextEditingController(); + + @override + void dispose() { + usernameController.dispose(); + emailController.dispose(); + passwordController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + Size size = MediaQuery.sizeOf(context); + MainAxisAlignment alignment = MainAxisAlignment.center; + + if (size.width < 700) { + alignment = MainAxisAlignment.spaceBetween; + } + + if (size.height < 700) { + alignment = MainAxisAlignment.center; + } + + return Column ( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: alignment, + children: <Widget> [ + const Padding( + padding: EdgeInsets.symmetric(horizontal: 8, vertical: 16), + child: Text( + "OpenBills Sign Up", + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 30, + ), + ), + ), + + Column( + children: <Widget>[ + FormInputBox( + controller: usernameController, + hintText: "Username", + ), + + FormInputBox( + controller: emailController, + hintText: "E-mail", + ), + + FormInputBox( + controller: passwordController, + hintText: "Password", + obscureText: true, + ), + ], + ), + + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: <Widget> [ + TextButton( + onPressed: () { + Navigator.pop(context); + }, + child: const Text("Already have an account? Sign in.") + ), + + ElevatedButton( + onPressed: () async { + User u = User( + id: 0, + username: usernameController.text, + email: emailController.text, + ); + + try { + await userSignUp(u, passwordController.text); + + if (context.mounted) { + MySnackBar.show(context, "Successfully created an account!"); + Navigator.pop(context); + } + } on String catch (e) { + if (context.mounted) { + MySnackBar.show(context, "Error: $e"); + } + } + }, + child: const Text("Sign Up") + ), + ], + ), + ), + ], + ); + } +}
\ No newline at end of file |