Files
sfm_app_final/lib/feature/auth/login/screen/login_screen.dart
2025-04-10 09:26:52 +07:00

235 lines
10 KiB
Dart

// ignore_for_file: use_build_context_synchronously
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import '../../../../product/constant/app/api_path_constant.dart';
import '../../../../product/constant/enums/app_route_enums.dart';
import '../model/login_model.dart';
import '../../../../product/cache/local_manager.dart';
import '../../../../product/constant/enums/local_keys_enums.dart';
import '../../../../product/services/api_services.dart';
import '../../../../product/shared/shared_snack_bar.dart';
import '../../../../product/constant/icon/icon_constants.dart';
import '../../../../product/extension/context_extension.dart';
import '../../../../product/constant/image/image_constants.dart';
import '../../../../product/services/language_services.dart';
import '../../../../bloc/login_bloc.dart';
import '../../../../product/base/bloc/base_bloc.dart';
import '../../../../product/shared/shared_background.dart';
class LoginScreen extends StatefulWidget {
const LoginScreen({super.key});
@override
State<LoginScreen> createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
late LoginBloc loginBloc;
Map<String, dynamic> loginRequest = {"username": "", "password": ""};
final _formKey = GlobalKey<FormState>();
bool isShowPassword = true;
APIServices apiServices = APIServices();
@override
void initState() {
super.initState();
loginBloc = BlocProvider.of(context);
checkLogin(context);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SharedBackground(
child: SizedBox(
height: MediaQuery.sizeOf(context).height,
width: MediaQuery.sizeOf(context).width,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
children: [
const SizedBox(height: 100.0,),
Image.asset(
ImageConstants.instance.getImage("lo-go"),
height: context.dynamicHeight(0.1),
),
],
),
StreamBuilder<Map<String, dynamic>>(
stream: loginBloc.streamLoginRequest,
builder: (context, loginResquestSnapshot) {
return Padding(
padding: context.paddingMediumHorizontal,
child: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
textInputAction: TextInputAction.next,
validator: (value) {
if (value == "null" || value!.isEmpty) {
return appLocalization(context)
.login_account_not_empty;
}
return null;
},
onSaved: (username) {
loginRequest["username"] = username!;
loginBloc.sinkLoginRequest.add(loginRequest);
},
decoration: InputDecoration(
hintText:
appLocalization(context).login_account_hint,
prefixIcon: Padding(
padding: context.dynamicPadding(16),
child: IconConstants.instance
.getMaterialIcon(Icons.person),
),
),
),
SizedBox(height: context.lowValue),
StreamBuilder<bool>(
stream: loginBloc.streamIsShowPassword,
builder: (context, isShowPassSnapshot) {
return TextFormField(
textInputAction: TextInputAction.done,
obscureText:
isShowPassSnapshot.data ?? isShowPassword,
validator: (value) {
if (value == null || value.isEmpty) {
return appLocalization(context)
.login_password_not_empty;
}
return null;
},
onSaved: (password) {
loginRequest["password"] = password!;
loginBloc.sinkLoginRequest.add(loginRequest);
},
decoration: InputDecoration(
hintText: appLocalization(context)
.login_password_hint,
prefixIcon: Padding(
padding: context.dynamicPadding(16),
child: IconConstants.instance
.getMaterialIcon(Icons.lock),
),
suffixIcon: IconButton(
onPressed: () {
isShowPassword = !isShowPassword;
loginBloc.sinkIsShowPassword
.add(isShowPassword);
},
icon: isShowPassword
? IconConstants.instance
.getMaterialIcon(
Icons.visibility,
)
: IconConstants.instance
.getMaterialIcon(
Icons.visibility_off,
),
),
),
);
},
),
SizedBox(
height: context.mediumValue,
),
SizedBox(
width: MediaQuery.sizeOf(context).width,
height: 50.0,
child: ElevatedButton(
style: const ButtonStyle(
backgroundColor:
WidgetStatePropertyAll(Colors.blue),
foregroundColor:
WidgetStatePropertyAll(Colors.white),
),
onPressed: () {
validate();
},
child: Text(
appLocalization(context).login_button_content),
),
),
const SizedBox(height: 100.0,)
],
),
),
);
},
)
],
),
),
),
);
}
void validate() async {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
var data =
await apiServices.login(APIPathConstants.LOGIN_PATH, loginRequest);
log("Data: $data");
// log(message)
if (data != "") {
Map<String, dynamic> tokenData = jsonDecode(data);
String token = tokenData['token'];
LocaleManager.instance.setString(PreferencesKeys.TOKEN, token);
String userToken = getBaseToken(token);
var decode = decodeBase64Token(userToken);
LoginModel loginModel =
LoginModel.fromJson(jsonDecode(decode) as Map<String, dynamic>);
LocaleManager.instance.setString(PreferencesKeys.UID, loginModel.id!);
LocaleManager.instance.setInt(PreferencesKeys.EXP, loginModel.exp!);
LocaleManager.instance
.setString(PreferencesKeys.ROLE, loginModel.role!);
context.goNamed(AppRoutes.HOME.name);
// context.goNamed("notification");
} else {
showErrorTopSnackBarCustom(
context, appLocalization(context).login_incorrect_usernameOrPass);
}
}
}
void checkLogin(BuildContext context) async {
// ThemeNotifier themeNotifier = context.watch<ThemeNotifier>();
await LocaleManager.prefrencesInit();
// String theme = LocaleManager.instance.getStringValue(PreferencesKeys.THEME);
String token = LocaleManager.instance.getStringValue(PreferencesKeys.TOKEN);
int exp = LocaleManager.instance.getIntValue(PreferencesKeys.EXP);
log("Token cu: ${LocaleManager.instance.getStringValue(PreferencesKeys.TOKEN)}");
log("UID: ${LocaleManager.instance.getStringValue(PreferencesKeys.UID)}");
log("EXP: ${LocaleManager.instance.getIntValue(PreferencesKeys.EXP)}");
log("Role: ${LocaleManager.instance.getStringValue(PreferencesKeys.ROLE)}");
log("Theme: ${LocaleManager.instance.getStringValue(PreferencesKeys.THEME)}");
log("Lang: ${LocaleManager.instance.getStringValue(PreferencesKeys.LANGUAGE_CODE)}");
int timeNow = DateTime.now().millisecondsSinceEpoch ~/ 1000;
if (token != "" && (exp - timeNow) > 7200) {
context.goNamed(AppRoutes.HOME.name);
// context.goNamed("notification");
}
}
getBaseToken(String token) {
List<String> parts = token.split('.');
String userToken = parts[1];
return userToken;
}
decodeBase64Token(String value) {
List<int> res = base64.decode(base64.normalize(value));
return utf8.decode(res);
}
}