import 'dart:async'; import 'package:animated_background/animated_background.dart'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:tuuli_api/tuuli_api.dart'; import 'package:tuuli_app/api_controller.dart'; class LoginPageController extends GetxController { final _login = "".obs; String get login => _login.value; set login(String value) => _login.value = value; final _password = "".obs; String get password => _password.value; set password(String value) => _password.value = value; final _submitted = false.obs; bool get submitted => _submitted.value; set submitted(bool value) => _submitted.value = value; bool get isFormValid => login.isNotEmpty && password.isNotEmpty; Future submitForm() async { submitted = true; if (isFormValid) { final amb = AuthModelBuilder() ..username = login ..password = password; try { final resp = await ApiController.to.apiClient .getAccessTokenApiGetAccessTokenPost(authModel: amb.build()); final respData = resp.data; if (resp.statusCode == 200 && respData != null) { final accessToken = respData.accessToken; Get.find().token = accessToken; WidgetsBinding.instance.addPostFrameCallback((_) { Get.offAllNamed("/home"); }); } else { Get.snackbar( "Login failed", resp.statusMessage ?? "Unknown error", ); } } on DioError catch (e) { final errorData = e.response?.data; if (errorData != null) { final error = errorData["error"]; if (error != null) { Get.snackbar( "Login failed", "$error", ); } } else { Get.snackbar( "Login failed", "$e", ); } } catch (e) { Get.snackbar( "Login failed", "$e", ); } } submitted = false; } } class LoginPage extends GetView { const LoginPage({super.key}); @override Widget build(BuildContext context) { final screenSize = Get.mediaQuery.size; final formWidth = screenSize.width <= 600 ? screenSize.width : 300.0; return Scaffold( body: Stack( children: [ const SizedBox.square( dimension: 0, ), Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ LimitedBox( maxWidth: formWidth, child: Obx( () => Container( color: Colors.black.withAlpha(100), padding: const EdgeInsets.all(16), child: Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ TextFormField( enabled: !controller.submitted, decoration: const InputDecoration( labelText: 'Login', hintText: 'Enter your login', ), onChanged: (value) => controller.login = value, validator: (value) { if (value == null || value.isEmpty) { return 'Please enter your Login'; } return null; }, ), TextFormField( obscureText: true, enabled: !controller.submitted, decoration: const InputDecoration( labelText: 'Password', hintText: 'Enter your password', ), onChanged: (value) => controller.password = value, validator: (value) { if (value == null || value.isEmpty) { return 'Please enter your password'; } return null; }, ), const SizedBox(height: 16), ElevatedButton( onPressed: controller.submitted ? null : () => controller.submitForm(), child: const Text('Login'), ), ], ), ), ), ), ], ), ], ), ); } } /* class LoginPage extends StatefulWidget { const LoginPage({super.key}); @override State createState() => _LoginPageState(); } class _LoginPageState extends State with TickerProviderStateMixin { final _formKey = GlobalKey(); final apiClient = Get.find(); var submitted = false; final loginPageController = TextEditingController(); final passwordController = TextEditingController(); @override Widget build(BuildContext context) { final screenSize = MediaQuery.of(context).size; final formWidth = screenSize.width <= 600 ? screenSize.width : 300.0; return Scaffold( body: Stack( children: [ AnimatedBackground( behaviour: RandomParticleBehaviour(), vsync: this, child: const SizedBox.square( dimension: 0, ), ), Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ LimitedBox( maxWidth: formWidth, child: Container( color: Colors.black.withAlpha(100), padding: const EdgeInsets.all(16), child: Form( key: _formKey, child: Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ TextFormField( controller: loginPageController, enabled: !submitted, decoration: const InputDecoration( labelText: 'Login', hintText: 'Enter your login', ), validator: (value) { if (value == null || value.isEmpty) { return 'Please enter your Login'; } return null; }, ), TextFormField( controller: passwordController, obscureText: true, enabled: !submitted, decoration: const InputDecoration( labelText: 'Password', hintText: 'Enter your password', ), validator: (value) { if (value == null || value.isEmpty) { return 'Please enter your password'; } return null; }, ), const SizedBox(height: 16), ElevatedButton( onPressed: submitted ? null : _submit, child: const Text('Login'), ), ], ), ), ), ), ], ), ], ), ); } Future _submit() async { if (!_formKey.currentState!.validate()) { return; } setState(() { submitted = true; }); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Trying to login...'), ), ); final response = await apiClient.login( loginPageController.text.trim(), passwordController.text.trim(), ); response.unfold((data) { ScaffoldMessenger.of(context).hideCurrentSnackBar(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Login successful'), ), ); apiClient.setAccessToken(data.accessToken); GetStorage() .write("accessToken", data.accessToken) .then((value) => GetStorage().save()) .then((value) { Timer(1.seconds, () { ScaffoldMessenger.of(context).hideCurrentSnackBar(); WidgetsBinding.instance.addPostFrameCallback((_) { Get.offAllNamed("/home"); }); }); }); }, (error) { ScaffoldMessenger.of(context).hideCurrentSnackBar(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(error.toString()), ), ); setState(() { submitted = false; }); }); } } */