import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import '/components/flash_message.dart'; import '/models/my_profile.dart'; import '/utils/storage/session_cookie.dart'; class LoginResponse { final String userId; final String username; final String publicKey; final String privateKey; final String symmetricKey; final String? imageLink; const LoginResponse({ required this.publicKey, required this.privateKey, required this.symmetricKey, required this.userId, required this.username, this.imageLink, }); factory LoginResponse.fromJson(Map json) { return LoginResponse( userId: json['user_id'], username: json['username'], publicKey: json['asymmetric_public_key'], privateKey: json['asymmetric_private_key'], symmetricKey: json['symmetric_key'], imageLink: json['image_link'], ); } } class Login extends StatelessWidget { const Login({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: null, automaticallyImplyLeading: true, leading: IconButton(icon: const Icon(Icons.arrow_back), onPressed:() => { Navigator.pop(context) } ), backgroundColor: Colors.transparent, shadowColor: Colors.transparent, ), body: const SafeArea( child: LoginWidget(), ), ); } } class LoginWidget extends StatefulWidget { const LoginWidget({Key? key}) : super(key: key); @override State createState() => _LoginWidgetState(); } class _LoginWidgetState extends State { final _formKey = GlobalKey(); final TextEditingController _usernameController = TextEditingController(); final TextEditingController _passwordController = TextEditingController(); @override Widget build(BuildContext context) { const TextStyle inputTextStyle = TextStyle( fontSize: 18, ); final OutlineInputBorder inputBorderStyle = OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: const BorderSide( color: Colors.transparent, ) ); final ButtonStyle buttonStyle = ElevatedButton.styleFrom( backgroundColor: Theme.of(context).colorScheme.surface, foregroundColor: Theme.of(context).colorScheme.onSurface, minimumSize: const Size.fromHeight(50), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10), textStyle: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.error, ), ); return Center( child: Form( key: _formKey, child: Center( child: Padding( padding: const EdgeInsets.only( left: 20, right: 20, top: 0, bottom: 80, ), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( 'Login', style: TextStyle( fontSize: 35, color: Theme.of(context).colorScheme.onBackground, ), ), const SizedBox(height: 30), TextFormField( controller: _usernameController, decoration: InputDecoration( hintText: 'Username', enabledBorder: inputBorderStyle, focusedBorder: inputBorderStyle, ), style: inputTextStyle, // The validator receives the text that the user has entered. validator: (value) { if (value == null || value.isEmpty) { return 'Enter a username'; } return null; }, ), const SizedBox(height: 10), TextFormField( controller: _passwordController, obscureText: true, enableSuggestions: false, autocorrect: false, decoration: InputDecoration( hintText: 'Password', enabledBorder: inputBorderStyle, focusedBorder: inputBorderStyle, ), style: inputTextStyle, // The validator receives the text that the user has entered. validator: (value) { if (value == null || value.isEmpty) { return 'Enter a password'; } return null; }, ), const SizedBox(height: 15), ElevatedButton( style: buttonStyle, onPressed: () { if (_formKey.currentState!.validate()) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Processing Data')), ); login() .then((val) { Navigator. pushNamedAndRemoveUntil( context, '/home', ModalRoute.withName('/home'), ); }).catchError((error) { showMessage( 'Could not login to Envelope, please try again later.', context, ); }); } }, child: const Text('Submit'), ), ], ) ) ) ) ); } Future login() async { final resp = await http.post( await MyProfile.getServerUrl('api/v1/login'), headers: { 'Content-Type': 'application/json; charset=UTF-8', }, body: jsonEncode({ 'username': _usernameController.text, 'password': _passwordController.text, }), ); if (resp.statusCode != 200) { throw Exception(resp.body); } String? rawCookie = resp.headers['set-cookie']; if (rawCookie != null) { int index = rawCookie.indexOf(';'); setSessionCookie((index == -1) ? rawCookie : rawCookie.substring(0, index)); } return await MyProfile.login( json.decode(resp.body), _passwordController.text, ); } }