push fetch devices and connecting the filters

This commit is contained in:
ashrafzarkanisala
2024-08-24 16:37:10 +03:00
parent 0c047de9c1
commit 2597cdc311
68 changed files with 1800 additions and 989 deletions

View File

@ -0,0 +1 @@

View File

@ -22,33 +22,36 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
int? effectiveTimeTimeStamp; int? effectiveTimeTimeStamp;
int? expirationTimeTimeStamp; int? expirationTimeTimeStamp;
TextEditingController passwordName= TextEditingController(); TextEditingController passwordName = TextEditingController();
List<PasswordModel> filteredData = []; List<PasswordModel> filteredData = [];
List<PasswordModel> data=[]; List<PasswordModel> data = [];
Future<void> _onFetchTableData( Future<void> _onFetchTableData(
FetchTableData event, Emitter<AccessState> emit) async { FetchTableData event, Emitter<AccessState> emit) async {
try { try {
emit(AccessLoaded()); emit(AccessLoaded());
data = await AccessMangApi().fetchVisitorPassword(); data = await AccessMangApi().fetchVisitorPassword();
filteredData= data; filteredData = data;
updateTabsCount(); updateTabsCount();
emit(TableLoaded(data)); emit(TableLoaded(data));
} catch (e) { } catch (e) {
emit(FailedState(e.toString())); emit(FailedState(e.toString()));
} }
} }
void updateTabsCount() { void updateTabsCount() {
int toBeEffectiveCount = data.where((item) => item.passwordStatus.value== 'To Be Effective').length; int toBeEffectiveCount = data
int effectiveCount = data.where((item) => item.passwordStatus.value == 'Effective').length; .where((item) => item.passwordStatus.value == 'To Be Effective')
int expiredCount = data.where((item) => item.passwordStatus.value == 'Expired').length; .length;
int effectiveCount =
data.where((item) => item.passwordStatus.value == 'Effective').length;
int expiredCount =
data.where((item) => item.passwordStatus.value == 'Expired').length;
tabs[1] = 'To Be Effective ($toBeEffectiveCount)'; tabs[1] = 'To Be Effective ($toBeEffectiveCount)';
tabs[2] = 'Effective ($effectiveCount)'; tabs[2] = 'Effective ($effectiveCount)';
tabs[3] = 'Expired ($expiredCount)'; tabs[3] = 'Expired ($expiredCount)';
} }
int selectedIndex = 0; int selectedIndex = 0;
final List<String> tabs = [ final List<String> tabs = [
'All', 'All',
@ -57,20 +60,19 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
'Expired' 'Expired'
]; ];
Future selectFilterTap(
Future selectFilterTap(TabChangedEvent event, Emitter<AccessState> emit) async { TabChangedEvent event, Emitter<AccessState> emit) async {
try { try {
emit(AccessLoaded()); emit(AccessLoaded());
selectedIndex= event.selectedIndex; selectedIndex = event.selectedIndex;
emit(AccessInitial()); emit(AccessInitial());
emit(TableLoaded(data)); emit(TableLoaded(data));
} catch (e) { } catch (e) {
emit(FailedState( e.toString())); emit(FailedState(e.toString()));
return; return;
} }
} }
Future<void> selectTime(SelectTime event, Emitter<AccessState> emit) async { Future<void> selectTime(SelectTime event, Emitter<AccessState> emit) async {
emit(AccessLoaded()); emit(AccessLoaded());
@ -84,7 +86,6 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
final TimeOfDay? timePicked = await showTimePicker( final TimeOfDay? timePicked = await showTimePicker(
context: event.context, context: event.context,
initialTime: TimeOfDay.now(), initialTime: TimeOfDay.now(),
builder: (context, child) { builder: (context, child) {
return Theme( return Theme(
data: ThemeData.light().copyWith( data: ThemeData.light().copyWith(
@ -116,19 +117,30 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
selectedDateTime.day, selectedDateTime.day,
selectedDateTime.hour, selectedDateTime.hour,
selectedDateTime.minute, selectedDateTime.minute,
).millisecondsSinceEpoch ~/ 1000; // Divide by 1000 to remove milliseconds ).millisecondsSinceEpoch ~/
1000; // Divide by 1000 to remove milliseconds
if (event.isStart) { if (event.isStart) {
if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) { if (expirationTimeTimeStamp != null &&
CustomSnackBar.displaySnackBar('Effective Time cannot be later than Expiration Time.'); selectedTimestamp > expirationTimeTimeStamp!) {
CustomSnackBar.displaySnackBar(
'Effective Time cannot be later than Expiration Time.');
} else { } else {
startTime = selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds startTime = selectedDateTime
.toString()
.split('.')
.first; // Remove seconds and milliseconds
effectiveTimeTimeStamp = selectedTimestamp; effectiveTimeTimeStamp = selectedTimestamp;
} }
} else { } else {
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) { if (effectiveTimeTimeStamp != null &&
CustomSnackBar.displaySnackBar('Expiration Time cannot be earlier than Effective Time.'); selectedTimestamp < effectiveTimeTimeStamp!) {
CustomSnackBar.displaySnackBar(
'Expiration Time cannot be earlier than Effective Time.');
} else { } else {
endTime = selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds endTime = selectedDateTime
.toString()
.split('.')
.first; // Remove seconds and milliseconds
expirationTimeTimeStamp = selectedTimestamp; expirationTimeTimeStamp = selectedTimestamp;
} }
} }
@ -137,8 +149,8 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
emit(ChangeTimeState()); emit(ChangeTimeState());
} }
Future<void> _filterData(
Future<void> _filterData(FilterDataEvent event, Emitter<AccessState> emit) async { FilterDataEvent event, Emitter<AccessState> emit) async {
emit(AccessLoaded()); emit(AccessLoaded());
try { try {
filteredData = data.where((item) { filteredData = data.where((item) {
@ -151,7 +163,8 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
} }
} }
if (event.startTime != null && event.endTime != null) { if (event.startTime != null && event.endTime != null) {
final int? effectiveTime = int.tryParse(item.effectiveTime.toString()); final int? effectiveTime =
int.tryParse(item.effectiveTime.toString());
final int? invalidTime = int.tryParse(item.invalidTime.toString()); final int? invalidTime = int.tryParse(item.invalidTime.toString());
if (effectiveTime == null || invalidTime == null) { if (effectiveTime == null || invalidTime == null) {
matchesCriteria = false; matchesCriteria = false;
@ -163,11 +176,14 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
} }
} }
} }
if (event.selectedTabIndex == 1 && item.passwordStatus.value != 'To Be Effective') { if (event.selectedTabIndex == 1 &&
item.passwordStatus.value != 'To Be Effective') {
matchesCriteria = false; matchesCriteria = false;
} else if (event.selectedTabIndex == 2 && item.passwordStatus.value != 'Effective') { } else if (event.selectedTabIndex == 2 &&
item.passwordStatus.value != 'Effective') {
matchesCriteria = false; matchesCriteria = false;
} else if (event.selectedTabIndex == 3 && item.passwordStatus.value != 'Expired') { } else if (event.selectedTabIndex == 3 &&
item.passwordStatus.value != 'Expired') {
matchesCriteria = false; matchesCriteria = false;
} }
return matchesCriteria; return matchesCriteria;
@ -178,23 +194,25 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
} }
} }
resetSearch(ResetSearch event, Emitter<AccessState> emit) async{ resetSearch(ResetSearch event, Emitter<AccessState> emit) async {
emit(AccessLoaded()); emit(AccessLoaded());
startTime = 'Start Time'; startTime = 'Start Time';
endTime = 'End Time'; endTime = 'End Time';
passwordName.clear(); passwordName.clear();
selectedIndex=0; selectedIndex = 0;
effectiveTimeTimeStamp=null; effectiveTimeTimeStamp = null;
expirationTimeTimeStamp=null; expirationTimeTimeStamp = null;
add(FetchTableData()); add(FetchTableData());
} }
String timestampToDate(dynamic timestamp) { String timestampToDate(dynamic timestamp) {
DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(int.parse(timestamp) * 1000); DateTime dateTime =
DateTime.fromMillisecondsSinceEpoch(int.parse(timestamp) * 1000);
return "${dateTime.year}/${dateTime.month.toString().padLeft(2, '0')}/${dateTime.day.toString().padLeft(2, '0')}"; return "${dateTime.year}/${dateTime.month.toString().padLeft(2, '0')}/${dateTime.day.toString().padLeft(2, '0')}";
} }
Future<void> onTabChanged(TabChangedEvent event, Emitter<AccessState> emit) async { Future<void> onTabChanged(
TabChangedEvent event, Emitter<AccessState> emit) async {
try { try {
emit(AccessLoaded()); emit(AccessLoaded());
selectedIndex = event.selectedIndex; selectedIndex = event.selectedIndex;
@ -203,13 +221,19 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
filteredData = data; filteredData = data;
break; break;
case 1: // To Be Effective case 1: // To Be Effective
filteredData = data.where((item) => item.passwordStatus.value == "To Be Effective").toList(); filteredData = data
.where((item) => item.passwordStatus.value == "To Be Effective")
.toList();
break; break;
case 2: // Effective case 2: // Effective
filteredData = data.where((item) => item.passwordStatus.value == "Effective").toList(); filteredData = data
.where((item) => item.passwordStatus.value == "Effective")
.toList();
break; break;
case 3: // Expired case 3: // Expired
filteredData = data.where((item) => item.passwordStatus.value == "Expired").toList(); filteredData = data
.where((item) => item.passwordStatus.value == "Expired")
.toList();
break; break;
default: default:
filteredData = data; filteredData = data;
@ -218,12 +242,10 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
selectedTabIndex: selectedIndex, selectedTabIndex: selectedIndex,
passwordName: passwordName.text.toLowerCase(), passwordName: passwordName.text.toLowerCase(),
startTime: effectiveTimeTimeStamp, startTime: effectiveTimeTimeStamp,
endTime: expirationTimeTimeStamp endTime: expirationTimeTimeStamp));
));
emit(TableLoaded(filteredData)); emit(TableLoaded(filteredData));
} catch (e) { } catch (e) {
emit(FailedState(e.toString())); emit(FailedState(e.toString()));
} }
} }
} }

View File

@ -1,4 +1,3 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -8,7 +7,9 @@ abstract class AccessEvent extends Equatable {
@override @override
List<Object> get props => []; List<Object> get props => [];
} }
class FetchTableData extends AccessEvent {} class FetchTableData extends AccessEvent {}
class ResetSearch extends AccessEvent {} class ResetSearch extends AccessEvent {}
class TabChangedEvent extends AccessEvent { class TabChangedEvent extends AccessEvent {
@ -17,16 +18,14 @@ class TabChangedEvent extends AccessEvent {
const TabChangedEvent(this.selectedIndex); const TabChangedEvent(this.selectedIndex);
} }
class SelectTime extends AccessEvent { class SelectTime extends AccessEvent {
final BuildContext context; final BuildContext context;
final bool isStart; final bool isStart;
const SelectTime({required this.context,required this.isStart}); const SelectTime({required this.context, required this.isStart});
@override @override
List<Object> get props => [context,isStart]; List<Object> get props => [context, isStart];
} }
class FilterDataEvent extends AccessEvent { class FilterDataEvent extends AccessEvent {
final String? passwordName; final String? passwordName;
final int? startTime; final int? startTime;
@ -38,9 +37,5 @@ class FilterDataEvent extends AccessEvent {
this.startTime, this.startTime,
this.endTime, this.endTime,
required this.selectedTabIndex, // Initialize this field required this.selectedTabIndex, // Initialize this field
}); });
} }

View File

@ -11,6 +11,7 @@ abstract class AccessState extends Equatable {
class AccessInitial extends AccessState {} class AccessInitial extends AccessState {}
class AccessLoaded extends AccessState {} class AccessLoaded extends AccessState {}
class FailedState extends AccessState { class FailedState extends AccessState {
final String message; final String message;

View File

@ -30,9 +30,9 @@ class PasswordModel {
effectiveTime: json['effectiveTime'], effectiveTime: json['effectiveTime'],
passwordCreated: json['passwordCreated'], passwordCreated: json['passwordCreated'],
createdTime: json['createdTime'], createdTime: json['createdTime'],
passwordName: json['passwordName']??'No name', // New field passwordName: json['passwordName'] ?? 'No name', // New field
passwordStatus:AccessStatusExtension.fromString(json['passwordStatus']), passwordStatus: AccessStatusExtension.fromString(json['passwordStatus']),
passwordType:AccessTypeExtension.fromString(json['passwordType']), passwordType: AccessTypeExtension.fromString(json['passwordType']),
deviceUuid: json['deviceUuid'], deviceUuid: json['deviceUuid'],
); );
} }
@ -50,5 +50,4 @@ class PasswordModel {
'deviceUuid': deviceUuid, 'deviceUuid': deviceUuid,
}; };
} }
} }

View File

@ -6,7 +6,6 @@ import 'package:syncrow_web/pages/access_management/bloc/access_state.dart';
import 'package:syncrow_web/pages/common/custom_table.dart'; import 'package:syncrow_web/pages/common/custom_table.dart';
import 'package:syncrow_web/pages/common/date_time_widget.dart'; import 'package:syncrow_web/pages/common/date_time_widget.dart';
import 'package:syncrow_web/pages/common/buttons/default_button.dart'; import 'package:syncrow_web/pages/common/buttons/default_button.dart';
import 'package:syncrow_web/pages/common/filter/filter_widget.dart';
import 'package:syncrow_web/pages/visitor_password/view/visitor_password_dialog.dart'; import 'package:syncrow_web/pages/visitor_password/view/visitor_password_dialog.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/assets.dart';

View File

@ -84,7 +84,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
} else if (response == "You entered wrong otp") { } else if (response == "You entered wrong otp") {
forgetValidate = 'Wrong one time password.'; forgetValidate = 'Wrong one time password.';
emit(AuthInitialState()); emit(AuthInitialState());
}else if (response == "OTP expired") { } else if (response == "OTP expired") {
forgetValidate = 'One time password has been expired.'; forgetValidate = 'One time password has been expired.';
emit(AuthInitialState()); emit(AuthInitialState());
} }
@ -94,6 +94,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
// emit(FailureForgetState(error: failure.toString())); // emit(FailureForgetState(error: failure.toString()));
} }
} }
//925207 //925207
String? validateCode(String? value) { String? validateCode(String? value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {

View File

@ -13,47 +13,60 @@ class LoginButtonPressed extends AuthEvent {
final String password; final String password;
final String regionUuid; final String regionUuid;
const LoginButtonPressed({required this.username, required this.password, required this.regionUuid, }); const LoginButtonPressed({
required this.username,
required this.password,
required this.regionUuid,
});
@override @override
List<Object> get props => [username, password,regionUuid]; List<Object> get props => [username, password, regionUuid];
} }
class CheckBoxEvent extends AuthEvent { class CheckBoxEvent extends AuthEvent {
final bool? newValue; final bool? newValue;
const CheckBoxEvent({required this.newValue,}); const CheckBoxEvent({
required this.newValue,
});
@override @override
List<Object> get props => [newValue!,]; List<Object> get props => [
newValue!,
];
} }
class GetCodeEvent extends AuthEvent{} class GetCodeEvent extends AuthEvent {}
class SubmitEvent extends AuthEvent{} class SubmitEvent extends AuthEvent {}
class StartTimerEvent extends AuthEvent{} class StartTimerEvent extends AuthEvent {}
class StopTimerEvent extends AuthEvent{} class StopTimerEvent extends AuthEvent {}
class UpdateTimerEvent extends AuthEvent { class UpdateTimerEvent extends AuthEvent {
final int remainingTime; final int remainingTime;
final bool isButtonEnabled; final bool isButtonEnabled;
const UpdateTimerEvent({required this.remainingTime, required this.isButtonEnabled}); const UpdateTimerEvent(
{required this.remainingTime, required this.isButtonEnabled});
} }
class ChangePasswordEvent extends AuthEvent{} class ChangePasswordEvent extends AuthEvent {}
class SendOtpEvent extends AuthEvent{} class SendOtpEvent extends AuthEvent {}
class PasswordVisibleEvent extends AuthEvent{ class PasswordVisibleEvent extends AuthEvent {
final bool? newValue; final bool? newValue;
const PasswordVisibleEvent({required this.newValue,}); const PasswordVisibleEvent({
required this.newValue,
});
} }
class RegionInitialEvent extends AuthEvent {} class RegionInitialEvent extends AuthEvent {}
class CheckEnableEvent extends AuthEvent {} class CheckEnableEvent extends AuthEvent {}
class ChangeValidateEvent extends AuthEvent {} class ChangeValidateEvent extends AuthEvent {}
class SelectRegionEvent extends AuthEvent { class SelectRegionEvent extends AuthEvent {
@ -62,4 +75,3 @@ class SelectRegionEvent extends AuthEvent {
@override @override
List<Object> get props => [val]; List<Object> get props => [val];
} }

View File

@ -12,6 +12,7 @@ class LoginInitial extends AuthState {}
class AuthTokenLoading extends AuthState {} class AuthTokenLoading extends AuthState {}
class AuthLoading extends AuthState {} class AuthLoading extends AuthState {}
class AuthInitialState extends AuthState {} class AuthInitialState extends AuthState {}
class LoginSuccess extends AuthState {} class LoginSuccess extends AuthState {}
@ -55,7 +56,8 @@ class TimerState extends AuthState {
final bool isButtonEnabled; final bool isButtonEnabled;
final int remainingTime; final int remainingTime;
const TimerState({required this.isButtonEnabled, required this.remainingTime}); const TimerState(
{required this.isButtonEnabled, required this.remainingTime});
@override @override
List<Object> get props => [isButtonEnabled, remainingTime]; List<Object> get props => [isButtonEnabled, remainingTime];
@ -74,6 +76,7 @@ class AuthTokenError extends AuthError {
class AuthSuccess extends AuthState {} class AuthSuccess extends AuthState {}
class AuthTokenSuccess extends AuthSuccess {} class AuthTokenSuccess extends AuthSuccess {}
class TimerUpdated extends AuthState { class TimerUpdated extends AuthState {
final String formattedTime; final String formattedTime;
final bool isButtonEnabled; final bool isButtonEnabled;

View File

@ -1,5 +1,3 @@
class RegionModel { class RegionModel {
final String name; final String name;
final String id; final String id;

View File

@ -42,14 +42,11 @@ class Token {
//save token to secure storage //save token to secure storage
var storage = const FlutterSecureStorage(); var storage = const FlutterSecureStorage();
storage.write( storage.write(
key: loginAccessTokenKey, key: loginAccessTokenKey, value: json[loginAccessTokenKey] ?? '');
value: json[loginAccessTokenKey] ?? '');
storage.write( storage.write(
key: loginRefreshTokenKey, key: loginRefreshTokenKey, value: json[loginRefreshTokenKey] ?? '');
value: json[loginRefreshTokenKey] ?? '');
//create token object ? //create token object ?
return Token( return Token(json[loginAccessTokenKey] ?? '',
json[loginAccessTokenKey] ?? '',
json[loginRefreshTokenKey] ?? '', '', 0, 0); json[loginRefreshTokenKey] ?? '', '', 0, 0);
} }

View File

@ -1,5 +1,3 @@
import 'package:syncrow_web/pages/auth/model/token.dart'; import 'package:syncrow_web/pages/auth/model/token.dart';
class UserModel { class UserModel {

View File

@ -10,7 +10,10 @@ class VerifyPassCode {
final String deviceId; final String deviceId;
VerifyPassCode( VerifyPassCode(
{required this.phone, required this.passCode, required this.agent, required this.deviceId}); {required this.phone,
required this.passCode,
required this.agent,
required this.deviceId});
factory VerifyPassCode.fromJson(Map<String, dynamic> json) => VerifyPassCode( factory VerifyPassCode.fromJson(Map<String, dynamic> json) => VerifyPassCode(
phone: json[verificationPhone], phone: json[verificationPhone],

View File

@ -1,4 +1,3 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class ForgetPasswordMobilePage extends StatelessWidget { class ForgetPasswordMobilePage extends StatelessWidget {

View File

@ -1,10 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:syncrow_web/pages/auth/view/forget_password_mobile_page.dart'; import 'package:syncrow_web/pages/auth/view/forget_password_mobile_page.dart';
import 'package:syncrow_web/pages/auth/view/forget_password_web_page.dart'; import 'package:syncrow_web/pages/auth/view/forget_password_web_page.dart';
import 'package:syncrow_web/utils/responsive_layout.dart'; import 'package:syncrow_web/utils/responsive_layout.dart';
class ForgetPasswordPage extends StatelessWidget { class ForgetPasswordPage extends StatelessWidget {
const ForgetPasswordPage({super.key}); const ForgetPasswordPage({super.key});
@ -12,8 +10,6 @@ class ForgetPasswordPage extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return const ResponsiveLayout( return const ResponsiveLayout(
desktopBody: ForgetPasswordWebPage(), desktopBody: ForgetPasswordWebPage(),
mobileBody:ForgetPasswordWebPage() mobileBody: ForgetPasswordWebPage());
);
} }
} }

View File

@ -99,7 +99,8 @@ class ForgetPasswordWebPage extends StatelessWidget {
borderRadius: borderRadius:
const BorderRadius.all(Radius.circular(30)), const BorderRadius.all(Radius.circular(30)),
border: Border.all( border: Border.all(
color: ColorsManager.graysColor.withOpacity(0.2)), color:
ColorsManager.graysColor.withOpacity(0.2)),
), ),
child: Form( child: Form(
key: forgetBloc.forgetFormKey, key: forgetBloc.forgetFormKey,
@ -108,7 +109,8 @@ class ForgetPasswordWebPage extends StatelessWidget {
horizontal: size.width * 0.02, horizontal: size.width * 0.02,
vertical: size.width * 0.003), vertical: size.width * 0.003),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
const SizedBox(height: 10), const SizedBox(height: 10),
@ -122,21 +124,27 @@ class ForgetPasswordWebPage extends StatelessWidget {
const SizedBox(height: 10), const SizedBox(height: 10),
Text( Text(
'Please fill in your account information to\nretrieve your password', 'Please fill in your account information to\nretrieve your password',
style: Theme.of(context).textTheme.bodySmall!.copyWith( style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w400), fontWeight: FontWeight.w400),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Text( Text(
"Country/Region", "Country/Region",
style: Theme.of(context).textTheme.bodySmall!.copyWith( style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w400), fontWeight: FontWeight.w400),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
SizedBox( SizedBox(
@ -145,7 +153,8 @@ class ForgetPasswordWebPage extends StatelessWidget {
icon: const Icon( icon: const Icon(
Icons.keyboard_arrow_down_outlined, Icons.keyboard_arrow_down_outlined,
), ),
decoration: textBoxDecoration()!.copyWith( decoration:
textBoxDecoration()!.copyWith(
hintText: null, hintText: null,
), ),
hint: SizedBox( hint: SizedBox(
@ -160,15 +169,14 @@ class ForgetPasswordWebPage extends StatelessWidget {
), ),
), ),
isDense: true, isDense: true,
style: style: const TextStyle(
const TextStyle(color: Colors.black), color: Colors.black),
items: forgetBloc.regionList! items: forgetBloc.regionList!
.map((RegionModel region) { .map((RegionModel region) {
return DropdownMenuItem<String>( return DropdownMenuItem<String>(
value: region.id, value: region.id,
child: SizedBox( child: SizedBox(
width: size.width*0.06, width: size.width * 0.06,
child: Text(region.name)), child: Text(region.name)),
); );
}).toList(), }).toList(),
@ -183,13 +191,18 @@ class ForgetPasswordWebPage extends StatelessWidget {
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Text( Text(
"Account", "Account",
style: Theme.of(context).textTheme.bodySmall!.copyWith(fontSize: 14,fontWeight: FontWeight.w400), style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
fontSize: 14,
fontWeight: FontWeight.w400),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
SizedBox( SizedBox(
@ -197,22 +210,29 @@ class ForgetPasswordWebPage extends StatelessWidget {
validator: forgetBloc.validateEmail, validator: forgetBloc.validateEmail,
controller: controller:
forgetBloc.forgetEmailController, forgetBloc.forgetEmailController,
decoration: textBoxDecoration()!.copyWith( decoration: textBoxDecoration()!
.copyWith(
hintText: 'Enter your email'), hintText: 'Enter your email'),
style: style: const TextStyle(
const TextStyle(color: Colors.black), color: Colors.black),
), ),
), ),
], ],
), ),
const SizedBox(height: 20.0), const SizedBox(height: 20.0),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Text( Text(
"One Time Password", "One Time Password",
style: Theme.of(context).textTheme.bodySmall!.copyWith(fontSize: 14,fontWeight: FontWeight.w400), style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
fontSize: 14,
fontWeight: FontWeight.w400),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
SizedBox( SizedBox(
@ -221,65 +241,88 @@ class ForgetPasswordWebPage extends StatelessWidget {
keyboardType: keyboardType:
TextInputType.visiblePassword, TextInputType.visiblePassword,
controller: forgetBloc.forgetOtp, controller: forgetBloc.forgetOtp,
decoration: textBoxDecoration()!.copyWith( decoration:
textBoxDecoration()!.copyWith(
hintText: 'Enter Code', hintText: 'Enter Code',
suffixIcon: SizedBox( suffixIcon: SizedBox(
width: 100, width: 100,
child: Center( child: Center(
child: InkWell( child: InkWell(
onTap:state is TimerState && !state.isButtonEnabled && state.remainingTime!=1?null: () { onTap: state is TimerState &&
forgetBloc.add(StartTimerEvent()); !state
.isButtonEnabled &&
state.remainingTime !=
1
? null
: () {
forgetBloc.add(
StartTimerEvent());
}, },
child: Text( child: Text(
'Get Code ${state is TimerState && !state.isButtonEnabled && state.remainingTime!=1? "(${forgetBloc.formattedTime(state.remainingTime)}) " : ""}', 'Get Code ${state is TimerState && !state.isButtonEnabled && state.remainingTime != 1 ? "(${forgetBloc.formattedTime(state.remainingTime)}) " : ""}',
style: TextStyle( style: TextStyle(
color: state is TimerState && color: state
!state.isButtonEnabled is TimerState &&
!state
.isButtonEnabled
? Colors.grey ? Colors.grey
: ColorsManager.btnColor, : ColorsManager
.btnColor,
), ),
), ),
), ),
), ),
), ),
), ),
style: style: const TextStyle(
const TextStyle(color: Colors.black), color: Colors.black),
), ),
), ),
if (forgetBloc.forgetValidate != '') // Check if there is a validation message if (forgetBloc.forgetValidate !=
'') // Check if there is a validation message
Padding( Padding(
padding: const EdgeInsets.only(top: 8.0), padding:
const EdgeInsets.only(top: 8.0),
child: Text( child: Text(
forgetBloc.forgetValidate, forgetBloc.forgetValidate,
style: const TextStyle( style: const TextStyle(
color: ColorsManager.red, color: ColorsManager.red,
fontSize: 10, fontSize: 10,
fontWeight: FontWeight.w700 fontWeight: FontWeight.w700),
),
), ),
), ),
], ],
), ),
const SizedBox(height: 20.0), const SizedBox(height: 20.0),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Text( Text(
"Password", "Password",
style: Theme.of(context).textTheme.bodySmall!.copyWith(fontSize: 14,fontWeight: FontWeight.w400), style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
fontSize: 14,
fontWeight: FontWeight.w400),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
SizedBox( SizedBox(
child: TextFormField( child: TextFormField(
validator: forgetBloc.passwordValidator, validator:
keyboardType: TextInputType.visiblePassword, forgetBloc.passwordValidator,
controller: forgetBloc.forgetPasswordController, keyboardType:
decoration: textBoxDecoration()!.copyWith( TextInputType.visiblePassword,
controller: forgetBloc
.forgetPasswordController,
decoration:
textBoxDecoration()!.copyWith(
hintText: 'At least 8 characters', hintText: 'At least 8 characters',
), ),
style: const TextStyle(color: Colors.black), style: const TextStyle(
color: Colors.black),
), ),
), ),
], ],
@ -289,17 +332,22 @@ class ForgetPasswordWebPage extends StatelessWidget {
), ),
const SizedBox(height: 20.0), const SizedBox(height: 20.0),
Row( Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment:
CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
SizedBox( SizedBox(
width: size.width * 0.2, width: size.width * 0.2,
child: DefaultButton( child: DefaultButton(
backgroundColor: ColorsManager.btnColor, backgroundColor:
ColorsManager.btnColor,
child: const Text('Submit'), child: const Text('Submit'),
onPressed: () { onPressed: () {
if (forgetBloc.forgetFormKey.currentState!.validate()) { if (forgetBloc
forgetBloc.add(ChangePasswordEvent()); .forgetFormKey.currentState!
.validate()) {
forgetBloc
.add(ChangePasswordEvent());
} }
}, },
), ),
@ -321,8 +369,10 @@ class ForgetPasswordWebPage extends StatelessWidget {
SizedBox( SizedBox(
width: size.width * 0.2, width: size.width * 0.2,
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment:
crossAxisAlignment: CrossAxisAlignment.center, MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [ children: [
const Flexible( const Flexible(
child: Text( child: Text(

View File

@ -148,14 +148,14 @@ class LoginMobilePage extends StatelessWidget {
), ),
isDense: true, isDense: true,
style: const TextStyle(color: Colors.black), style: const TextStyle(color: Colors.black),
items:loginBloc.regionList!.map((RegionModel region) { items: loginBloc.regionList!
.map((RegionModel region) {
return DropdownMenuItem<String>( return DropdownMenuItem<String>(
value: region.name, value: region.name,
child: Text(region.name), child: Text(region.name),
); );
}).toList(), }).toList(),
onChanged: (String? value) { onChanged: (String? value) {},
},
), ),
) )
], ],
@ -194,7 +194,8 @@ class LoginMobilePage extends StatelessWidget {
validator: loginBloc.validatePassword, validator: loginBloc.validatePassword,
obscureText: loginBloc.obscureText, obscureText: loginBloc.obscureText,
keyboardType: TextInputType.visiblePassword, keyboardType: TextInputType.visiblePassword,
controller: loginBloc.loginPasswordController, controller:
loginBloc.loginPasswordController,
decoration: textBoxDecoration()!.copyWith( decoration: textBoxDecoration()!.copyWith(
hintText: 'At least 8 characters', hintText: 'At least 8 characters',
), ),
@ -220,7 +221,8 @@ class LoginMobilePage extends StatelessWidget {
}, },
child: Text( child: Text(
"Forgot Password?", "Forgot Password?",
style: Theme.of(context).textTheme.bodySmall, style:
Theme.of(context).textTheme.bodySmall,
), ),
), ),
], ],
@ -295,12 +297,15 @@ class LoginMobilePage extends StatelessWidget {
: ColorsManager.grayColor, : ColorsManager.grayColor,
child: const Text('Sign in'), child: const Text('Sign in'),
onPressed: () { onPressed: () {
if (loginBloc.loginFormKey.currentState!.validate()) { if (loginBloc.loginFormKey.currentState!
.validate()) {
loginBloc.add( loginBloc.add(
LoginButtonPressed( LoginButtonPressed(
regionUuid:'' , regionUuid: '',
username: loginBloc.loginEmailController.text, username:
password: loginBloc.loginPasswordController.text, loginBloc.loginEmailController.text,
password: loginBloc
.loginPasswordController.text,
), ),
); );
} }

View File

@ -9,8 +9,6 @@ class LoginPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return const ResponsiveLayout( return const ResponsiveLayout(
desktopBody: LoginWebPage(), desktopBody: LoginWebPage(), mobileBody: LoginWebPage());
mobileBody:LoginWebPage()
);
} }
} }

View File

@ -24,7 +24,6 @@ class LoginWebPage extends StatefulWidget {
} }
class _LoginWebPageState extends State<LoginWebPage> { class _LoginWebPageState extends State<LoginWebPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -48,26 +47,28 @@ class _LoginWebPageState extends State<LoginWebPage> {
} }
}, },
builder: (context, state) { builder: (context, state) {
return _buildLoginForm(context,state); return _buildLoginForm(context, state);
}, },
), ),
), ),
); );
} }
Widget _buildLoginForm(BuildContext context,AuthState state) { Widget _buildLoginForm(BuildContext context, AuthState state) {
final loginBloc = BlocProvider.of<AuthBloc>(context); final loginBloc = BlocProvider.of<AuthBloc>(context);
Size size = MediaQuery.of(context).size; Size size = MediaQuery.of(context).size;
late ScrollController _scrollController; late ScrollController _scrollController;
_scrollController = ScrollController(); _scrollController = ScrollController();
void _scrollToCenter() { void _scrollToCenter() {
final double middlePosition = _scrollController.position.maxScrollExtent / 2; final double middlePosition =
_scrollController.position.maxScrollExtent / 2;
_scrollController.animateTo( _scrollController.animateTo(
middlePosition, middlePosition,
duration: const Duration(seconds: 1), duration: const Duration(seconds: 1),
curve: Curves.easeInOut, curve: Curves.easeInOut,
); );
} }
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
_scrollToCenter(); _scrollToCenter();
}); });
@ -80,14 +81,14 @@ class _LoginWebPageState extends State<LoginWebPage> {
shrinkWrap: true, shrinkWrap: true,
children: [ children: [
Container( Container(
padding: EdgeInsets.all(size.width*0.02) , padding: EdgeInsets.all(size.width * 0.02),
margin: EdgeInsets.all(size.width*0.09), margin: EdgeInsets.all(size.width * 0.09),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.black.withOpacity(0.3), color: Colors.black.withOpacity(0.3),
borderRadius: const BorderRadius.all(Radius.circular(20)), borderRadius: const BorderRadius.all(Radius.circular(20)),
), ),
child: Center( child: Center(
child:Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
@ -104,89 +105,137 @@ class _LoginWebPageState extends State<LoginWebPage> {
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white.withOpacity(0.1), color: Colors.white.withOpacity(0.1),
borderRadius: const BorderRadius.all(Radius.circular(30)), borderRadius: const BorderRadius.all(
border: Border.all(color: ColorsManager.graysColor.withOpacity(0.2))), Radius.circular(30)),
border: Border.all(
color: ColorsManager.graysColor
.withOpacity(0.2))),
child: Form( child: Form(
key: loginBloc.loginFormKey, key: loginBloc.loginFormKey,
child: Padding( child: Padding(
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
horizontal: size.width*0.02, horizontal: size.width * 0.02,
vertical: size.width*0.003), vertical: size.width * 0.003),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment:
crossAxisAlignment: CrossAxisAlignment.start, MainAxisAlignment.spaceEvenly,
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
const SizedBox(height: 40), const SizedBox(height: 40),
Text( Text('Login',
'Login', style: Theme.of(context)
style:Theme.of(context).textTheme.headlineLarge), .textTheme
SizedBox(height: size.height*0.03), .headlineLarge),
SizedBox(height: size.height * 0.03),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment:
mainAxisAlignment: MainAxisAlignment.start, CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.start,
children: [ children: [
Text( Text(
"Country/Region", "Country/Region",
style: Theme.of(context).textTheme.bodySmall!.copyWith(fontSize: 14,fontWeight: FontWeight.w400), style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
fontSize: 14,
fontWeight:
FontWeight.w400),
),
const SizedBox(
height: 10,
), ),
const SizedBox(height: 10,),
SizedBox( SizedBox(
child: DropdownButtonFormField<String>( child: DropdownButtonFormField<
String>(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
value: loginBloc.regionList!.any((region) => region.id == loginBloc.regionUuid) value: loginBloc.regionList!
.any((region) =>
region.id ==
loginBloc
.regionUuid)
? loginBloc.regionUuid ? loginBloc.regionUuid
: null, : null,
validator:
validator: loginBloc.validateRegion, loginBloc.validateRegion,
icon: const Icon( icon: const Icon(
Icons.keyboard_arrow_down_outlined, Icons
.keyboard_arrow_down_outlined,
), ),
decoration: textBoxDecoration()!.copyWith( decoration: textBoxDecoration()!
errorStyle: const TextStyle(height: 0), .copyWith(
errorStyle: const TextStyle(
height: 0),
hintText: null, hintText: null,
), ),
hint: SizedBox( hint: SizedBox(
width: size.width * 0.12, width: size.width * 0.12,
child: Align( child: Align(
alignment: Alignment.centerLeft, alignment:
Alignment.centerLeft,
child: Text( child: Text(
'Select your region/country', 'Select your region/country',
textAlign: TextAlign.center, textAlign:
style: Theme.of(context).textTheme.bodySmall!.copyWith( TextAlign.center,
color: ColorsManager.grayColor, style: Theme.of(context)
fontWeight: FontWeight.w400), .textTheme
overflow: TextOverflow.ellipsis, .bodySmall!
.copyWith(
color:
ColorsManager
.grayColor,
fontWeight:
FontWeight
.w400),
overflow:
TextOverflow.ellipsis,
), ),
), ),
), ),
isDense: true, isDense: true,
style: const TextStyle(color: Colors.black), style: const TextStyle(
items: loginBloc.regionList!.map((RegionModel region) { color: Colors.black),
return DropdownMenuItem<String>( items: loginBloc.regionList!
.map((RegionModel region) {
return DropdownMenuItem<
String>(
value: region.id, value: region.id,
child: SizedBox( child: SizedBox(
width: size.width*0.08, width:
child: Text(region.name)), size.width * 0.08,
child:
Text(region.name)),
); );
}).toList(), }).toList(),
onChanged: (String? value) { onChanged: (String? value) {
loginBloc.add(CheckEnableEvent()); loginBloc
loginBloc.add(SelectRegionEvent(val: value!)); .add(CheckEnableEvent());
loginBloc.add(
SelectRegionEvent(
val: value!));
}, },
), ),
) )
], ],
), ),
const SizedBox(height: 20.0), const SizedBox(height: 20.0),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment:
mainAxisAlignment: MainAxisAlignment.start, CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.start,
children: [ children: [
Text("Email", Text(
style: Theme.of(context).textTheme.bodySmall!.copyWith(fontSize: 14,fontWeight: FontWeight.w400), "Email",
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
fontSize: 14,
fontWeight:
FontWeight.w400),
), ),
const SizedBox( const SizedBox(
height: 10, height: 10,
@ -194,30 +243,53 @@ class _LoginWebPageState extends State<LoginWebPage> {
SizedBox( SizedBox(
child: TextFormField( child: TextFormField(
onChanged: (value) { onChanged: (value) {
loginBloc.add(CheckEnableEvent()); loginBloc
.add(CheckEnableEvent());
// print(loginBloc.checkEnable()); // print(loginBloc.checkEnable());
}, },
validator:loginBloc.loginValidateEmail , validator: loginBloc
controller:loginBloc.loginEmailController, .loginValidateEmail,
decoration: textBoxDecoration()!.copyWith( controller: loginBloc
errorStyle: const TextStyle(height: 0), // Hide the error text space .loginEmailController,
hintText: 'Enter your email address', decoration: textBoxDecoration()!
hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith( .copyWith(
color: ColorsManager.grayColor, errorStyle: const TextStyle(
fontWeight: FontWeight.w400) height:
), 0), // Hide the error text space
style: const TextStyle(color: Colors.black), hintText:
'Enter your email address',
hintStyle: Theme.of(
context)
.textTheme
.bodySmall!
.copyWith(
color: ColorsManager
.grayColor,
fontWeight:
FontWeight
.w400)),
style: const TextStyle(
color: Colors.black),
), ),
), ),
], ],
), ),
const SizedBox(height: 20.0), const SizedBox(height: 20.0),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment:
mainAxisAlignment: MainAxisAlignment.start, CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.start,
children: [ children: [
Text("Password", Text(
style: Theme.of(context).textTheme.bodySmall!.copyWith(fontSize: 14,fontWeight: FontWeight.w400), "Password",
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
fontSize: 14,
fontWeight:
FontWeight.w400),
), ),
const SizedBox( const SizedBox(
height: 10, height: 10,
@ -225,33 +297,54 @@ class _LoginWebPageState extends State<LoginWebPage> {
SizedBox( SizedBox(
child: TextFormField( child: TextFormField(
onChanged: (value) { onChanged: (value) {
loginBloc.add(CheckEnableEvent()); loginBloc
.add(CheckEnableEvent());
}, },
validator:loginBloc.validatePassword, validator:
obscureText:loginBloc.obscureText, loginBloc.validatePassword,
keyboardType: TextInputType.visiblePassword, obscureText:
controller:loginBloc.loginPasswordController, loginBloc.obscureText,
decoration: textBoxDecoration()!.copyWith( keyboardType: TextInputType
hintText: 'At least 8 characters', .visiblePassword,
hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith( controller: loginBloc
color: ColorsManager.grayColor, .loginPasswordController,
fontWeight: FontWeight.w400), decoration: textBoxDecoration()!
suffixIcon: IconButton(onPressed: () { .copyWith(
loginBloc.add(PasswordVisibleEvent(newValue: loginBloc.obscureText)); hintText:
'At least 8 characters',
hintStyle: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
color: ColorsManager
.grayColor,
fontWeight:
FontWeight.w400),
suffixIcon: IconButton(
onPressed: () {
loginBloc.add(
PasswordVisibleEvent(
newValue: loginBloc
.obscureText));
}, },
icon: SizedBox( icon: SizedBox(
child: SvgPicture.asset( child: SvgPicture.asset(
loginBloc.obscureText? loginBloc.obscureText
Assets.visiblePassword : ? Assets
Assets.invisiblePassword, .visiblePassword
: Assets
.invisiblePassword,
height: 15, height: 15,
width: 15, width: 15,
), ),
), ),
), ),
errorStyle: const TextStyle(height: 0), // Hide the error text space errorStyle: const TextStyle(
height:
0), // Hide the error text space
), ),
style: const TextStyle(color: Colors.black), style: const TextStyle(
color: Colors.black),
), ),
), ),
], ],
@ -261,15 +354,27 @@ class _LoginWebPageState extends State<LoginWebPage> {
), ),
SizedBox( SizedBox(
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment:
MainAxisAlignment.end,
children: [ children: [
InkWell( InkWell(
onTap: () { onTap: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => const ForgetPasswordPage(),)); Navigator.of(context)
.push(MaterialPageRoute(
builder: (context) =>
const ForgetPasswordPage(),
));
}, },
child: Text( child: Text(
"Forgot Password?", "Forgot Password?",
style: Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.black,fontSize: 14,fontWeight: FontWeight.w400), style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
color: Colors.black,
fontSize: 14,
fontWeight:
FontWeight.w400),
), ),
), ),
], ],
@ -281,49 +386,61 @@ class _LoginWebPageState extends State<LoginWebPage> {
Row( Row(
children: [ children: [
Transform.scale( Transform.scale(
scale: 1.2, // Adjust the scale as needed scale:
1.2, // Adjust the scale as needed
child: Checkbox( child: Checkbox(
fillColor: MaterialStateProperty.all<Color>(Colors.white), fillColor: MaterialStateProperty
.all<Color>(Colors.white),
activeColor: Colors.white, activeColor: Colors.white,
value:loginBloc.isChecked, value: loginBloc.isChecked,
checkColor: Colors.black, checkColor: Colors.black,
shape: const CircleBorder(), shape: const CircleBorder(),
onChanged: (bool? newValue) { onChanged: (bool? newValue) {
loginBloc.add(CheckBoxEvent(newValue: newValue)); loginBloc.add(CheckBoxEvent(
newValue: newValue));
}, },
), ),
), ),
SizedBox( SizedBox(
width:size.width * 0.14, width: size.width * 0.14,
child: RichText( child: RichText(
text: TextSpan( text: TextSpan(
text: 'Agree to ', text: 'Agree to ',
style: const TextStyle(color: Colors.white), style: const TextStyle(
color: Colors.white),
children: [ children: [
TextSpan( TextSpan(
text: '(Terms of Service)', text:
'(Terms of Service)',
style: const TextStyle( style: const TextStyle(
color: Colors.black,), color: Colors.black,
recognizer: TapGestureRecognizer() ),
recognizer:
TapGestureRecognizer()
..onTap = () { ..onTap = () {
loginBloc.launchURL( loginBloc.launchURL(
'https://example.com/terms'); 'https://example.com/terms');
}, },
), ),
TextSpan( TextSpan(
text: ' (Legal Statement)', text:
style: const TextStyle(color: Colors.black), ' (Legal Statement)',
recognizer: TapGestureRecognizer() style: const TextStyle(
color: Colors.black),
recognizer:
TapGestureRecognizer()
..onTap = () { ..onTap = () {
loginBloc.launchURL( loginBloc.launchURL(
'https://example.com/legal'); 'https://example.com/legal');
}, },
), ),
TextSpan( TextSpan(
text: ' (Privacy Statement)', text:
' (Privacy Statement)',
style: const TextStyle( style: const TextStyle(
color: Colors.black), color: Colors.black),
recognizer: TapGestureRecognizer() recognizer:
TapGestureRecognizer()
..onTap = () { ..onTap = () {
loginBloc.launchURL( loginBloc.launchURL(
'https://example.com/privacy'); 'https://example.com/privacy');
@ -337,30 +454,49 @@ class _LoginWebPageState extends State<LoginWebPage> {
), ),
const SizedBox(height: 20.0), const SizedBox(height: 20.0),
Row( Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment:
mainAxisAlignment: MainAxisAlignment.center, CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.center,
children: [ children: [
SizedBox( SizedBox(
width:size.width * 0.2, width: size.width * 0.2,
child: DefaultButton( child: DefaultButton(
enabled: loginBloc.checkValidate, enabled:
child:Text('Sign in', loginBloc.checkValidate,
style: Theme.of(context).textTheme.labelLarge !.copyWith( child: Text('Sign in',
style: Theme.of(context)
.textTheme
.labelLarge!
.copyWith(
fontSize: 14, fontSize: 14,
color: color: loginBloc
loginBloc.checkValidate ? .checkValidate
ColorsManager.whiteColors:ColorsManager.whiteColors.withOpacity(0.2), ? ColorsManager
) .whiteColors
), : ColorsManager
.whiteColors
.withOpacity(
0.2),
)),
onPressed: () { onPressed: () {
if(loginBloc.loginFormKey.currentState!.validate() ){ if (loginBloc.loginFormKey
loginBloc.add(LoginButtonPressed( .currentState!
regionUuid:loginBloc.regionUuid, .validate()) {
username: loginBloc.loginEmailController.text, loginBloc
password: loginBloc.loginPasswordController.text, .add(LoginButtonPressed(
regionUuid:
loginBloc.regionUuid,
username: loginBloc
.loginEmailController
.text,
password: loginBloc
.loginPasswordController
.text,
)); ));
}else{ } else {
loginBloc.add(ChangeValidateEvent()); loginBloc.add(
ChangeValidateEvent());
} }
}, },
), ),
@ -369,18 +505,29 @@ class _LoginWebPageState extends State<LoginWebPage> {
), ),
const SizedBox(height: 15.0), const SizedBox(height: 15.0),
Row( Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment:
mainAxisAlignment: MainAxisAlignment.center, CrossAxisAlignment.center,
children: [ SizedBox(child: Text(loginBloc.validate, mainAxisAlignment:
style: const TextStyle(fontWeight: FontWeight.w700,color: ColorsManager.red ),),)],) MainAxisAlignment.center,
], children: [
), SizedBox(
child: Text(
loginBloc.validate,
style: const TextStyle(
fontWeight: FontWeight.w700,
color: ColorsManager.red),
), ),
) )
)), ],
)
],
),
),
))),
const Spacer(), const Spacer(),
], ],
),), ),
),
), ),
], ],
), ),

View File

@ -40,14 +40,12 @@ class DefaultButton extends StatelessWidget {
: customButtonStyle ?? : customButtonStyle ??
ButtonStyle( ButtonStyle(
textStyle: MaterialStateProperty.all( textStyle: MaterialStateProperty.all(
customTextStyle customTextStyle ??
?? Theme.of(context).textTheme.bodySmall!.copyWith( Theme.of(context).textTheme.bodySmall!.copyWith(
fontSize: 13, fontSize: 13,
color: foregroundColor, color: foregroundColor,
fontWeight: FontWeight.normal fontWeight: FontWeight.normal),
), ),
),
foregroundColor: MaterialStateProperty.all( foregroundColor: MaterialStateProperty.all(
isSecondary isSecondary
? Colors.black ? Colors.black

View File

@ -11,7 +11,8 @@ Future<void> showCustomDialog({
double? iconHeight, double? iconHeight,
double? iconWidth, double? iconWidth,
VoidCallback? onOkPressed, VoidCallback? onOkPressed,
bool barrierDismissible = false, required actions, bool barrierDismissible = false,
required actions,
}) { }) {
return showDialog( return showDialog(
context: context, context: context,

View File

@ -224,8 +224,14 @@ class _DynamicTableState extends State<DynamicTable> {
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: Text(
content, content,
style: const TextStyle( style: TextStyle(
color: Colors.black, fontSize: 10, fontWeight: FontWeight.w400), color: content == 'Online'
? ColorsManager.green
: content == 'Offline'
? ColorsManager.red
: Colors.black,
fontSize: 12,
fontWeight: FontWeight.w400),
), ),
), ),
); );

View File

@ -1,7 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/style.dart'; import 'package:syncrow_web/utils/style.dart';
class DateTimeWebWidget extends StatelessWidget { class DateTimeWebWidget extends StatelessWidget {
@ -34,7 +33,7 @@ class DateTimeWebWidget extends StatelessWidget {
children: [ children: [
Row( Row(
children: [ children: [
if(isRequired) if (isRequired)
Text( Text(
'* ', '* ',
style: Theme.of(context) style: Theme.of(context)
@ -42,15 +41,22 @@ class DateTimeWebWidget extends StatelessWidget {
.bodyMedium! .bodyMedium!
.copyWith(color: Colors.red), .copyWith(color: Colors.red),
), ),
Text(title??'' , Text(
style: Theme.of(context).textTheme.bodySmall!.copyWith( title,
color: Colors.black,fontSize: 13),), style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: Colors.black, fontSize: 13),
),
], ],
), ),
const SizedBox(height: 8,), const SizedBox(
height: 8,
),
Container( Container(
height:size.height * 0.055 , height: size.height * 0.055,
padding: EdgeInsets.only(top: 10,bottom: 10,right: 30,left: 10), padding:
const EdgeInsets.only(top: 10, bottom: 10, right: 30, left: 10),
decoration: containerDecoration, decoration: containerDecoration,
child: FittedBox( child: FittedBox(
child: Column( child: Column(
@ -61,25 +67,41 @@ class DateTimeWebWidget extends StatelessWidget {
InkWell( InkWell(
onTap: startTime, onTap: startTime,
child: FittedBox( child: FittedBox(
child: Text(firstString, child: Text(
style: Theme.of(context).textTheme.bodySmall!.copyWith( firstString,
color: ColorsManager.grayColor,fontSize: 12,fontWeight: FontWeight.w400),), style: Theme.of(context)
) .textTheme
), .bodySmall!
SizedBox(width: 30,), .copyWith(
const Icon(Icons.arrow_right_alt), color: ColorsManager.grayColor,
SizedBox(width: 30,), fontSize: 12,
fontWeight: FontWeight.w400),
InkWell(
onTap:endTime,
child: FittedBox(
child: Text(secondString,
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: ColorsManager.grayColor,fontSize: 12,fontWeight: FontWeight.w400),
), ),
)), )),
SizedBox(width: 30,), const SizedBox(
width: 30,
),
const Icon(Icons.arrow_right_alt),
const SizedBox(
width: 30,
),
InkWell(
onTap: endTime,
child: FittedBox(
child: Text(
secondString,
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
color: ColorsManager.grayColor,
fontSize: 12,
fontWeight: FontWeight.w400),
),
)),
const SizedBox(
width: 30,
),
SvgPicture.asset( SvgPicture.asset(
icon, icon,
), ),

View File

@ -4,7 +4,7 @@ import 'package:syncrow_web/utils/constants/assets.dart';
class FirstLayer extends StatelessWidget { class FirstLayer extends StatelessWidget {
final Widget? second; final Widget? second;
const FirstLayer({super.key,this.second}); const FirstLayer({super.key, this.second});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View File

@ -1,5 +1,3 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class HourPickerDialog extends StatefulWidget { class HourPickerDialog extends StatefulWidget {
@ -17,7 +15,9 @@ class _HourPickerDialogState extends State<HourPickerDialog> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_selectedHour = widget.initialTime.hour > 12 ? widget.initialTime.hour - 12 : widget.initialTime.hour; _selectedHour = widget.initialTime.hour > 12
? widget.initialTime.hour - 12
: widget.initialTime.hour;
_isPm = widget.initialTime.period == DayPeriod.pm; _isPm = widget.initialTime.period == DayPeriod.pm;
} }

View File

@ -35,7 +35,6 @@ class InfoDialog extends StatelessWidget {
width: 35, width: 35,
), ),
), ),
Text( Text(
title, title,
style: Theme.of(context).textTheme.headlineLarge!.copyWith( style: Theme.of(context).textTheme.headlineLarge!.copyWith(

View File

@ -8,37 +8,25 @@ class StatefulTextField extends StatefulWidget {
this.hintText = 'Please enter', this.hintText = 'Please enter',
required this.width, required this.width,
this.elevation = 0, this.elevation = 0,
required this.controller, // Add the controller
}); });
final String title; final String title;
final String hintText; final String hintText;
final double width; final double width;
final double elevation; final double elevation;
final TextEditingController controller;
@override @override
State<StatefulTextField> createState() => _StatefulTextFieldState(); State<StatefulTextField> createState() => _StatefulTextFieldState();
} }
class _StatefulTextFieldState extends State<StatefulTextField> { class _StatefulTextFieldState extends State<StatefulTextField> {
late TextEditingController _controller;
@override
void initState() {
super.initState();
_controller = TextEditingController();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return CustomTextField( return CustomTextField(
title: widget.title, title: widget.title,
controller: _controller, controller: widget.controller,
hintText: widget.hintText, hintText: widget.hintText,
width: widget.width, width: widget.width,
elevation: widget.elevation, elevation: widget.elevation,

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/style.dart'; import 'package:syncrow_web/utils/style.dart';
class CustomWebTextField extends StatelessWidget { class CustomWebTextField extends StatelessWidget {
const CustomWebTextField({ const CustomWebTextField({
super.key, super.key,
@ -18,7 +18,6 @@ class CustomWebTextField extends StatelessWidget {
final TextEditingController? controller; final TextEditingController? controller;
final String? Function(String?)? validator; final String? Function(String?)? validator;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return Column(
@ -28,51 +27,59 @@ class CustomWebTextField extends StatelessWidget {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
if(isRequired) if (isRequired)
Row( Row(
children: [ children: [
Text('* ', Text(
'* ',
style: Theme.of(context) style: Theme.of(context)
.textTheme.bodyMedium! .textTheme
.bodyMedium!
.copyWith(color: Colors.red), .copyWith(color: Colors.red),
), ),
Text(textFieldName, style: Theme.of(context).textTheme.bodySmall!.copyWith( Text(
color: Colors.black,fontSize: 13),), textFieldName,
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: Colors.black, fontSize: 13),
),
], ],
), ),
const SizedBox(width: 10,), const SizedBox(
width: 10,
),
Expanded( Expanded(
child: Text( child: Text(
description??'', description ?? '',
style: Theme.of(context) style: Theme.of(context).textTheme.bodySmall!.copyWith(
.textTheme.bodySmall! fontSize: 9,
.copyWith(fontSize: 9,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
color: ColorsManager.textGray), color: ColorsManager.textGray),
), ),
), ),
], ],
), ),
const SizedBox(height: 7,), const SizedBox(
height: 7,
),
Container( Container(
decoration: containerDecoration.copyWith( decoration: containerDecoration
color: const Color(0xFFF5F6F7), .copyWith(color: const Color(0xFFF5F6F7), boxShadow: [
boxShadow: [
BoxShadow( BoxShadow(
color: Colors.grey.withOpacity(0.3), color: Colors.grey.withOpacity(0.3),
spreadRadius:2, spreadRadius: 2,
blurRadius: 3, blurRadius: 3,
offset: const Offset(1, 1), // changes position of shadow offset: const Offset(1, 1), // changes position of shadow
), ),
] ]),
),
child: TextFormField( child: TextFormField(
validator: validator, validator: validator,
controller: controller, controller: controller,
style: const TextStyle(color: Colors.black), style: const TextStyle(color: Colors.black),
decoration: textBoxDecoration()! decoration: textBoxDecoration()!.copyWith(
.copyWith( errorStyle:
errorStyle: const TextStyle(height: 0), // Hide the error text space const TextStyle(height: 0), // Hide the error text space
hintText: 'Please enter'), hintText: 'Please enter'),
), ),

View File

@ -1,13 +1,130 @@
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:syncrow_web/pages/device_managment/models/devices_model.dart';
import 'package:syncrow_web/services/devices_mang_api.dart';
part 'device_managment_event.dart'; part 'device_managment_event.dart';
part 'device_managment_state.dart'; part 'device_managment_state.dart';
class DeviceManagmentBloc extends Bloc<DeviceManagmentEvent, DeviceManagmentState> { class DeviceManagementBloc
DeviceManagmentBloc() : super(DeviceManagmentInitial()) { extends Bloc<DeviceManagementEvent, DeviceManagementState> {
on<DeviceManagmentEvent>((event, emit) { int _selectedIndex = 0;
// TODO: implement event handler List<AllDevicesModel> _devices = [];
}); int _onlineCount = 0;
int _offlineCount = 0;
int _lowBatteryCount = 0;
DeviceManagementBloc() : super(DeviceManagementInitial()) {
on<FetchDevices>(_onFetchDevices);
on<FilterDevices>(_onFilterDevices);
on<SelectedFilterChanged>(_onSelectedFilterChanged);
on<SearchDevices>(_onSearchDevices);
}
Future<void> _onFetchDevices(
FetchDevices event, Emitter<DeviceManagementState> emit) async {
emit(DeviceManagementLoading());
try {
final devices = await DevicesManagementApi().fetchDevices();
_devices = devices;
_calculateDeviceCounts();
emit(DeviceManagementLoaded(
devices: devices,
selectedIndex: _selectedIndex,
onlineCount: _onlineCount,
offlineCount: _offlineCount,
lowBatteryCount: _lowBatteryCount,
));
} catch (e) {
emit(DeviceManagementInitial());
}
}
void _onFilterDevices(
FilterDevices event, Emitter<DeviceManagementState> emit) {
if (_devices.isNotEmpty) {
final filteredDevices = _devices.where((device) {
switch (event.filter) {
case 'Online':
return device.online == true;
case 'Offline':
return device.online == false;
case 'Low Battery':
return device.batteryLevel != null && device.batteryLevel! < 20;
default:
return true;
}
}).toList();
emit(DeviceManagementFiltered(
filteredDevices: filteredDevices,
selectedIndex: _selectedIndex,
onlineCount: _onlineCount,
offlineCount: _offlineCount,
lowBatteryCount: _lowBatteryCount,
));
}
}
void _onSelectedFilterChanged(
SelectedFilterChanged event, Emitter<DeviceManagementState> emit) {
_selectedIndex = event.selectedIndex;
add(FilterDevices(_getFilterFromIndex(_selectedIndex)));
}
void _calculateDeviceCounts() {
_onlineCount = _devices.where((device) => device.online == true).length;
_offlineCount = _devices.where((device) => device.online == false).length;
_lowBatteryCount = _devices
.where((device) =>
device.batteryLevel != null && device.batteryLevel! < 20)
.length;
}
String _getFilterFromIndex(int index) {
switch (index) {
case 1:
return 'Online';
case 2:
return 'Offline';
case 3:
return 'Low Battery';
default:
return 'All';
}
}
void _onSearchDevices(
SearchDevices event, Emitter<DeviceManagementState> emit) {
if (_devices.isNotEmpty) {
final filteredDevices = _devices.where((device) {
final matchesCommunity = event.community == null ||
event.community!.isEmpty ||
(device.room?.name
?.toLowerCase()
.contains(event.community!.toLowerCase()) ??
false);
final matchesUnit = event.unitName == null ||
event.unitName!.isEmpty ||
(device.unit?.name
?.toLowerCase()
.contains(event.unitName!.toLowerCase()) ??
false);
final matchesProductName = event.productName == null ||
event.productName!.isEmpty ||
(device.name
?.toLowerCase()
.contains(event.productName!.toLowerCase()) ??
false);
return matchesCommunity && matchesUnit && matchesProductName;
}).toList();
emit(DeviceManagementFiltered(
filteredDevices: filteredDevices,
selectedIndex: _selectedIndex,
onlineCount: _onlineCount,
offlineCount: _offlineCount,
lowBatteryCount: _lowBatteryCount,
));
}
} }
} }

View File

@ -1,8 +1,43 @@
part of 'device_managment_bloc.dart'; part of 'device_managment_bloc.dart';
sealed class DeviceManagmentEvent extends Equatable { abstract class DeviceManagementEvent extends Equatable {
const DeviceManagmentEvent(); const DeviceManagementEvent();
@override @override
List<Object> get props => []; List<Object?> get props => [];
}
class FetchDevices extends DeviceManagementEvent {}
class FilterDevices extends DeviceManagementEvent {
final String filter;
const FilterDevices(this.filter);
@override
List<Object?> get props => [filter];
}
class SelectedFilterChanged extends DeviceManagementEvent {
final int selectedIndex;
const SelectedFilterChanged(this.selectedIndex);
@override
List<Object?> get props => [selectedIndex];
}
class SearchDevices extends DeviceManagementEvent {
final String? community;
final String? unitName;
final String? productName;
const SearchDevices({
this.community,
this.unitName,
this.productName,
});
@override
List<Object?> get props => [community, unitName, productName];
} }

View File

@ -1,10 +1,57 @@
part of 'device_managment_bloc.dart'; part of 'device_managment_bloc.dart';
sealed class DeviceManagmentState extends Equatable { abstract class DeviceManagementState extends Equatable {
const DeviceManagmentState(); const DeviceManagementState();
@override @override
List<Object> get props => []; List<Object?> get props => [];
} }
final class DeviceManagmentInitial extends DeviceManagmentState {} class DeviceManagementInitial extends DeviceManagementState {}
class DeviceManagementLoading extends DeviceManagementState {}
class DeviceManagementLoaded extends DeviceManagementState {
final List<AllDevicesModel> devices;
final int selectedIndex;
final int onlineCount;
final int offlineCount;
final int lowBatteryCount;
const DeviceManagementLoaded({
required this.devices,
required this.selectedIndex,
required this.onlineCount,
required this.offlineCount,
required this.lowBatteryCount,
});
@override
List<Object?> get props =>
[devices, selectedIndex, onlineCount, offlineCount, lowBatteryCount];
}
class DeviceManagementFiltered extends DeviceManagementState {
final List<AllDevicesModel> filteredDevices;
final int selectedIndex;
final int onlineCount;
final int offlineCount;
final int lowBatteryCount;
const DeviceManagementFiltered({
required this.filteredDevices,
required this.selectedIndex,
required this.onlineCount,
required this.offlineCount,
required this.lowBatteryCount,
});
@override
List<Object?> get props => [
filteredDevices,
selectedIndex,
onlineCount,
offlineCount,
lowBatteryCount
];
}

View File

@ -0,0 +1,157 @@
import 'package:syncrow_web/pages/device_managment/models/room.dart';
import 'package:syncrow_web/pages/device_managment/models/unit.dart';
class AllDevicesModel {
/*
{
"room": {
"uuid": "75ea7d60-5104-4726-b5f8-ea426c0c6a1b",
"name": "Room 1"
},
"unit": {
"uuid": "04fd1dcf-f24a-40db-970d-d0be884ed30f",
"name": "unit 1"
},
"productUuid": "894aad5c-ce03-423a-9d61-2fd0c3f67ebf",
"productType": "3G",
"permissionType": "CONTROLLABLE",
"activeTime": 1722173778,
"category": "kg",
"categoryName": "Switch",
"createTime": 1722173778,
"gatewayId": "bf0294123ed2c19067skrk",
"icon": "smart/icon/bay1642572935385vcsA/2b1f5efbaa5bbf81c3164fa312cf2032.png",
"ip": "",
"lat": "31.97",
"localKey": "T/39+<l/![iv>:9M",
"lon": "35.89",
"model": "S01ZLSWBSA3",
"name": "3 Gang Button Switch L-L",
"nodeId": "60a423fffed5a7f6",
"online": true,
"ownerId": "199200732",
"sub": true,
"timeZone": "+03:00",
"updateTime": 1723626515,
"uuid": "5b31dae4-ce9c-4c70-b52b-7e15011163bf"
}
*/
DevicesModelRoom? room;
DevicesModelUnit? unit;
String? productUuid;
String? productType;
String? permissionType;
int? activeTime;
String? category;
String? categoryName;
int? createTime;
String? gatewayId;
String? icon;
String? ip;
String? lat;
String? localKey;
String? lon;
String? model;
String? name;
String? nodeId;
bool? online;
String? ownerId;
bool? sub;
String? timeZone;
int? updateTime;
String? uuid;
int? batteryLevel;
AllDevicesModel({
this.room,
this.unit,
this.productUuid,
this.productType,
this.permissionType,
this.activeTime,
this.category,
this.categoryName,
this.createTime,
this.gatewayId,
this.icon,
this.ip,
this.lat,
this.localKey,
this.lon,
this.model,
this.name,
this.nodeId,
this.online,
this.ownerId,
this.sub,
this.timeZone,
this.updateTime,
this.uuid,
this.batteryLevel,
});
AllDevicesModel.fromJson(Map<String, dynamic> json) {
room = (json['room'] != null && (json['room'] is Map))
? DevicesModelRoom.fromJson(json['room'])
: null;
unit = (json['unit'] != null && (json['unit'] is Map))
? DevicesModelUnit.fromJson(json['unit'])
: null;
productUuid = json['productUuid']?.toString();
productType = json['productType']?.toString();
permissionType = json['permissionType']?.toString();
activeTime = int.tryParse(json['activeTime']?.toString() ?? '');
category = json['category']?.toString();
categoryName = json['categoryName']?.toString();
createTime = int.tryParse(json['createTime']?.toString() ?? '');
gatewayId = json['gatewayId']?.toString();
icon = json['icon']?.toString();
ip = json['ip']?.toString();
lat = json['lat']?.toString();
localKey = json['localKey']?.toString();
lon = json['lon']?.toString();
model = json['model']?.toString();
name = json['name']?.toString();
nodeId = json['nodeId']?.toString();
online = json['online'];
ownerId = json['ownerId']?.toString();
sub = json['sub'];
timeZone = json['timeZone']?.toString();
updateTime = int.tryParse(json['updateTime']?.toString() ?? '');
uuid = json['uuid']?.toString();
batteryLevel = int.tryParse(json['batteryLevel']?.toString() ?? '');
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
if (room != null) {
data['room'] = room!.toJson();
}
if (unit != null) {
data['unit'] = unit!.toJson();
}
data['productUuid'] = productUuid;
data['productType'] = productType;
data['permissionType'] = permissionType;
data['activeTime'] = activeTime;
data['category'] = category;
data['categoryName'] = categoryName;
data['createTime'] = createTime;
data['gatewayId'] = gatewayId;
data['icon'] = icon;
data['ip'] = ip;
data['lat'] = lat;
data['localKey'] = localKey;
data['lon'] = lon;
data['model'] = model;
data['name'] = name;
data['nodeId'] = nodeId;
data['online'] = online;
data['ownerId'] = ownerId;
data['sub'] = sub;
data['timeZone'] = timeZone;
data['updateTime'] = updateTime;
data['uuid'] = uuid;
data['batteryLevel'] = batteryLevel;
return data;
}
}

View File

@ -0,0 +1,26 @@
class DevicesModelRoom {
/*
{
"uuid": "75ea7d60-5104-4726-b5f8-ea426c0c6a1b",
"name": "Room 1"
}
*/
String? uuid;
String? name;
DevicesModelRoom({
this.uuid,
this.name,
});
DevicesModelRoom.fromJson(Map<String, dynamic> json) {
uuid = json['uuid']?.toString();
name = json['name']?.toString();
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['uuid'] = uuid;
data['name'] = name;
return data;
}
}

View File

@ -0,0 +1,26 @@
class DevicesModelUnit {
/*
{
"uuid": "04fd1dcf-f24a-40db-970d-d0be884ed30f",
"name": "unit 1"
}
*/
String? uuid;
String? name;
DevicesModelUnit({
this.uuid,
this.name,
});
DevicesModelUnit.fromJson(Map<String, dynamic> json) {
uuid = json['uuid']?.toString();
name = json['name']?.toString();
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['uuid'] = uuid;
data['name'] = name;
return data;
}
}

View File

@ -1,4 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/bloc/device_managment_bloc.dart';
import 'package:syncrow_web/pages/device_managment/widgets/device_managment_body.dart'; import 'package:syncrow_web/pages/device_managment/widgets/device_managment_body.dart';
import 'package:syncrow_web/web_layout/web_scaffold.dart'; import 'package:syncrow_web/web_layout/web_scaffold.dart';
@ -7,17 +9,31 @@ class DeviceManagementPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return WebScaffold( return BlocProvider(
enableMenuSideba: true, create: (context) => DeviceManagementBloc()..add(FetchDevices()),
appBarTitle: Row( child: WebScaffold(
children: [ appBarTitle: Text(
Text(
'Device Management', 'Device Management',
style: Theme.of(context).textTheme.headlineLarge, style: Theme.of(context).textTheme.headlineLarge,
)
],
), ),
scaffoldBody: const DeviceManagementBody(), enableMenuSideba: true,
scaffoldBody: BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
builder: (context, state) {
if (state is DeviceManagementLoading) {
return const Center(child: CircularProgressIndicator());
} else if (state is DeviceManagementLoaded ||
state is DeviceManagementFiltered) {
final devices = state is DeviceManagementLoaded
? state.devices
: (state as DeviceManagementFiltered).filteredDevices;
return DeviceManagementBody(devices: devices);
} else {
return const Center(child: Text('No Devices Found'));
}
},
),
),
); );
} }
} }

View File

@ -1,17 +1,53 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/core/extension/build_context_x.dart'; import 'package:syncrow_web/core/extension/build_context_x.dart';
import 'package:syncrow_web/pages/common/buttons/search_reset_buttons.dart'; import 'package:syncrow_web/pages/common/buttons/default_button.dart';
import 'package:syncrow_web/pages/common/custom_table.dart'; import 'package:syncrow_web/pages/common/custom_table.dart';
import 'package:syncrow_web/pages/common/filter/filter_widget.dart'; import 'package:syncrow_web/pages/common/filter/filter_widget.dart';
import 'package:syncrow_web/pages/common/text_field/custom_text_field.dart'; import 'package:syncrow_web/pages/device_managment/bloc/device_managment_bloc.dart';
import 'package:syncrow_web/pages/device_managment/models/devices_model.dart';
import 'package:syncrow_web/pages/device_managment/widgets/device_search_filters.dart';
import 'package:syncrow_web/utils/format_date_time.dart';
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
import 'package:syncrow_web/utils/style.dart'; import 'package:syncrow_web/utils/style.dart';
class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
const DeviceManagementBody({super.key}); const DeviceManagementBody({super.key, required this.devices});
final List<AllDevicesModel> devices;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
builder: (context, state) {
List<AllDevicesModel> devicesToShow = [];
int selectedIndex = 0;
int onlineCount = 0;
int offlineCount = 0;
int lowBatteryCount = 0;
if (state is DeviceManagementLoaded) {
devicesToShow = state.devices;
selectedIndex = state.selectedIndex;
onlineCount = state.onlineCount;
offlineCount = state.offlineCount;
lowBatteryCount = state.lowBatteryCount;
} else if (state is DeviceManagementFiltered) {
devicesToShow = state.filteredDevices;
selectedIndex = state.selectedIndex;
onlineCount = state.onlineCount;
offlineCount = state.offlineCount;
lowBatteryCount = state.lowBatteryCount;
}
// Create tab labels with counts
final tabs = [
'All (${devices.length})',
'Online ($onlineCount)',
'Offline ($offlineCount)',
'Low Battery ($lowBatteryCount)',
];
return Container( return Container(
padding: const EdgeInsets.all(30), padding: const EdgeInsets.all(30),
height: context.screenHeight, height: context.screenHeight,
@ -20,68 +56,34 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
FilterWidget( FilterWidget(
size: context.screenSize, size: MediaQuery.of(context).size,
tabs: ['All', 'Online', 'Offline', 'Low Battery'], tabs: tabs,
selectedIndex: 0, selectedIndex: selectedIndex,
onTabChanged: (index) {}, onTabChanged: (index) {
context
.read<DeviceManagementBloc>()
.add(SelectedFilterChanged(index));
},
), ),
const SizedBox( const SizedBox(
height: 20, height: 20,
), ),
if (isLargeScreenSize(context)) ...[ const DeviceSearchFilters(),
Row( const SizedBox(
children: [ height: 12,
const StatefulTextField(
title: "Community",
width: 200,
elevation: 2,
), ),
const SizedBox(width: 20), Container(
const StatefulTextField( height: 43,
title: "Unit Name", width: 100,
width: 200, decoration: containerDecoration,
elevation: 2, child: Center(
child: DefaultButton(
onPressed: () {},
borderRadius: 9,
child: const Text('Control'),
), ),
const SizedBox(width: 20),
const StatefulTextField(
title: "Device Name / Product Name",
width: 300,
elevation: 2,
), ),
const SizedBox(width: 20),
SearchResetButtons(
onSearch: () {},
onReset: () {},
), ),
],
),
] else ...[
Wrap(
spacing: 20,
runSpacing: 10,
children: [
const StatefulTextField(
title: "Community",
width: 200,
elevation: 2,
),
const StatefulTextField(
title: "Unit Name",
width: 200,
elevation: 2,
),
const StatefulTextField(
title: "Device Name / Product Name",
width: 300,
elevation: 2,
),
SearchResetButtons(
onSearch: () {},
onReset: () {},
),
],
),
],
const SizedBox( const SizedBox(
height: 12, height: 12,
), ),
@ -111,19 +113,28 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
'Status', 'Status',
'Last Offline Date and Time', 'Last Offline Date and Time',
], ],
data: [] data: devicesToShow.map((device) {
// state.data.map((item) { return [
// return [ device.categoryName ?? '',
// item.name.toString(), device.name ?? '',
// item.uuid.toString(), device.uuid ?? '',
// item.productType.toString(), device.unit?.name ?? '',
// '', device.room?.name ?? '',
// item.online.value.toString(), device.batteryLevel?.toString() ?? '',
// ]; formatDateTime(DateTime.fromMillisecondsSinceEpoch(
// }).toList(), device.createTime ?? 0)),
)), device.online == true ? 'Online' : 'Offline',
formatDateTime(DateTime.fromMillisecondsSinceEpoch(
device.updateTime ?? 0)),
];
}).toList(),
isEmpty: devicesToShow.isEmpty,
),
),
], ],
), ),
); );
},
);
} }
} }

View File

@ -0,0 +1,84 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/text_field/custom_text_field.dart';
import 'package:syncrow_web/pages/device_managment/bloc/device_managment_bloc.dart';
import 'package:syncrow_web/pages/common/buttons/search_reset_buttons.dart';
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
class DeviceSearchFilters extends StatefulWidget {
const DeviceSearchFilters({super.key});
@override
State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState();
}
class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
with HelperResponsiveLayout {
final TextEditingController communityController = TextEditingController();
final TextEditingController unitNameController = TextEditingController();
final TextEditingController productNameController = TextEditingController();
@override
void dispose() {
communityController.dispose();
unitNameController.dispose();
productNameController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return isLargeScreenSize(context)
? Row(
children: [
_buildSearchField("Community", communityController, 200),
const SizedBox(width: 20),
_buildSearchField("Unit Name", unitNameController, 200),
const SizedBox(width: 20),
_buildSearchField(
"Device Name / Product Name", productNameController, 300),
const SizedBox(width: 20),
_buildSearchResetButtons(),
],
)
: Wrap(
spacing: 20,
runSpacing: 10,
children: [
_buildSearchField("Community", communityController, 200),
_buildSearchField("Unit Name", unitNameController, 200),
_buildSearchField(
"Device Name / Product Name", productNameController, 300),
_buildSearchResetButtons(),
],
);
}
Widget _buildSearchField(
String title, TextEditingController controller, double width) {
return StatefulTextField(
title: title,
width: width,
elevation: 2,
controller: controller,
);
}
Widget _buildSearchResetButtons() {
return SearchResetButtons(
onSearch: () {
context.read<DeviceManagementBloc>().add(SearchDevices(
community: communityController.text,
unitName: unitNameController.text,
productName: productNameController.text,
));
},
onReset: () {
communityController.clear();
unitNameController.clear();
productNameController.clear();
context.read<DeviceManagementBloc>().add(FetchDevices());
},
);
}
}

View File

@ -25,6 +25,7 @@ class HomeUpdateTree extends HomeState {
@override @override
List<Object> get props => [graph, builder]; List<Object> get props => [graph, builder];
} }
class HomeUserInfoLoaded extends HomeState { class HomeUserInfoLoaded extends HomeState {
final UserModel user; final UserModel user;

View File

@ -1,7 +1,3 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
class HomeItemModel { class HomeItemModel {
@ -11,7 +7,6 @@ class HomeItemModel {
final bool? active; final bool? active;
final void Function(BuildContext context) onPress; final void Function(BuildContext context) onPress;
HomeItemModel({ HomeItemModel({
this.title, this.title,
this.icon, this.icon,

View File

@ -22,11 +22,12 @@ class HomeCard extends StatelessWidget {
return InkWell( return InkWell(
onTap: active ? onTap : null, onTap: active ? onTap : null,
child: Container( child: Container(
padding: const EdgeInsets.only(left: 10,right: 10,bottom: 10), padding: const EdgeInsets.only(left: 10, right: 10, bottom: 10),
decoration: BoxDecoration( decoration: BoxDecoration(
color: evenNumbers && active? color: evenNumbers && active
ColorsManager.blueColor.withOpacity(0.8) : ? ColorsManager.blueColor.withOpacity(0.8)
(active ?ColorsManager.blueColor : (active
? ColorsManager.blueColor
: ColorsManager.blueColor.withOpacity(0.2)), : ColorsManager.blueColor.withOpacity(0.2)),
borderRadius: BorderRadius.circular(30), borderRadius: BorderRadius.circular(30),
), ),

View File

@ -9,8 +9,6 @@ class HomePage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ResponsiveLayout( return ResponsiveLayout(
desktopBody: HomeWebPage(), desktopBody: HomeWebPage(), mobileBody: HomeMobilePage());
mobileBody:HomeMobilePage()
);
} }
} }

View File

@ -44,7 +44,8 @@ class HomeMobilePage extends StatelessWidget {
width: size.width * 0.68, width: size.width * 0.68,
child: GridView.builder( child: GridView.builder(
itemCount: 8, itemCount: 8,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, crossAxisCount: 2,
crossAxisSpacing: 20.0, crossAxisSpacing: 20.0,
mainAxisSpacing: 20.0, mainAxisSpacing: 20.0,

View File

@ -39,7 +39,8 @@ class HomeWebPage extends StatelessWidget {
Text( Text(
'ACCESS YOUR APPS', 'ACCESS YOUR APPS',
style: Theme.of(context) style: Theme.of(context)
.textTheme.headlineLarge! .textTheme
.headlineLarge!
.copyWith(color: Colors.black, fontSize: 40), .copyWith(color: Colors.black, fontSize: 40),
), ),
const SizedBox(height: 30), const SizedBox(height: 30),
@ -63,7 +64,8 @@ class HomeWebPage extends StatelessWidget {
active: homeBloc.homeItems[index].active!, active: homeBloc.homeItems[index].active!,
name: homeBloc.homeItems[index].title!, name: homeBloc.homeItems[index].title!,
img: homeBloc.homeItems[index].icon!, img: homeBloc.homeItems[index].icon!,
onTap: () => homeBloc.homeItems[index].onPress(context), onTap: () =>
homeBloc.homeItems[index].onPress(context),
); );
}, },
), ),

View File

@ -32,8 +32,8 @@ class TreeWidget extends StatelessWidget {
SizedBox( SizedBox(
width: 100, width: 100,
child: TextFormField( child: TextFormField(
decoration: decoration: const InputDecoration(
const InputDecoration(labelText: "Subtree separation"), labelText: "Subtree separation"),
onChanged: (text) { onChanged: (text) {
firstNodeName = text; firstNodeName = text;
}, },
@ -73,9 +73,7 @@ class TreeWidget extends StatelessWidget {
child: GraphView( child: GraphView(
graph: state.graph, graph: state.graph,
algorithm: BuchheimWalkerAlgorithm( algorithm: BuchheimWalkerAlgorithm(
state.builder, state.builder, TreeEdgeRenderer(state.builder)),
TreeEdgeRenderer(state.builder)
),
paint: Paint() paint: Paint()
..color = Colors.green ..color = Colors.green
..strokeWidth = 1 ..strokeWidth = 1
@ -138,7 +136,7 @@ Widget rectangleWidget(String text, Node node, BuildContext blocContext) {
); );
}, },
child: Container( child: Container(
width: MediaQuery.of(blocContext).size.width*0.2, width: MediaQuery.of(blocContext).size.width * 0.2,
margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0), margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
padding: EdgeInsets.all(20.0), padding: EdgeInsets.all(20.0),
decoration: BoxDecoration( decoration: BoxDecoration(

View File

@ -220,7 +220,6 @@ class VisitorPasswordBloc
} }
} }
Future<void> postOnlineMultipleTimePassword( Future<void> postOnlineMultipleTimePassword(
OnlineMultipleTimePasswordEvent event, OnlineMultipleTimePasswordEvent event,
Emitter<VisitorPasswordState> emit) async { Emitter<VisitorPasswordState> emit) async {
@ -246,11 +245,10 @@ class VisitorPasswordBloc
passwordName: event.passwordName); passwordName: event.passwordName);
if (res == true) { if (res == true) {
emit(SuccessState()); emit(SuccessState());
}else { } else {
throw Exception('Failed to create password'); throw Exception('Failed to create password');
} }
emit(TableLoaded(data)); emit(TableLoaded(data));
} catch (e) { } catch (e) {
emit(FailedState(e.toString())); emit(FailedState(e.toString()));
Navigator.pop(event.context!); Navigator.pop(event.context!);
@ -273,11 +271,10 @@ class VisitorPasswordBloc
passwordName: event.passwordName); passwordName: event.passwordName);
if (res == true) { if (res == true) {
emit(SuccessState()); emit(SuccessState());
}else { } else {
throw Exception('Failed to create password'); throw Exception('Failed to create password');
} }
emit(TableLoaded(data)); emit(TableLoaded(data));
} catch (e) { } catch (e) {
emit(FailedState(e.toString())); emit(FailedState(e.toString()));
Navigator.pop(event.context!); Navigator.pop(event.context!);
@ -303,18 +300,18 @@ class VisitorPasswordBloc
); );
if (res == true) { if (res == true) {
emit(SuccessState()); emit(SuccessState());
}else { } else {
throw Exception('Failed to create password'); throw Exception('Failed to create password');
} }
emit(TableLoaded(data)); emit(TableLoaded(data));
} catch (e) { } catch (e) {
emit(FailedState(e.toString())); emit(FailedState(e.toString()));
Navigator.pop(event.context!); Navigator.pop(event.context!);
stateDialog( stateDialog(
context: event.context!, context: event.context!,
message: e.toString(), message: e.toString(),
title: 'Something Wrong'); } title: 'Something Wrong');
}
} }
void selectDevice( void selectDevice(

View File

@ -26,19 +26,19 @@ class SelectUsageFrequency extends VisitorPasswordEvent {
@override @override
List<Object> get props => [usageType]; List<Object> get props => [usageType];
} }
class SelectTimeVisitorPassword extends VisitorPasswordEvent { class SelectTimeVisitorPassword extends VisitorPasswordEvent {
final BuildContext context; final BuildContext context;
final bool isStart; final bool isStart;
final bool isRepeat; final bool isRepeat;
const SelectTimeVisitorPassword({ required this.context,required this.isStart,required this.isRepeat}); const SelectTimeVisitorPassword(
{required this.context, required this.isStart, required this.isRepeat});
@override @override
List<Object> get props => [context,isStart,isRepeat]; List<Object> get props => [context, isStart, isRepeat];
} }
class ToggleDaySelectionEvent extends VisitorPasswordEvent { class ToggleDaySelectionEvent extends VisitorPasswordEvent {
final String key; final String key;
@ -47,12 +47,11 @@ class ToggleDaySelectionEvent extends VisitorPasswordEvent {
List<Object> get props => [key]; List<Object> get props => [key];
} }
class ToggleRepeatEvent extends VisitorPasswordEvent {} class ToggleRepeatEvent extends VisitorPasswordEvent {}
class GeneratePasswordEvent extends VisitorPasswordEvent {} class GeneratePasswordEvent extends VisitorPasswordEvent {}
class FetchDevice extends VisitorPasswordEvent { class FetchDevice extends VisitorPasswordEvent {}
}
//online password //online password
class OnlineOneTimePasswordEvent extends VisitorPasswordEvent { class OnlineOneTimePasswordEvent extends VisitorPasswordEvent {
@ -60,20 +59,31 @@ class OnlineOneTimePasswordEvent extends VisitorPasswordEvent {
final String? passwordName; final String? passwordName;
final BuildContext? context; final BuildContext? context;
const OnlineOneTimePasswordEvent({this.email,this.passwordName,this.context}); const OnlineOneTimePasswordEvent(
{this.email, this.passwordName, this.context});
@override @override
List<Object> get props => [email!,passwordName!,]; List<Object> get props => [
email!,
passwordName!,
];
} }
class OnlineMultipleTimePasswordEvent extends VisitorPasswordEvent { class OnlineMultipleTimePasswordEvent extends VisitorPasswordEvent {
final String? email; final String? email;
final String? passwordName; final String? passwordName;
final String? invalidTime; final String? invalidTime;
final String? effectiveTime; final String? effectiveTime;
final BuildContext? context; final BuildContext? context;
const OnlineMultipleTimePasswordEvent({this.email,this.passwordName,this.invalidTime,this.effectiveTime,this.context}); const OnlineMultipleTimePasswordEvent(
{this.email,
this.passwordName,
this.invalidTime,
this.effectiveTime,
this.context});
@override @override
List<Object> get props => [email!,passwordName!,invalidTime!,effectiveTime!,context!]; List<Object> get props =>
[email!, passwordName!, invalidTime!, effectiveTime!, context!];
} }
//offline password //offline password
@ -81,9 +91,14 @@ class OfflineOneTimePasswordEvent extends VisitorPasswordEvent {
final BuildContext? context; final BuildContext? context;
final String? email; final String? email;
final String? passwordName; final String? passwordName;
const OfflineOneTimePasswordEvent({this.email,this.passwordName,this.context}); const OfflineOneTimePasswordEvent(
{this.email, this.passwordName, this.context});
@override @override
List<Object> get props => [email!,passwordName!,context!,]; List<Object> get props => [
email!,
passwordName!,
context!,
];
} }
class OfflineMultipleTimePasswordEvent extends VisitorPasswordEvent { class OfflineMultipleTimePasswordEvent extends VisitorPasswordEvent {
@ -93,13 +108,18 @@ class OfflineMultipleTimePasswordEvent extends VisitorPasswordEvent {
final String? effectiveTime; final String? effectiveTime;
final BuildContext? context; final BuildContext? context;
const OfflineMultipleTimePasswordEvent({this.context,this.email,this.passwordName,this.invalidTime,this.effectiveTime}); const OfflineMultipleTimePasswordEvent(
{this.context,
this.email,
this.passwordName,
this.invalidTime,
this.effectiveTime});
@override @override
List<Object> get props => [email!,passwordName!,invalidTime!,effectiveTime!,context!]; List<Object> get props =>
[email!, passwordName!, invalidTime!, effectiveTime!, context!];
} }
class SelectDeviceEvent extends VisitorPasswordEvent { class SelectDeviceEvent extends VisitorPasswordEvent {
final String deviceId; final String deviceId;
const SelectDeviceEvent(this.deviceId); const SelectDeviceEvent(this.deviceId);
@ -116,22 +136,26 @@ class FilterDataEvent extends VisitorPasswordEvent {
this.endTime, this.endTime,
}); });
} }
class UpdateFilteredDevicesEvent extends VisitorPasswordEvent { class UpdateFilteredDevicesEvent extends VisitorPasswordEvent {
final List<DeviceModel> filteredData; final List<DeviceModel> filteredData;
UpdateFilteredDevicesEvent(this.filteredData); UpdateFilteredDevicesEvent(this.filteredData);
}class SelectTimeEvent extends VisitorPasswordEvent { }
class SelectTimeEvent extends VisitorPasswordEvent {
final BuildContext context; final BuildContext context;
final bool isEffective; final bool isEffective;
const SelectTimeEvent({required this.context,required this.isEffective}); const SelectTimeEvent({required this.context, required this.isEffective});
@override @override
List<Object> get props => [context,isEffective]; List<Object> get props => [context, isEffective];
} }
class ChangeTimeEvent extends VisitorPasswordEvent { class ChangeTimeEvent extends VisitorPasswordEvent {
final dynamic val; final dynamic val;
final bool isStartEndTime; final bool isStartEndTime;
const ChangeTimeEvent({required this.val,required this.isStartEndTime}); const ChangeTimeEvent({required this.val, required this.isStartEndTime});
@override @override
List<Object> get props => [val,isStartEndTime]; List<Object> get props => [val, isStartEndTime];
} }

View File

@ -1,5 +1,3 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:syncrow_web/pages/visitor_password/model/device_model.dart'; import 'package:syncrow_web/pages/visitor_password/model/device_model.dart';
@ -12,8 +10,6 @@ abstract class VisitorPasswordState extends Equatable {
class VisitorPasswordInitial extends VisitorPasswordState {} class VisitorPasswordInitial extends VisitorPasswordState {}
class PasswordTypeSelected extends VisitorPasswordState { class PasswordTypeSelected extends VisitorPasswordState {
final String selectedType; final String selectedType;
const PasswordTypeSelected(this.selectedType); const PasswordTypeSelected(this.selectedType);
@ -36,13 +32,16 @@ class IsRepeatState extends VisitorPasswordState {
@override @override
List<Object> get props => [repeat]; List<Object> get props => [repeat];
} }
class LoadingInitialState extends VisitorPasswordState {} class LoadingInitialState extends VisitorPasswordState {}
class ChangeTimeState extends VisitorPasswordState {} class ChangeTimeState extends VisitorPasswordState {}
class TimeSelectedState extends VisitorPasswordState {} class TimeSelectedState extends VisitorPasswordState {}
class DeviceLoaded extends VisitorPasswordState {} class DeviceLoaded extends VisitorPasswordState {}
class SuccessState extends VisitorPasswordState {} class SuccessState extends VisitorPasswordState {}
class FailedState extends VisitorPasswordState { class FailedState extends VisitorPasswordState {

View File

@ -1,5 +1,3 @@
import 'package:syncrow_web/utils/constants/const.dart'; import 'package:syncrow_web/utils/constants/const.dart';
class DeviceModel { class DeviceModel {
@ -50,25 +48,25 @@ class DeviceModel {
// Deserialize from JSON // Deserialize from JSON
factory DeviceModel.fromJson(Map<String, dynamic> json) { factory DeviceModel.fromJson(Map<String, dynamic> json) {
return DeviceModel( return DeviceModel(
productUuid: json['productUuid'] , productUuid: json['productUuid'],
productType: json['productType'], productType: json['productType'],
activeTime: json['activeTime'], activeTime: json['activeTime'],
category: json['category'] , category: json['category'],
categoryName: json['categoryName'] , categoryName: json['categoryName'],
createTime: json['createTime'] , createTime: json['createTime'],
gatewayId: json['gatewayId'], gatewayId: json['gatewayId'],
icon: json['icon'], icon: json['icon'],
ip: json['ip'] , ip: json['ip'],
lat: json['lat'] , lat: json['lat'],
localKey: json['localKey'] , localKey: json['localKey'],
lon: json['lon'] , lon: json['lon'],
model: json['model'] , model: json['model'],
name: json['name'], name: json['name'],
online: OnlineTypeExtension.fromString(json['online']), online: OnlineTypeExtension.fromString(json['online']),
ownerId: json['ownerId'] , ownerId: json['ownerId'],
sub: json['sub'], sub: json['sub'],
timeZone: json['timeZone'], timeZone: json['timeZone'],
updateTime: json['updateTime'] , updateTime: json['updateTime'],
uuid: json['uuid'], uuid: json['uuid'],
); );
} }

View File

@ -44,7 +44,8 @@ class RepeatWidget extends StatelessWidget {
value: visitorBloc.selectedDays.contains(day['key']), value: visitorBloc.selectedDays.contains(day['key']),
onChanged: (bool? value) { onChanged: (bool? value) {
if (value != null) { if (value != null) {
visitorBloc.add(ToggleDaySelectionEvent(key: day['key']!)); visitorBloc
.add(ToggleDaySelectionEvent(key: day['key']!));
} }
}, },
), ),
@ -60,18 +61,20 @@ class RepeatWidget extends StatelessWidget {
title: '', title: '',
size: size, size: size,
endTime: () { endTime: () {
visitorBloc.add(SelectTimeEvent( visitorBloc
context: context, .add(SelectTimeEvent(context: context, isEffective: false));
isEffective: false));
Future.delayed(const Duration(milliseconds: 500), () { Future.delayed(const Duration(milliseconds: 500), () {
visitorBloc.add(ChangeTimeEvent(val: visitorBloc.endTime, isStartEndTime: true)); visitorBloc.add(ChangeTimeEvent(
val: visitorBloc.endTime, isStartEndTime: true));
}); });
}, },
startTime: () { startTime: () {
Future.delayed(const Duration(milliseconds: 500), () { Future.delayed(const Duration(milliseconds: 500), () {
visitorBloc.add(ChangeTimeEvent(val: visitorBloc.endTime, isStartEndTime: true)); visitorBloc.add(ChangeTimeEvent(
val: visitorBloc.endTime, isStartEndTime: true));
}); });
visitorBloc.add(SelectTimeEvent(context: context, isEffective: true)); visitorBloc
.add(SelectTimeEvent(context: context, isEffective: true));
}, },
firstString: visitorBloc.effectiveTime, firstString: visitorBloc.effectiveTime,
secondString: visitorBloc.expirationTime, secondString: visitorBloc.expirationTime,
@ -80,7 +83,6 @@ class RepeatWidget extends StatelessWidget {
const SizedBox(height: 20), const SizedBox(height: 20),
], ],
); );
} });
);
} }
} }

View File

@ -7,8 +7,7 @@ import 'package:syncrow_web/pages/visitor_password/model/schedule_model.dart';
import 'package:syncrow_web/services/api/http_service.dart'; import 'package:syncrow_web/services/api/http_service.dart';
import 'package:syncrow_web/utils/constants/api_const.dart'; import 'package:syncrow_web/utils/constants/api_const.dart';
class AccessMangApi{ class AccessMangApi {
Future<List<PasswordModel>> fetchVisitorPassword() async { Future<List<PasswordModel>> fetchVisitorPassword() async {
try { try {
final response = await HTTPService().get( final response = await HTTPService().get(
@ -49,8 +48,8 @@ class AccessMangApi{
} }
} }
Future<bool> postOnlineOneTime({ Future<bool> postOnlineOneTime(
String? email, {String? email,
String? passwordName, String? passwordName,
String? password, String? password,
String? effectiveTime, String? effectiveTime,
@ -64,14 +63,14 @@ class AccessMangApi{
"passwordName": passwordName, "passwordName": passwordName,
"password": password, "password": password,
"devicesUuid": devicesUuid, "devicesUuid": devicesUuid,
"effectiveTime":effectiveTime , "effectiveTime": effectiveTime,
"invalidTime": invalidTime "invalidTime": invalidTime
}), }),
showServerMessage: true, showServerMessage: true,
expectedResponseModel: (json) { expectedResponseModel: (json) {
if(json['statusCode'].toString()=='201'){ if (json['statusCode'].toString() == '201') {
return true; return true;
}else{ } else {
return false; return false;
} }
}, },
@ -84,8 +83,8 @@ class AccessMangApi{
} }
} }
Future postOnlineMultipleTime({ Future postOnlineMultipleTime(
String? effectiveTime, {String? effectiveTime,
String? invalidTime, String? invalidTime,
String? email, String? email,
String? password, String? password,
@ -102,22 +101,24 @@ class AccessMangApi{
"invalidTime": invalidTime, "invalidTime": invalidTime,
}; };
if (scheduleList != null) { if (scheduleList != null) {
body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList(); body["scheduleList"] =
scheduleList.map((schedule) => schedule.toJson()).toList();
} }
final response = await HTTPService().post( final response = await HTTPService().post(
path: ApiEndpoints.sendOnlineMultipleTime, path: ApiEndpoints.sendOnlineMultipleTime,
body: jsonEncode(body), body: jsonEncode(body),
showServerMessage: true, showServerMessage: true,
expectedResponseModel: (json) { expectedResponseModel: (json) {
if(json['data']['successOperations'][0]['success'].toString()=='true'){ if (json['data']['successOperations'][0]['success'].toString() ==
'true') {
return true; return true;
}else{ } else {
return false; return false;
} }
}, },
); );
return response; return response;
} on DioException catch (e){ } on DioException catch (e) {
debugPrint('Error fetching ${e.type.name}'); debugPrint('Error fetching ${e.type.name}');
debugPrint('Error fetching ${e.response!.statusMessage}'); debugPrint('Error fetching ${e.response!.statusMessage}');
return false; return false;
@ -126,7 +127,8 @@ class AccessMangApi{
// OffLine One Time Password // OffLine One Time Password
Future postOffLineOneTime({String? email,String? passwordName,List<String>? devicesUuid}) async { Future postOffLineOneTime(
{String? email, String? passwordName, List<String>? devicesUuid}) async {
try { try {
final response = await HTTPService().post( final response = await HTTPService().post(
path: ApiEndpoints.sendOffLineOneTime, path: ApiEndpoints.sendOffLineOneTime,
@ -143,8 +145,7 @@ class AccessMangApi{
} else { } else {
return false; return false;
} }
} });
);
return response; return response;
} catch (e) { } catch (e) {
debugPrint('Error fetching $e'); debugPrint('Error fetching $e');
@ -152,20 +153,18 @@ class AccessMangApi{
} }
} }
Future postOffLineMultipleTime({ Future postOffLineMultipleTime(
String? email, {String? email,
String? passwordName, String? passwordName,
String? effectiveTime, String? effectiveTime,
String? invalidTime, String? invalidTime,
List<String>? devicesUuid List<String>? devicesUuid}) async {
}) async {
try { try {
final response = await HTTPService().post( final response = await HTTPService().post(
path: ApiEndpoints.sendOffLineOneTime, path: ApiEndpoints.sendOffLineOneTime,
body: jsonEncode({ body: jsonEncode({
"email": email, "email": email,
"devicesUuid":devicesUuid, "devicesUuid": devicesUuid,
"passwordName": passwordName, "passwordName": passwordName,
"effectiveTime": effectiveTime, "effectiveTime": effectiveTime,
"invalidTime": invalidTime "invalidTime": invalidTime
@ -178,8 +177,7 @@ class AccessMangApi{
} else { } else {
return false; return false;
} }
} });
);
return response; return response;
} catch (e) { } catch (e) {
debugPrint('Error fetching $e'); debugPrint('Error fetching $e');

View File

@ -22,16 +22,19 @@ class HTTPInterceptor extends InterceptorsWrapper {
if (await validateResponse(response)) { if (await validateResponse(response)) {
super.onResponse(response, handler); super.onResponse(response, handler);
} else { } else {
handler.reject(DioException(requestOptions: response.requestOptions, response: response)); handler.reject(DioException(
requestOptions: response.requestOptions, response: response));
} }
} }
@override @override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) async { void onRequest(
RequestOptions options, RequestInterceptorHandler handler) async {
var storage = const FlutterSecureStorage(); var storage = const FlutterSecureStorage();
var token = await storage.read(key: Token.loginAccessTokenKey); var token = await storage.read(key: Token.loginAccessTokenKey);
if (checkHeaderExclusionListOfAddedParameters(options.path)) { if (checkHeaderExclusionListOfAddedParameters(options.path)) {
options.headers.putIfAbsent(HttpHeaders.authorizationHeader, () => "Bearer $token"); options.headers
.putIfAbsent(HttpHeaders.authorizationHeader, () => "Bearer $token");
} }
// options.headers['Authorization'] = 'Bearer ${'${token!}123'}'; // options.headers['Authorization'] = 'Bearer ${'${token!}123'}';
super.onRequest(options, handler); super.onRequest(options, handler);

View File

@ -31,8 +31,7 @@ class ServerFailure extends Failure {
{ {
// var document = parser.parse(dioError.response!.data.toString()); // var document = parser.parse(dioError.response!.data.toString());
// var message = document.body!.text; // var message = document.body!.text;
return ServerFailure.fromResponse( return ServerFailure.fromResponse(dioError.response!.statusCode!,
dioError.response!.statusCode!,
dioError.response?.data['message'] ?? "Error"); dioError.response?.data['message'] ?? "Error");
} }
case DioExceptionType.cancel: case DioExceptionType.cancel:

View File

@ -1,4 +1,3 @@
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:syncrow_web/pages/auth/model/region_model.dart'; import 'package:syncrow_web/pages/auth/model/region_model.dart';
@ -18,48 +17,43 @@ class AuthenticationAPI {
return response; return response;
} }
static Future forgetPassword( static Future forgetPassword({
{required var email, required var password,}) async { required var email,
required var password,
}) async {
final response = await HTTPService().post( final response = await HTTPService().post(
path: ApiEndpoints.forgetPassword, path: ApiEndpoints.forgetPassword,
body: { body: {"email": email, "password": password},
"email": email,
"password": password
},
showServerMessage: true, showServerMessage: true,
expectedResponseModel: (json) {}); expectedResponseModel: (json) {});
return response; return response;
} }
static Future<int?> sendOtp(
static Future<int?> sendOtp({required String email, required String regionUuid}) async { {required String email, required String regionUuid}) async {
try { try {
final response = await HTTPService().post( final response = await HTTPService().post(
path: ApiEndpoints.sendOtp, path: ApiEndpoints.sendOtp,
body: { body: {"email": email, "type": "PASSWORD", "regionUuid": regionUuid},
"email": email,
"type": "PASSWORD",
"regionUuid": regionUuid
},
showServerMessage: true, showServerMessage: true,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return 30; return 30;
} });
);
return 30; return 30;
} on DioException catch (e) { } on DioException catch (e) {
if (e.response != null) { if (e.response != null) {
if (e.response!.statusCode == 400) { if (e.response!.statusCode == 400) {
final errorData = e.response!.data; final errorData = e.response!.data;
String errorMessage = errorData['message']; String errorMessage = errorData['message'];
if(errorMessage=='User not found'){ if (errorMessage == 'User not found') {
return 1; return 1;
}else{ } else {
int cooldown = errorData['data']['cooldown'] ?? 1; int cooldown = errorData['data']['cooldown'] ?? 1;
return cooldown; return cooldown;
} }
} else { } else {
debugPrint('Error: ${e.response!.statusCode} - ${e.response!.statusMessage}'); debugPrint(
'Error: ${e.response!.statusCode} - ${e.response!.statusMessage}');
return 1; return 1;
} }
} else { } else {
@ -74,7 +68,7 @@ class AuthenticationAPI {
static Future verifyOtp( static Future verifyOtp(
{required String email, required String otpCode}) async { {required String email, required String otpCode}) async {
try{ try {
final response = await HTTPService().post( final response = await HTTPService().post(
path: ApiEndpoints.verifyOtp, path: ApiEndpoints.verifyOtp,
body: {"email": email, "type": "PASSWORD", "otpCode": otpCode}, body: {"email": email, "type": "PASSWORD", "otpCode": otpCode},
@ -87,7 +81,7 @@ class AuthenticationAPI {
} }
}); });
return response; return response;
}on DioException catch (e){ } on DioException catch (e) {
if (e.response != null) { if (e.response != null) {
if (e.response!.statusCode == 400) { if (e.response!.statusCode == 400) {
final errorData = e.response!.data; final errorData = e.response!.data;
@ -105,10 +99,10 @@ class AuthenticationAPI {
path: ApiEndpoints.getRegion, path: ApiEndpoints.getRegion,
showServerMessage: true, showServerMessage: true,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return (json as List).map((zone) => RegionModel.fromJson(zone)).toList(); return (json as List)
} .map((zone) => RegionModel.fromJson(zone))
); .toList();
});
return response as List<RegionModel>; return response as List<RegionModel>;
} }
} }

View File

@ -0,0 +1,26 @@
import 'package:flutter/material.dart';
import 'package:syncrow_web/pages/device_managment/models/devices_model.dart';
import 'package:syncrow_web/services/api/http_service.dart';
import 'package:syncrow_web/utils/constants/api_const.dart';
class DevicesManagementApi {
Future<List<AllDevicesModel>> fetchDevices() async {
try {
final response = await HTTPService().get(
path: ApiEndpoints.getAllDevices,
showServerMessage: true,
expectedResponseModel: (json) {
List<dynamic> jsonData = json;
List<AllDevicesModel> devicesList = jsonData.map((jsonItem) {
return AllDevicesModel.fromJson(jsonItem);
}).toList();
return devicesList;
},
);
return response;
} catch (e) {
debugPrint('Error fetching $e');
return [];
}
}
}

View File

@ -1,16 +1,15 @@
import 'package:syncrow_web/pages/auth/model/user_model.dart'; import 'package:syncrow_web/pages/auth/model/user_model.dart';
import 'package:syncrow_web/services/api/http_service.dart'; import 'package:syncrow_web/services/api/http_service.dart';
import 'package:syncrow_web/utils/constants/api_const.dart'; import 'package:syncrow_web/utils/constants/api_const.dart';
class HomeApi{ class HomeApi {
Future fetchUserInfo(userId) async { Future fetchUserInfo(userId) async {
final response = await HTTPService().get( final response = await HTTPService().get(
path: ApiEndpoints.getUser.replaceAll('{userUuid}', userId!), path: ApiEndpoints.getUser.replaceAll('{userUuid}', userId!),
showServerMessage: true, showServerMessage: true,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return UserModel.fromJson(json); return UserModel.fromJson(json);
} });
);
return response; return response;
} }
} }

View File

@ -4,7 +4,7 @@ import 'package:syncrow_web/services/api/http_interceptor.dart';
import 'package:syncrow_web/services/api/http_service.dart'; import 'package:syncrow_web/services/api/http_service.dart';
final GetIt serviceLocator = GetIt.instance; final GetIt serviceLocator = GetIt.instance;
//setupLocator() // to search for dependency injection in flutter //setupLocator() // to search for dependency injection in flutter
initialSetup() { initialSetup() {
serviceLocator.registerSingleton<HTTPInterceptor>(HTTPInterceptor()); serviceLocator.registerSingleton<HTTPInterceptor>(HTTPInterceptor());
//Base classes //Base classes

View File

@ -25,6 +25,7 @@ abstract class ColorsManager {
static const Color slidingBlueColor = Color(0x99023DFE); static const Color slidingBlueColor = Color(0x99023DFE);
static const Color blackColor = Color(0xFF000000); static const Color blackColor = Color(0xFF000000);
static const Color lightGreen = Color(0xFF00FF0A); static const Color lightGreen = Color(0xFF00FF0A);
static const Color green = Color(0xFF008905);
static const Color grayColor = Color(0xFF999999); static const Color grayColor = Color(0xFF999999);
static const Color red = Color(0xFFFF0000); static const Color red = Color(0xFFFF0000);
static const Color graysColor = Color(0xffEBEBEB); static const Color graysColor = Color(0xffEBEBEB);

View File

@ -5,21 +5,28 @@ abstract class ApiEndpoints {
////////////////////////////////////// Authentication /////////////////////////////// ////////////////////////////////////// Authentication ///////////////////////////////
static const String signUp = '$baseUrl/authentication/user/signup'; static const String signUp = '$baseUrl/authentication/user/signup';
static const String login = '$baseUrl/authentication/user/login'; static const String login = '$baseUrl/authentication/user/login';
static const String forgetPassword = '$baseUrl/authentication/user/forget-password'; static const String forgetPassword =
'$baseUrl/authentication/user/forget-password';
static const String sendOtp = '$baseUrl/authentication/user/send-otp'; static const String sendOtp = '$baseUrl/authentication/user/send-otp';
static const String verifyOtp = '$baseUrl/authentication/user/verify-otp'; static const String verifyOtp = '$baseUrl/authentication/user/verify-otp';
static const String getRegion = '$baseUrl/region'; static const String getRegion = '$baseUrl/region';
static const String visitorPassword = '$baseUrl/visitor-password'; static const String visitorPassword = '$baseUrl/visitor-password';
static const String getDevices = '$baseUrl/visitor-password/devices'; static const String getDevices = '$baseUrl/visitor-password/devices';
static const String sendOnlineOneTime =
static const String sendOnlineOneTime = '$baseUrl/visitor-password/temporary-password/online/one-time'; '$baseUrl/visitor-password/temporary-password/online/one-time';
static const String sendOnlineMultipleTime = '$baseUrl/visitor-password/temporary-password/online/multiple-time'; static const String sendOnlineMultipleTime =
'$baseUrl/visitor-password/temporary-password/online/multiple-time';
//offline Password //offline Password
static const String sendOffLineOneTime = '$baseUrl/visitor-password/temporary-password/offline/one-time'; static const String sendOffLineOneTime =
static const String sendOffLineMultipleTime = '$baseUrl/visitor-password/temporary-password/offline/multiple-time'; '$baseUrl/visitor-password/temporary-password/offline/one-time';
static const String sendOffLineMultipleTime =
'$baseUrl/visitor-password/temporary-password/offline/multiple-time';
static const String getUser = '$baseUrl/user/{userUuid}'; static const String getUser = '$baseUrl/user/{userUuid}';
////// Devices Management ////////////////
static const String getAllDevices = '$baseUrl/device';
} }

View File

@ -13,10 +13,12 @@ class Assets {
static const String rightLine = "assets/images/right_line.png"; static const String rightLine = "assets/images/right_line.png";
static const String google = "assets/images/google.svg"; static const String google = "assets/images/google.svg";
static const String facebook = "assets/images/facebook.svg"; static const String facebook = "assets/images/facebook.svg";
static const String invisiblePassword = "assets/images/Password_invisible.svg"; static const String invisiblePassword =
"assets/images/Password_invisible.svg";
static const String visiblePassword = "assets/images/Password_visible.svg"; static const String visiblePassword = "assets/images/Password_visible.svg";
static const String accessIcon = "assets/images/access_icon.svg"; static const String accessIcon = "assets/images/access_icon.svg";
static const String spaseManagementIcon = "assets/images/spase_management_icon.svg"; static const String spaseManagementIcon =
"assets/images/spase_management_icon.svg";
static const String devicesIcon = "assets/images/devices_icon.svg"; static const String devicesIcon = "assets/images/devices_icon.svg";
static const String moveinIcon = "assets/images/movein_icon.svg"; static const String moveinIcon = "assets/images/movein_icon.svg";
static const String constructionIcon = "assets/images/construction_icon.svg"; static const String constructionIcon = "assets/images/construction_icon.svg";

View File

@ -1,4 +1,3 @@
enum AccessType { enum AccessType {
onlineOnetime, onlineOnetime,
onlineMultiple, onlineMultiple,
@ -36,11 +35,6 @@ extension AccessTypeExtension on AccessType {
} }
} }
enum DeviseStatus { enum DeviseStatus {
online, online,
offline, offline,
@ -53,7 +47,6 @@ extension OnlineTypeExtension on DeviseStatus {
return "Online"; return "Online";
case DeviseStatus.offline: case DeviseStatus.offline:
return "Offline"; return "Offline";
} }
} }
@ -69,10 +62,9 @@ extension OnlineTypeExtension on DeviseStatus {
} }
} }
enum AccessStatus { enum AccessStatus {
expired , expired,
effective , effective,
toBeEffective, toBeEffective,
} }
@ -82,18 +74,17 @@ extension AccessStatusExtension on AccessStatus {
case AccessStatus.expired: case AccessStatus.expired:
return "Expired"; return "Expired";
case AccessStatus.effective: case AccessStatus.effective:
return "Effective" ; return "Effective";
case AccessStatus.toBeEffective: case AccessStatus.toBeEffective:
return "To be effective"; return "To be effective";
} }
} }
static AccessStatus fromString(String value) { static AccessStatus fromString(String value) {
switch (value) { switch (value) {
case "EXPIRED" : case "EXPIRED":
return AccessStatus.expired; return AccessStatus.expired;
case "EFFECTIVE" : case "EFFECTIVE":
return AccessStatus.effective; return AccessStatus.effective;
case "TO_BE_EFFECTIVE": case "TO_BE_EFFECTIVE":
return AccessStatus.toBeEffective; return AccessStatus.toBeEffective;
@ -102,8 +93,3 @@ extension AccessStatusExtension on AccessStatus {
} }
} }
} }

View File

@ -0,0 +1,11 @@
import 'package:intl/intl.dart';
String formatDateTime(DateTime? dateTime) {
if (dateTime == null) {
return '-';
}
final DateFormat dateFormatter = DateFormat('dd/MM/yyyy');
final DateFormat timeFormatter = DateFormat('HH:mm');
return '${dateFormatter.format(dateTime)} ${timeFormatter.format(dateTime)}';
}

View File

@ -1,16 +1,17 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class ResponsiveLayout extends StatelessWidget { class ResponsiveLayout extends StatelessWidget {
final Widget desktopBody; final Widget desktopBody;
final Widget mobileBody; final Widget mobileBody;
const ResponsiveLayout({super.key,required this.desktopBody,required this.mobileBody}); const ResponsiveLayout(
{super.key, required this.desktopBody, required this.mobileBody});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) { return LayoutBuilder(
if(constraints.maxWidth<600){ builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return mobileBody; return mobileBody;
}else{ } else {
return desktopBody; return desktopBody;
} }
}, },

View File

@ -16,7 +16,6 @@ class CustomSnackBar {
BuildContext? currentContext = key?.currentContext; BuildContext? currentContext = key?.currentContext;
if (key != null && currentContext != null) { if (key != null && currentContext != null) {
final snackBar = SnackBar( final snackBar = SnackBar(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
backgroundColor: Colors.green, backgroundColor: Colors.green,
content: Row(mainAxisAlignment: MainAxisAlignment.center, children: [ content: Row(mainAxisAlignment: MainAxisAlignment.center, children: [

View File

@ -1,9 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'color_manager.dart'; import 'color_manager.dart';
InputDecoration? textBoxDecoration({bool suffixIcon = false}) => InputDecoration( InputDecoration? textBoxDecoration({bool suffixIcon = false}) =>
InputDecoration(
focusColor: ColorsManager.grayColor, focusColor: ColorsManager.grayColor,
suffixIcon:suffixIcon? const Icon(Icons.search):null, suffixIcon: suffixIcon ? const Icon(Icons.search) : null,
hintText: 'Search', hintText: 'Search',
filled: true, // Enable background filling filled: true, // Enable background filling
fillColor: const Color(0xffF5F6F7), // Set the background color fillColor: const Color(0xffF5F6F7), // Set the background color
@ -27,8 +28,7 @@ InputDecoration? textBoxDecoration({bool suffixIcon = false}) => InputDecoration
borderSide: BorderSide(color: Colors.red, width: 2), borderSide: BorderSide(color: Colors.red, width: 2),
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
); );
BoxDecoration containerDecoration = BoxDecoration( BoxDecoration containerDecoration = BoxDecoration(
boxShadow: [ boxShadow: [
@ -36,11 +36,8 @@ BoxDecoration containerDecoration = BoxDecoration(
color: Colors.grey.withOpacity(0.5), color: Colors.grey.withOpacity(0.5),
spreadRadius: 5, spreadRadius: 5,
blurRadius: 8, blurRadius: 8,
offset: const Offset(0, offset: const Offset(0, 3), // changes position of shadow
3), // changes position of shadow
), ),
], ],
color: ColorsManager.boxColor, color: ColorsManager.boxColor,
borderRadius: const BorderRadius.all(Radius.circular(10))); borderRadius: const BorderRadius.all(Radius.circular(10)));

View File

@ -28,23 +28,28 @@ class MenuSidebar extends StatelessWidget {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
const Text('Community',style: TextStyle(fontSize: 20),), const Text(
'Community',
style: TextStyle(fontSize: 20),
),
CircleAvatar( CircleAvatar(
backgroundColor: Colors.grey.shade200, backgroundColor: Colors.grey.shade200,
child: IconButton( child: IconButton(
color: ColorsManager.onSecondaryColor, color: ColorsManager.onSecondaryColor,
onPressed: () {}, onPressed: () {},
icon: const Icon(Icons.add) icon: const Icon(Icons.add)),
),
) )
], ],
), ),
const SizedBox(height: 20,), const SizedBox(
height: 20,
),
TextFormField( TextFormField(
controller: TextEditingController(), controller: TextEditingController(),
decoration:textBoxDecoration(suffixIcon: true) decoration: textBoxDecoration(suffixIcon: true)),
), Container(
Container(height: 100,) height: 100,
)
], ],
), ),
), ),

View File

@ -3,12 +3,18 @@ import 'package:flutter_svg/svg.dart';
import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/web_layout/web_app_bar.dart'; import 'package:syncrow_web/web_layout/web_app_bar.dart';
import 'menu_sidebar.dart'; import 'menu_sidebar.dart';
class WebScaffold extends StatelessWidget { class WebScaffold extends StatelessWidget {
final bool enableMenuSideba; final bool enableMenuSideba;
final Widget? appBarTitle; final Widget? appBarTitle;
final List<Widget>? appBarBody; final List<Widget>? appBarBody;
final Widget? scaffoldBody; final Widget? scaffoldBody;
const WebScaffold({super.key,this.appBarTitle,this.appBarBody,this.scaffoldBody,this.enableMenuSideba=true}); const WebScaffold(
{super.key,
this.appBarTitle,
this.appBarBody,
this.scaffoldBody,
this.enableMenuSideba = true});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -22,7 +28,9 @@ class WebScaffold extends StatelessWidget {
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
), ),
Container(color: Colors.white.withOpacity(0.7),), Container(
color: Colors.white.withOpacity(0.7),
),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
@ -31,17 +39,12 @@ class WebScaffold extends StatelessWidget {
child: WebAppBar( child: WebAppBar(
title: appBarTitle, title: appBarTitle,
body: appBarBody, body: appBarBody,
) )),
),
Expanded( Expanded(
child: Row( child: Row(
children: [ children: [
if(enableMenuSideba) if (enableMenuSideba) const MenuSidebar(),
const MenuSidebar(), Expanded(flex: 5, child: scaffoldBody!)
Expanded(
flex: 5,
child: scaffoldBody!
)
], ],
), ),
) )