diff --git a/unit2/lib/bloc/bloc/user_bloc.dart b/unit2/lib/bloc/bloc/user_bloc.dart new file mode 100644 index 0000000..1d10614 --- /dev/null +++ b/unit2/lib/bloc/bloc/user_bloc.dart @@ -0,0 +1,26 @@ +import 'package:bloc/bloc.dart'; +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:unit2/model/login_data/version_info.dart'; +import 'package:unit2/sevices/login_service/auth_service.dart'; +import 'package:unit2/widgets/error_state.dart'; + +part 'user_event.dart'; +part 'user_state.dart'; + +class UserBloc extends Bloc { + UserBloc() : super(UserInitial()) { + on((event, emit) async { + debugPrint("getApkEvent is called"); + try { + emit(SplashScreen()); + VersionInfo versionInfo = await AuthService.instance.getVersionInfo(); + emit(VersionLoaded(versionInfo: versionInfo)); + } catch (e) { + emit(UserError( + message: e.toString(), + )); + } + }); + } +} diff --git a/unit2/lib/bloc/bloc/user_event.dart b/unit2/lib/bloc/bloc/user_event.dart new file mode 100644 index 0000000..1094d9f --- /dev/null +++ b/unit2/lib/bloc/bloc/user_event.dart @@ -0,0 +1,13 @@ +part of 'user_bloc.dart'; + +abstract class UserEvent extends Equatable { + const UserEvent(); + + @override + List get props => []; +} + +class GetApkVersion extends UserEvent{ + @override + List get props => []; +} diff --git a/unit2/lib/bloc/bloc/user_state.dart b/unit2/lib/bloc/bloc/user_state.dart new file mode 100644 index 0000000..c9b4833 --- /dev/null +++ b/unit2/lib/bloc/bloc/user_state.dart @@ -0,0 +1,36 @@ +part of 'user_bloc.dart'; + +abstract class UserState extends Equatable { + const UserState(); + + @override + List get props => []; +} + +class UserInitial extends UserState {} + +class UserLoading extends UserState { + final String? message; + const UserLoading({this.message}); + @override + List get props => [message!]; +} + +class SplashScreen extends UserState { + @override + List get props => []; +} + +class UserError extends UserState { + final String? message; + const UserError({this.message}); + @override + List get props => []; +} + +class VersionLoaded extends UserState { + final VersionInfo? versionInfo; + const VersionLoaded({this.versionInfo}); + @override + List get props => [versionInfo!]; +} diff --git a/unit2/lib/main.dart b/unit2/lib/main.dart index 9b80a31..af6b45d 100644 --- a/unit2/lib/main.dart +++ b/unit2/lib/main.dart @@ -2,6 +2,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:device_preview/device_preview.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:unit2/bloc/bloc/user_bloc.dart'; import './utils/router.dart'; import './utils/global.dart'; @@ -35,23 +37,26 @@ class MyApp extends StatelessWidget { safeBlockHorizontal = (screenWidth - safeAreaHorizontal) / 100; safeBlockVertical = (screenHeight - safeAreaVertical) / 100; - return MaterialApp.router( - // useInheritedMediaQuery: true, - // locale: DevicePreview.locale(context), - // builder: DevicePreview.appBuilder, - routeInformationParser: goRouter.routeInformationParser, - routerDelegate: goRouter.routerDelegate, - // routeInformationProvider: goRouter.routeInformationProvider, - title: 'uniT2 - Universal Tracker and Tracer', - theme: ThemeData( - appBarTheme: const AppBarTheme( - systemOverlayStyle: SystemUiOverlayStyle( - statusBarBrightness: Brightness.dark, - statusBarColor: Colors.black), + return BlocProvider( + create: (context) => UserBloc(), + child: MaterialApp.router( + // useInheritedMediaQuery: true, + // locale: DevicePreview.locale(context), + // builder: DevicePreview.appBuilder, + routeInformationParser: goRouter.routeInformationParser, + routerDelegate: goRouter.routerDelegate, + // routeInformationProvider: goRouter.routeInformationProvider, + title: 'uniT2 - Universal Tracker and Tracer', + theme: ThemeData( + appBarTheme: const AppBarTheme( + systemOverlayStyle: SystemUiOverlayStyle( + statusBarBrightness: Brightness.dark, + statusBarColor: Colors.black), + ), + fontFamily: 'LexendDeca', ), - fontFamily: 'LexendDeca', + debugShowCheckedModeBanner: false, ), - debugShowCheckedModeBanner: false, ); } } diff --git a/unit2/lib/model/login_data/employee_info/department.dart b/unit2/lib/model/login_data/employee_info/department.dart new file mode 100644 index 0000000..c6d6d78 --- /dev/null +++ b/unit2/lib/model/login_data/employee_info/department.dart @@ -0,0 +1,41 @@ +import 'package:unit2/model/login_data/employee_info/head.dart'; + +class Department { + Department({ + this.id, + this.code, + this.head, + this.name, + this.acronym, + this.parentStationId, + this.fullCode, + }); + + int? id; + String? code; + Head? head; + String? name; + int? acronym; + int? parentStationId; + String? fullCode; + + factory Department.fromJson(Map json) => Department( + id: json["id"], + code: json["code"], + head: json["head"], + name: json["name"], + acronym: json["acronym"], + parentStationId: json["parent_station_id"], + fullCode: json["full_code"], + ); + + Map toJson() => { + "id": id, + "code": code, + "head": head, + "name": name, + "acronym": acronym, + "parent_station_id": parentStationId, + "full_code": fullCode, + }; +} \ No newline at end of file diff --git a/unit2/lib/model/login_data/employee_info/employee_info.dart b/unit2/lib/model/login_data/employee_info/employee_info.dart new file mode 100644 index 0000000..5655fed --- /dev/null +++ b/unit2/lib/model/login_data/employee_info/employee_info.dart @@ -0,0 +1,137 @@ +import 'package:unit2/model/login_data/employee_info/office.dart'; + +class EmployeeInfo { + EmployeeInfo({ + this.employeeId, + this.empid, + this.classid, + this.uuid, + this.office, + this.profile, + }); + + String? employeeId; + int? empid; + String? classid; + String? uuid; + Office? office; + Profile? profile; + + factory EmployeeInfo.fromJson(Map json) => EmployeeInfo( + employeeId: json["employee_id"], + empid: json["empid"], + classid: json["classid"], + uuid: json["uuid"], + office: Office.fromJson(json["office"]), + profile: Profile.fromJson(json["profile"]), + ); + + Map toJson() => { + "employee_id": employeeId, + "empid": empid, + "classid": classid, + "uuid": uuid, + "office": office!.toJson(), + "profile": profile!.toJson(), + }; +} +class Profile { + Profile({ + this.id, + this.sex, + this.gender, + this.deceased, + this.heightM, + this.birthdate, + this.esigPath, + this.fullName, + this.lastName, + this.weightKg, + this.bloodType, + this.firstName, + this.photoPath, + this.maidenName, + this.middleName, + this.uuidQrcode, + this.civilStatus, + this.titlePrefix, + this.titleSuffix, + this.showTitleId, + this.lastFullName, + this.nameExtension, + }); + + int? id; + String? sex; + dynamic gender; + bool? deceased; + double? heightM; + DateTime? birthdate; + String? esigPath; + String? fullName; + String? lastName; + int? weightKg; + String? bloodType; + String? firstName; + String? photoPath; + String? maidenName; + String? middleName; + String? uuidQrcode; + String? civilStatus; + String? titlePrefix; + String? titleSuffix; + bool? showTitleId; + String? lastFullName; + String? nameExtension; + + factory Profile.fromJson(Map json) => Profile( + id: json["id"], + sex: json["sex"], + gender: json["gender"], + deceased: json["deceased"], + heightM: json["height_m"].toDouble(), + birthdate: DateTime.parse(json["birthdate"]), + esigPath: json["esig_path"], + fullName: json["full_name"], + lastName: json["last_name"], + weightKg: json["weight_kg"], + bloodType: json["blood_type"], + firstName: json["first_name"], + photoPath: json["photo_path"], + maidenName: json["maiden_name"], + middleName: json["middle_name"], + uuidQrcode: json["uuid_qrcode"], + civilStatus: json["civil_status"], + titlePrefix: json["title_prefix"], + titleSuffix: json["title_suffix"], + showTitleId: json["show_title_id"], + lastFullName: json["last_full_name"], + nameExtension: json["name_extension"], + ); + + Map toJson() => { + "id": id, + "sex": sex, + "gender": gender, + "deceased": deceased, + "height_m": heightM, + "birthdate": + "${birthdate!.year.toString().padLeft(4, '0')}-${birthdate!.month.toString().padLeft(2, '0')}-${birthdate!.day.toString().padLeft(2, '0')}", + "esig_path": esigPath, + "full_name": fullName, + "last_name": lastName, + "weight_kg": weightKg, + "blood_type": bloodType, + "first_name": firstName, + "photo_path": photoPath, + "maiden_name": maidenName, + "middle_name": middleName, + "uuid_qrcode": uuidQrcode, + "civil_status": civilStatus, + "title_prefix": titlePrefix, + "title_suffix": titleSuffix, + "show_title_id": showTitleId, + "last_full_name": lastFullName, + "name_extension": nameExtension, + }; +} diff --git a/unit2/lib/model/login_data/employee_info/head.dart b/unit2/lib/model/login_data/employee_info/head.dart new file mode 100644 index 0000000..afeee07 --- /dev/null +++ b/unit2/lib/model/login_data/employee_info/head.dart @@ -0,0 +1,44 @@ + +class Head { + Head({ + this.id, + this.title, + this.classid, + this.fullName, + this.personId, + this.employeeid, + this.officeposid, + this.lastFullName, + }); + + int? id; + String? title; + String? classid; + String? fullName; + int? personId; + String? employeeid; + int? officeposid; + String? lastFullName; + + factory Head.fromJson(Map json) => Head( + id: json["id"], + title: json["title"], + classid: json["classid"], + fullName: json["full_name"], + personId: json["person_id"], + employeeid: json["employeeid"], + officeposid: json["officeposid"], + lastFullName: json["last_full_name"], + ); + + Map toJson() => { + "id": id, + "title": title, + "classid": classid, + "full_name": fullName, + "person_id": personId, + "employeeid": employeeid, + "officeposid": officeposid, + "last_full_name": lastFullName, + }; +} \ No newline at end of file diff --git a/unit2/lib/model/login_data/employee_info/office.dart b/unit2/lib/model/login_data/employee_info/office.dart new file mode 100644 index 0000000..bd06e2e --- /dev/null +++ b/unit2/lib/model/login_data/employee_info/office.dart @@ -0,0 +1,47 @@ +import 'department.dart'; +import 'position_class.dart'; + +class Office { + Office({ + this.unit, + this.section, + this.division, + this.posstatid, + this.department, + this.stationId, + this.positionClass, + this.positionSpecificrole, + }); + + Department? unit; + Department? section; + Department? division; + int? posstatid; + Department? department; + int? stationId; + PositionClass? positionClass; + PositionSpecificrole? positionSpecificrole; + + factory Office.fromJson(Map json) => Office( + unit: Department.fromJson(json["unit"]), + section: Department.fromJson(json["section"]), + division: Department.fromJson(json["division"]), + posstatid: json["posstatid"], + department: Department.fromJson(json["department"]), + stationId: json["station_id"], + positionClass: PositionClass.fromJson(json["position_class"]), + positionSpecificrole: + PositionSpecificrole.fromJson(json["position_specificrole"]), + ); + + Map toJson() => { + "unit": unit!.toJson(), + "section": section!.toJson(), + "division": division!.toJson(), + "posstatid": posstatid, + "department": department!.toJson(), + "station_id": stationId, + "position_class": positionClass!.toJson(), + "position_specificrole": positionSpecificrole!.toJson(), + }; +} \ No newline at end of file diff --git a/unit2/lib/model/login_data/employee_info/position_class.dart b/unit2/lib/model/login_data/employee_info/position_class.dart new file mode 100644 index 0000000..878847f --- /dev/null +++ b/unit2/lib/model/login_data/employee_info/position_class.dart @@ -0,0 +1,65 @@ +class PositionClass { + PositionClass({ + this.level, + this.classid, + this.groupcode, + this.salarygrade, + this.classSuffix, + this.classTitleid, + this.qualificationid, + this.competencyModelId, + }); + + int? level; + String? classid; + String? groupcode; + int? salarygrade; + String? classSuffix; + PositionSpecificrole? classTitleid; + int? qualificationid; + int? competencyModelId; + + factory PositionClass.fromJson(Map json) => PositionClass( + level: json["level"], + classid: json["classid"], + groupcode: json["groupcode"], + salarygrade: json["salarygrade"], + classSuffix: json["class_suffix"], + classTitleid: PositionSpecificrole.fromJson(json["class_titleid"]), + qualificationid: json["qualificationid"], + competencyModelId: json["competency_model_id"], + ); + + Map toJson() => { + "level": level, + "classid": classid, + "groupcode": groupcode, + "salarygrade": salarygrade, + "class_suffix": classSuffix, + "class_titleid": classTitleid!.toJson(), + "qualificationid": qualificationid, + "competency_model_id": competencyModelId, + }; +} + + +class PositionSpecificrole { + PositionSpecificrole({ + this.title, + this.titleid, + }); + + String? title; + int? titleid; + + factory PositionSpecificrole.fromJson(Map json) => + PositionSpecificrole( + title: json["title"], + titleid: json["titleid"], + ); + + Map toJson() => { + "title": title, + "titleid": titleid, + }; +} \ No newline at end of file diff --git a/unit2/lib/model/login_data/user_info/assigned_area.dart b/unit2/lib/model/login_data/user_info/assigned_area.dart new file mode 100644 index 0000000..d67b215 --- /dev/null +++ b/unit2/lib/model/login_data/user_info/assigned_area.dart @@ -0,0 +1,31 @@ +class AssignedArea { + AssignedArea({ + this.id, + this.areaid, + this.isactive, + this.areaName, + this.areaTypeName, + }); + + int? id; + String? areaid; + bool? isactive; + String? areaName; + String? areaTypeName; + + factory AssignedArea.fromJson(Map json) => AssignedArea( + id: json["id"], + areaid: json["areaid"], + isactive: json["isactive"], + areaName: json["area_name"], + areaTypeName: json["area_type_name"], + ); + + Map toJson() => { + "id": id, + "areaid": areaid, + "isactive": isactive, + "area_name": areaName, + "area_type_name": areaTypeName, + }; +} \ No newline at end of file diff --git a/unit2/lib/model/login_data/user_info/login_user.dart b/unit2/lib/model/login_data/user_info/login_user.dart new file mode 100644 index 0000000..8d492b7 --- /dev/null +++ b/unit2/lib/model/login_data/user_info/login_user.dart @@ -0,0 +1,48 @@ +import 'role.dart'; +class LoginUser { + LoginUser({ + this.id, + this.profileId, + this.firstName, + this.lastName, + this.username, + this.email, + this.staff, + this.roles, + }); + + int? id; + int? profileId; + String? firstName; + String? lastName; + String? username; + String? email; + bool? staff; + List? roles; + + factory LoginUser.fromJson(Map json) => LoginUser( + id: json["id"], + profileId: json["profile_id"], + firstName: json["first_name"], + lastName: json["last_name"], + username: json["username"], + email: json["email"], + staff: json["staff"], + roles: json["roles"] == null + ? [] + : List.from(json["roles"]!.map((x) => Role.fromJson(x))), + ); + + Map toJson() => { + "id": id, + "profile_id": profileId, + "first_name": firstName, + "last_name": lastName, + "username": username, + "email": email, + "staff": staff, + "roles": roles == null + ? [] + : List.from(roles!.map((x) => x!.toJson())), + }; +} \ No newline at end of file diff --git a/unit2/lib/model/login_data/user_info/modue.dart b/unit2/lib/model/login_data/user_info/modue.dart new file mode 100644 index 0000000..700d9a5 --- /dev/null +++ b/unit2/lib/model/login_data/user_info/modue.dart @@ -0,0 +1,68 @@ +class Module { + Module({ + this.id, + this.icon, + this.name, + this.slug, + this.objects, + }); + + int? id; + String? icon; + String? name; + String? slug; + List? objects; + + factory Module.fromJson(Map json) => Module( + id: json["id"], + icon: json["icon"], + name: json["name"], + slug: json["slug"], + objects: json["objects"] == null + ? [] + : List.from( + json["objects"]!.map((x) => Object.fromJson(x))), + ); + + Map toJson() => { + "id": id, + "icon": icon, + "name": name, + "slug": slug, + "objects": objects == null + ? [] + : List.from(objects!.map((x) => x!.toJson())), + }; +} + +class Object { + Object({ + this.id, + this.name, + this.slug, + this.operations, + }); + + int? id; + String? name; + String? slug; + List? operations; + + factory Object.fromJson(Map json) => Object( + id: json["id"], + name: json["name"], + slug: json["slug"], + operations: json["operations"] == null + ? [] + : List.from(json["operations"]!.map((x) => x)), + ); + + Map toJson() => { + "id": id, + "name": name, + "slug": slug, + "operations": operations == null + ? [] + : List.from(operations!.map((x) => x)), + }; +} \ No newline at end of file diff --git a/unit2/lib/model/login_data/user_info/role.dart b/unit2/lib/model/login_data/user_info/role.dart new file mode 100644 index 0000000..5975d6d --- /dev/null +++ b/unit2/lib/model/login_data/user_info/role.dart @@ -0,0 +1,74 @@ +import 'assigned_area.dart'; +import 'modue.dart'; + +class Role { + Role({ + this.id, + this.name, + this.modules, + this.assignedArea, + }); + + int? id; + String? name; + List? modules; + List? assignedArea; + + factory Role.fromJson(Map json) => Role( + id: json["id"], + name: json["name"], + modules: json["modules"] == null + ? [] + : List.from( + json["modules"]!.map((x) => Module.fromJson(x))), + assignedArea: json["assigned_area"] == null + ? [] + : json["assigned_area"] == null + ? [] + : List.from(json["assigned_area"]! + .map((x) => AssignedArea.fromJson(x))), + ); + + Map toJson() => { + "id": id, + "name": name, + "modules": modules == null + ? [] + : List.from(modules!.map((x) => x!.toJson())), + "assigned_area": assignedArea == null + ? [] + : assignedArea == null + ? [] + : List.from(assignedArea!.map((x) => x!.toJson())), + }; +}class Object { + Object({ + this.id, + this.name, + this.slug, + this.operations, + }); + + int? id; + String? name; + String? slug; + List? operations; + + factory Object.fromJson(Map json) => Object( + id: json["id"], + name: json["name"], + slug: json["slug"], + operations: json["operations"] == null + ? [] + : List.from(json["operations"]!.map((x) => x)), + ); + + Map toJson() => { + "id": id, + "name": name, + "slug": slug, + "operations": operations == null + ? [] + : List.from(operations!.map((x) => x)), + }; +} \ No newline at end of file diff --git a/unit2/lib/model/login_data/user_info/user_data.dart b/unit2/lib/model/login_data/user_info/user_data.dart new file mode 100644 index 0000000..470404c --- /dev/null +++ b/unit2/lib/model/login_data/user_info/user_data.dart @@ -0,0 +1,71 @@ +import 'dart:convert'; + +import 'package:unit2/model/login_data/employee_info/employee_info.dart'; + +import 'login_user.dart'; + +UserData? userDataFromJson(String str) => UserData.fromJson(json.decode(str)); + +String userDataToJson(UserData? data) => json.encode(data!.toJson()); + +class UserData { + UserData({ + this.user, + this.employeeInfo, + }); + + UserDataUser? user; + EmployeeInfo? employeeInfo; + + factory UserData.fromJson(Map json) => UserData( + user: UserDataUser.fromJson(json["user"]), + employeeInfo: EmployeeInfo.fromJson(json["employee_info"]), + ); + + Map toJson() => { + "user": user!.toJson(), + "employee_info": employeeInfo!.toJson(), + }; +} + +class UserDataUser { + UserDataUser({ + this.login, + }); + + Login? login; + + factory UserDataUser.fromJson(Map json) => UserDataUser( + login: Login.fromJson(json["login"]), + ); + + Map toJson() => { + "login": login!.toJson(), + }; +} + +class Login { + Login({ + this.dateTime, + this.token, + this.user, + }); + + DateTime? dateTime; + String? token; + LoginUser? user; + + factory Login.fromJson(Map json) => Login( + dateTime: DateTime.parse(json["date_time"]), + token: json["token"], + user: LoginUser.fromJson(json["user"]), + ); + + Map toJson() => { + "date_time": dateTime?.toIso8601String(), + "token": token, + "user": user!.toJson(), + }; +} + + diff --git a/unit2/lib/model/login_data/version_info.dart b/unit2/lib/model/login_data/version_info.dart new file mode 100644 index 0000000..12ae4fb --- /dev/null +++ b/unit2/lib/model/login_data/version_info.dart @@ -0,0 +1,48 @@ +class VersionInfo { + VersionInfo({ + this.version, + this.versionInfo, + this.dateReleased, + this.development, + this.production, + this.downloadUrl, + this.arm64v8aDownloadUrl, + this.armeabiv7aDownloadUrl, + this.x8664DownloadUrl, + }); + + String? version; + String? versionInfo; + DateTime? dateReleased; + bool? development; + bool? production; + String? downloadUrl; + String? arm64v8aDownloadUrl; + String? armeabiv7aDownloadUrl; + String? x8664DownloadUrl; + + factory VersionInfo.fromJson(Map json) => VersionInfo( + version: json["version"], + versionInfo: json["version_info"], + dateReleased: DateTime.parse(json["date_released"]), + development: json["development"], + production: json["production"], + downloadUrl: json["download_url"], + arm64v8aDownloadUrl: json["arm64_v8a_download_url"], + armeabiv7aDownloadUrl: json["armeabi_v7a_download_url"], + x8664DownloadUrl: json["x86_64_down_download_url"], + ); + + Map toJson() => { + "version": version, + "version_info": versionInfo, + "date_released": + "${dateReleased!.year.toString().padLeft(4, '0')}-${dateReleased!.month.toString().padLeft(2, '0')}-${dateReleased!.day.toString().padLeft(2, '0')}", + "development": development, + "production": production, + "download_url": downloadUrl, + "arm64_v8a_download_url": arm64v8aDownloadUrl, + "armeabi_v7a_download_url": armeabiv7aDownloadUrl, + "x86_64_down_download_url": x8664DownloadUrl, + }; +} diff --git a/unit2/lib/screens/unit2/login/login.dart b/unit2/lib/screens/unit2/login/login.dart index 1ad705a..384a63e 100644 --- a/unit2/lib/screens/unit2/login/login.dart +++ b/unit2/lib/screens/unit2/login/login.dart @@ -1,5 +1,6 @@ import 'package:barcode_scan2/barcode_scan2.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:fluttericon/font_awesome5_icons.dart'; @@ -7,10 +8,13 @@ import 'package:form_builder_validators/form_builder_validators.dart'; import 'package:go_router/go_router.dart'; import 'package:flutter_progress_hud/flutter_progress_hud.dart'; +import 'package:unit2/bloc/bloc/user_bloc.dart'; import 'package:unit2/utils/alerts.dart'; import 'package:unit2/utils/scanner.dart'; import 'package:unit2/utils/text_container.dart'; +import 'package:unit2/widgets/error_state.dart'; +import '../../../widgets/splash_screen.dart'; import '../../../widgets/wave.dart'; import '../../../utils/global.dart'; import '../../../theme-data.dart/colors.dart'; @@ -36,236 +40,258 @@ class _UniT2LoginState extends State { onWillPop: pressAgainToExit, child: Scaffold( body: ProgressHUD( - child: Builder(builder: (context) { - return SizedBox( - child: SingleChildScrollView( - child: Stack( - children: [ - Positioned( - bottom: 0, - right: 0, - child: WaveReverse(height: blockSizeVertical * 7)), - SizedBox( - height: blockSizeVertical * 100, - child: FormBuilder( - key: _formKey, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 25), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SizedBox(height: blockSizeVertical * 7), - SvgPicture.asset( - 'assets/svgs/logo.svg', - height: blockSizeVertical * 16, - allowDrawingOutsideViewBox: true, - color: primary, - ), - - Text( - welcome, - style: TextStyle( - fontSize: blockSizeVertical * 5, - fontWeight: FontWeight.w600), - ), - Text(unitApp, - style: TextStyle( - fontSize: blockSizeVertical * 8, - fontWeight: FontWeight.w800, - letterSpacing: .2, - height: 1, - color: primary)), - Text( - loginToContinue, - style: TextStyle( - fontSize: blockSizeVertical * 2, - height: 1.5, - fontWeight: FontWeight.w600), - ), - SizedBox( - height: blockSizeVertical * 1.5, - ), - // USERNAME - FormBuilderTextField( - name: 'username', - validator: FormBuilderValidators.required( - errorText: usernameRequired), - autofocus: false, - style: const TextStyle( - fontWeight: FontWeight.bold, - color: Colors.black87), - decoration: loginTextFieldStyle().copyWith()), - SizedBox( - height: blockSizeVertical * 1.5, - ), - // PASSWORD - FormBuilderTextField( - name: 'password', - validator: FormBuilderValidators.required( - errorText: passwordRequired), - - // initialValue: state.password, - onChanged: (value) { - value!.isEmpty - ? setState(() { - showSuffixIcon = false; - }) - : setState(() { - showSuffixIcon = true; - }); - }, - autofocus: false, - style: const TextStyle( - fontWeight: FontWeight.bold, - color: Colors.black87), - decoration: loginTextFieldStyle().copyWith( - suffixIcon: Visibility( - visible: showSuffixIcon, - child: _showPassword - ? IconButton( - icon: Icon(FontAwesome5.eye_slash, - size: 24, - color: Theme.of(context) - .textTheme - .displayLarge - ?.color), - onPressed: () { - setState(() { - _showPassword = false; - }); - }, - ) - : IconButton( - onPressed: () { - setState(() { - _showPassword = true; - }); - }, - icon: Icon(FontAwesome5.eye, - size: 24, - color: Theme.of(context) - .textTheme - .displayLarge - ?.color)), - ), - prefixIcon: const Icon( - Icons.lock, - color: primary, - ), - labelText: "Password", - hintText: enterPassword), - obscureText: _showPassword ? true : false, - ), - SizedBox( - height: blockSizeVertical * 2, - ), - SizedBox( - height: blockSizeVertical * 7, - // Login Button - child: SizedBox( - width: MediaQuery.of(context).size.width, - child: ElevatedButton( - style: mainBtnStyle(second, - Colors.transparent, Colors.white54), - child: const Text( - login, - style: TextStyle(color: Colors.white), - ), - onPressed: () { - final progress = ProgressHUD.of(context); - progress?.showWithText( - 'Logging in...', - ); - FocusScope.of(context).unfocus(); - Future.delayed(const Duration(seconds: 5), - () { - progress!.dismiss(); - - context.goNamed("home"); - }); - // if (_formKey.currentState! - // .saveAndValidate()) { - // context.go(context.namedLocation('home')); - // } - - // if (_formKey.currentState.validate()) { - // _formKey.currentState.save(); - // BlocProvider.of(context) - // .add(UserWebLogin( - // password: password, - // username: username)); - // } - }, + child: BlocConsumer(listener: (context, state) { + if (state is UserLoading) { + final progress = ProgressHUD.of(context); + progress?.showWithText( + 'Logging in...', + ); + } + }, builder: (context, state) { + if (state is VersionLoaded) { + return Builder(builder: (context) { + return SizedBox( + child: SingleChildScrollView( + child: Stack( + children: [ + Positioned( + bottom: 0, + right: 0, + child: WaveReverse(height: blockSizeVertical * 7)), + SizedBox( + height: blockSizeVertical * 100, + child: FormBuilder( + key: _formKey, + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 25), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox(height: blockSizeVertical * 7), + SvgPicture.asset( + 'assets/svgs/logo.svg', + height: blockSizeVertical * 16, + allowDrawingOutsideViewBox: true, + color: primary, ), - ), - ), - SizedBox( - height: blockSizeVertical * 1.5, - ), - SizedBox( - height: blockSizeVertical * 7, - child: SizedBox( + Text( + welcome, + style: TextStyle( + fontSize: blockSizeVertical * 5, + fontWeight: FontWeight.w600), + ), + Text(unitApp, + style: TextStyle( + fontSize: blockSizeVertical * 8, + fontWeight: FontWeight.w800, + letterSpacing: .2, + height: 1, + color: primary)), + Text( + loginToContinue, + style: TextStyle( + fontSize: blockSizeVertical * 2, + height: 1.5, + fontWeight: FontWeight.w600), + ), + SizedBox( + height: blockSizeVertical * 1.5, + ), + // USERNAME + FormBuilderTextField( + name: 'username', + validator: FormBuilderValidators.required( + errorText: usernameRequired), + autofocus: false, + style: const TextStyle( + fontWeight: FontWeight.bold, + color: Colors.black87), + decoration: + loginTextFieldStyle().copyWith()), + SizedBox( + height: blockSizeVertical * 1.5, + ), + // PASSWORD + FormBuilderTextField( + name: 'password', + validator: FormBuilderValidators.required( + errorText: passwordRequired), + + // initialValue: state.password, + onChanged: (value) { + value!.isEmpty + ? setState(() { + showSuffixIcon = false; + }) + : setState(() { + showSuffixIcon = true; + }); + }, + autofocus: false, + style: const TextStyle( + fontWeight: FontWeight.bold, + color: Colors.black87), + decoration: loginTextFieldStyle().copyWith( + suffixIcon: Visibility( + visible: showSuffixIcon, + child: _showPassword + ? IconButton( + icon: Icon( + FontAwesome5.eye_slash, + size: 24, + color: Theme.of(context) + .textTheme + .displayLarge + ?.color), + onPressed: () { + setState(() { + _showPassword = false; + }); + }, + ) + : IconButton( + onPressed: () { + setState(() { + _showPassword = true; + }); + }, + icon: Icon(FontAwesome5.eye, + size: 24, + color: Theme.of(context) + .textTheme + .displayLarge + ?.color)), + ), + prefixIcon: const Icon( + Icons.lock, + color: primary, + ), + labelText: "Password", + hintText: enterPassword), + obscureText: _showPassword ? true : false, + ), + SizedBox( + height: blockSizeVertical * 2, + ), + SizedBox( + height: blockSizeVertical * 7, + // Login Button + child: SizedBox( + width: MediaQuery.of(context).size.width, + child: ElevatedButton( + style: mainBtnStyle(second, + Colors.transparent, Colors.white54), + child: const Text( + login, + style: TextStyle(color: Colors.white), + ), + onPressed: () { + FocusScope.of(context).unfocus(); + // Future.delayed( + // const Duration(seconds: 5), () { + // progress!.dismiss(); + + // context.goNamed("home"); + // }); + // if (_formKey.currentState! + // .saveAndValidate()) { + // context.go(context.namedLocation('home')); + // } + + // if (_formKey.currentState.validate()) { + // _formKey.currentState.save(); + // BlocProvider.of(context) + // .add(UserWebLogin( + // password: password, + // username: username)); + // } + }, + ), + ), + ), + SizedBox( + height: blockSizeVertical * 1.5, + ), + + SizedBox( + height: blockSizeVertical * 7, + child: SizedBox( + width: + MediaQuery.of(context).size.width, + child: ElevatedButton.icon( + style: mainBtnStyle(Colors.white, + second, primary.withOpacity(.4)), + icon: const Icon( + Icons.qr_code, + color: second, + ), + label: const Text( + loginViaQr, + style: TextStyle(color: second), + ), + onPressed: () async { + context.goNamed('register'); + // ScanResult result = + // await QRCodeBarCodeScanner.instance + // .scanner(); + + // debugPrint(result.type.toString()); + // debugPrint( + // result.rawContent.toString()); + // BlocProvider.of(context) + // .add(QRCodelogin()); + }, + ), + )), + SizedBox( + height: blockSizeVertical * 1, + ), + const LoginViaQr(text: emergencyReponseLabel), + SizedBox( + height: blockSizeVertical * 1, + ), + // REQUEST SOS + SizedBox( + height: screenHeight * .07, width: MediaQuery.of(context).size.width, child: ElevatedButton.icon( - style: mainBtnStyle(Colors.white, second, - primary.withOpacity(.4)), - icon: const Icon( - Icons.qr_code, - color: second, - ), - label: const Text( - loginViaQr, - style: TextStyle(color: second), - ), - onPressed: () async { - context.goNamed('register'); - // ScanResult result = - // await QRCodeBarCodeScanner.instance - // .scanner(); - - // debugPrint(result.type.toString()); - // debugPrint( - // result.rawContent.toString()); - // BlocProvider.of(context) - // .add(QRCodelogin()); - }, - ), - )), - SizedBox( - height: blockSizeVertical * 1, + icon: const Icon( + FontAwesome5.life_ring, + color: Colors.white, + ), + style: mainBtnStyle(third, + Colors.transparent, Colors.white38), + onPressed: () { + context.goNamed('add-mobile'); + }, + label: const Text( + requestSOS, + style: TextStyle(color: Colors.white), + )), + ) + ], ), - const LoginViaQr(text: emergencyReponseLabel), - SizedBox( - height: blockSizeVertical * 1, - ), - // REQUEST SOS - SizedBox( - height: screenHeight * .07, - width: MediaQuery.of(context).size.width, - child: ElevatedButton.icon( - icon: const Icon( - FontAwesome5.life_ring, - color: Colors.white, - ), - style: mainBtnStyle(third, - Colors.transparent, Colors.white38), - onPressed: () { - context.goNamed('add-mobile'); - }, - label: const Text( - requestSOS, - style: TextStyle(color: Colors.white), - )), - ) - ], + ), ), ), - ), + ], ), - ], - ), - ), + ), + ); + }); + } + if (state is UserError) { + return ErrorState( + message: state.message, + ); + } + if (state is SplashScreen) { + return const UniTSplashScreen(); + } + return Center( + child: Text("Default"), ); }), ), diff --git a/unit2/lib/sevices/login_service/auth_service.dart b/unit2/lib/sevices/login_service/auth_service.dart new file mode 100644 index 0000000..487631c --- /dev/null +++ b/unit2/lib/sevices/login_service/auth_service.dart @@ -0,0 +1,39 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:unit2/model/login_data/version_info.dart'; +import 'package:http/http.dart' as http; +import '../../utils/text_container.dart'; +import '../../utils/urls.dart'; + +class AuthService { + static final AuthService _instance = AuthService(); + static AuthService get instance => _instance; + + Future getVersionInfo() async { + VersionInfo versionInfo = VersionInfo(); + Map headers = { + 'Content-Type': 'application/json; charset=UTF-8', + HttpHeaders.authorizationHeader: 'UniT2', + 'X-User': "" + }; + try { + http.Response response = await http.get( + Uri.https('unitylb1.agusandelnorte.gov.ph', + '/unit2/api/sys/apk_version/latest/'), + headers: headers); + if (response.statusCode == 200) { + Map data = jsonDecode(response.body); + versionInfo = VersionInfo.fromJson(data['data']); + } + } on TimeoutException catch (e) { + throw (timeoutError); + } on SocketException catch (e) { + throw (timeoutError); + } catch (e) { + throw (e.toString()); + } + return versionInfo; + } +} diff --git a/unit2/lib/utils/router.dart b/unit2/lib/utils/router.dart index 97d210b..4d00ecb 100644 --- a/unit2/lib/utils/router.dart +++ b/unit2/lib/utils/router.dart @@ -1,4 +1,7 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; +import 'package:unit2/bloc/bloc/user_bloc.dart'; import 'package:unit2/screens/unit2/login/register.dart'; import 'package:unit2/screens/unit2/roles/qr_code_scanner.dart/scan.dart'; import 'package:unit2/screens/unit2/roles/qr_code_scanner.dart/settings_screen.dart'; @@ -17,7 +20,11 @@ final GoRouter goRouter = GoRouter(routes: [ GoRoute( path: '/', name: 'login', - builder: (context, state) => UniT2Login(), + builder: (context, state) { + debugPrint("login bloc called"); + BlocProvider.of(context).add(GetApkVersion()); + return const UniT2Login(); + }, routes: [ GoRoute( name: 'register', diff --git a/unit2/lib/utils/urls.dart b/unit2/lib/utils/urls.dart index 77defa3..2274a80 100644 --- a/unit2/lib/utils/urls.dart +++ b/unit2/lib/utils/urls.dart @@ -1,8 +1,7 @@ class Url{ static final Url _instance = Url(); - static Url get instance => instance; + static Url get instance => _instance; - String host(){ return '192.168.10.219:3000'; } @@ -10,4 +9,9 @@ class Url{ String authentication(){ return '/api/account/auth/login'; } + + String apkUrl(){ + return ""; + } + } \ No newline at end of file diff --git a/unit2/lib/widgets/error_state.dart b/unit2/lib/widgets/error_state.dart new file mode 100644 index 0000000..ede9ef3 --- /dev/null +++ b/unit2/lib/widgets/error_state.dart @@ -0,0 +1,13 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/src/widgets/container.dart'; +import 'package:flutter/src/widgets/framework.dart'; + +class ErrorState extends StatelessWidget { + final String? message; + const ErrorState({super.key,this.message}); + + @override + Widget build(BuildContext context) { + return Center(child: Text(message!)); + } +} \ No newline at end of file diff --git a/unit2/lib/widgets/splash_screen.dart b/unit2/lib/widgets/splash_screen.dart new file mode 100644 index 0000000..026a977 --- /dev/null +++ b/unit2/lib/widgets/splash_screen.dart @@ -0,0 +1,12 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/src/widgets/container.dart'; +import 'package:flutter/src/widgets/framework.dart'; + +class UniTSplashScreen extends StatelessWidget { + const UniTSplashScreen({super.key}); + + @override + Widget build(BuildContext context) { + return const Center(child: Text("Splash Screen"),); + } +} \ No newline at end of file diff --git a/unit2/pubspec.lock b/unit2/pubspec.lock index fa07d08..5ec7dd3 100644 --- a/unit2/pubspec.lock +++ b/unit2/pubspec.lock @@ -50,6 +50,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.2.3" + bloc: + dependency: transitive + description: + name: bloc + url: "https://pub.dartlang.org" + source: hosted + version: "8.1.0" boolean_selector: dependency: transitive description: @@ -148,6 +155,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" + equatable: + dependency: "direct main" + description: + name: equatable + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.5" fake_async: dependency: transitive description: @@ -188,6 +202,13 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_bloc: + dependency: "direct main" + description: + name: flutter_bloc + url: "https://pub.dartlang.org" + source: hosted + version: "8.1.1" flutter_blurhash: dependency: transitive description: diff --git a/unit2/pubspec.yaml b/unit2/pubspec.yaml index 19b17d2..7257490 100644 --- a/unit2/pubspec.yaml +++ b/unit2/pubspec.yaml @@ -60,6 +60,8 @@ dependencies: signature: ^5.3.0 awesome_dialog: ^3.0.2 system_info2: ^2.0.4 + flutter_bloc: ^8.1.1 + equatable: ^2.0.5 dev_dependencies: flutter_test: