mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-09 22:57:21 +00:00
push fetch devices and connecting the filters
This commit is contained in:
@ -0,0 +1 @@
|
||||
|
||||
|
@ -38,17 +38,20 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
||||
emit(FailedState(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
void updateTabsCount() {
|
||||
int toBeEffectiveCount = data.where((item) => item.passwordStatus.value== 'To Be Effective').length;
|
||||
int effectiveCount = data.where((item) => item.passwordStatus.value == 'Effective').length;
|
||||
int expiredCount = data.where((item) => item.passwordStatus.value == 'Expired').length;
|
||||
int toBeEffectiveCount = data
|
||||
.where((item) => item.passwordStatus.value == 'To Be Effective')
|
||||
.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[2] = 'Effective ($effectiveCount)';
|
||||
tabs[3] = 'Expired ($expiredCount)';
|
||||
}
|
||||
|
||||
|
||||
|
||||
int selectedIndex = 0;
|
||||
final List<String> tabs = [
|
||||
'All',
|
||||
@ -57,8 +60,8 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
||||
'Expired'
|
||||
];
|
||||
|
||||
|
||||
Future selectFilterTap(TabChangedEvent event, Emitter<AccessState> emit) async {
|
||||
Future selectFilterTap(
|
||||
TabChangedEvent event, Emitter<AccessState> emit) async {
|
||||
try {
|
||||
emit(AccessLoaded());
|
||||
selectedIndex = event.selectedIndex;
|
||||
@ -70,7 +73,6 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Future<void> selectTime(SelectTime event, Emitter<AccessState> emit) async {
|
||||
emit(AccessLoaded());
|
||||
|
||||
@ -84,7 +86,6 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
||||
final TimeOfDay? timePicked = await showTimePicker(
|
||||
context: event.context,
|
||||
initialTime: TimeOfDay.now(),
|
||||
|
||||
builder: (context, child) {
|
||||
return Theme(
|
||||
data: ThemeData.light().copyWith(
|
||||
@ -116,19 +117,30 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
||||
selectedDateTime.day,
|
||||
selectedDateTime.hour,
|
||||
selectedDateTime.minute,
|
||||
).millisecondsSinceEpoch ~/ 1000; // Divide by 1000 to remove milliseconds
|
||||
).millisecondsSinceEpoch ~/
|
||||
1000; // Divide by 1000 to remove milliseconds
|
||||
if (event.isStart) {
|
||||
if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) {
|
||||
CustomSnackBar.displaySnackBar('Effective Time cannot be later than Expiration Time.');
|
||||
if (expirationTimeTimeStamp != null &&
|
||||
selectedTimestamp > expirationTimeTimeStamp!) {
|
||||
CustomSnackBar.displaySnackBar(
|
||||
'Effective Time cannot be later than Expiration Time.');
|
||||
} else {
|
||||
startTime = selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
|
||||
startTime = selectedDateTime
|
||||
.toString()
|
||||
.split('.')
|
||||
.first; // Remove seconds and milliseconds
|
||||
effectiveTimeTimeStamp = selectedTimestamp;
|
||||
}
|
||||
} else {
|
||||
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) {
|
||||
CustomSnackBar.displaySnackBar('Expiration Time cannot be earlier than Effective Time.');
|
||||
if (effectiveTimeTimeStamp != null &&
|
||||
selectedTimestamp < effectiveTimeTimeStamp!) {
|
||||
CustomSnackBar.displaySnackBar(
|
||||
'Expiration Time cannot be earlier than Effective Time.');
|
||||
} else {
|
||||
endTime = selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
|
||||
endTime = selectedDateTime
|
||||
.toString()
|
||||
.split('.')
|
||||
.first; // Remove seconds and milliseconds
|
||||
expirationTimeTimeStamp = selectedTimestamp;
|
||||
}
|
||||
}
|
||||
@ -137,8 +149,8 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
||||
emit(ChangeTimeState());
|
||||
}
|
||||
|
||||
|
||||
Future<void> _filterData(FilterDataEvent event, Emitter<AccessState> emit) async {
|
||||
Future<void> _filterData(
|
||||
FilterDataEvent event, Emitter<AccessState> emit) async {
|
||||
emit(AccessLoaded());
|
||||
try {
|
||||
filteredData = data.where((item) {
|
||||
@ -151,7 +163,8 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
||||
}
|
||||
}
|
||||
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());
|
||||
if (effectiveTime == null || invalidTime == null) {
|
||||
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;
|
||||
} else if (event.selectedTabIndex == 2 && item.passwordStatus.value != 'Effective') {
|
||||
} else if (event.selectedTabIndex == 2 &&
|
||||
item.passwordStatus.value != 'Effective') {
|
||||
matchesCriteria = false;
|
||||
} else if (event.selectedTabIndex == 3 && item.passwordStatus.value != 'Expired') {
|
||||
} else if (event.selectedTabIndex == 3 &&
|
||||
item.passwordStatus.value != 'Expired') {
|
||||
matchesCriteria = false;
|
||||
}
|
||||
return matchesCriteria;
|
||||
@ -190,11 +206,13 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
||||
}
|
||||
|
||||
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')}";
|
||||
}
|
||||
|
||||
Future<void> onTabChanged(TabChangedEvent event, Emitter<AccessState> emit) async {
|
||||
Future<void> onTabChanged(
|
||||
TabChangedEvent event, Emitter<AccessState> emit) async {
|
||||
try {
|
||||
emit(AccessLoaded());
|
||||
selectedIndex = event.selectedIndex;
|
||||
@ -203,13 +221,19 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
||||
filteredData = data;
|
||||
break;
|
||||
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;
|
||||
case 2: // Effective
|
||||
filteredData = data.where((item) => item.passwordStatus.value == "Effective").toList();
|
||||
filteredData = data
|
||||
.where((item) => item.passwordStatus.value == "Effective")
|
||||
.toList();
|
||||
break;
|
||||
case 3: // Expired
|
||||
filteredData = data.where((item) => item.passwordStatus.value == "Expired").toList();
|
||||
filteredData = data
|
||||
.where((item) => item.passwordStatus.value == "Expired")
|
||||
.toList();
|
||||
break;
|
||||
default:
|
||||
filteredData = data;
|
||||
@ -218,12 +242,10 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
|
||||
selectedTabIndex: selectedIndex,
|
||||
passwordName: passwordName.text.toLowerCase(),
|
||||
startTime: effectiveTimeTimeStamp,
|
||||
endTime: expirationTimeTimeStamp
|
||||
));
|
||||
endTime: expirationTimeTimeStamp));
|
||||
emit(TableLoaded(filteredData));
|
||||
} catch (e) {
|
||||
emit(FailedState(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@ -8,7 +7,9 @@ abstract class AccessEvent extends Equatable {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class FetchTableData extends AccessEvent {}
|
||||
|
||||
class ResetSearch extends AccessEvent {}
|
||||
|
||||
class TabChangedEvent extends AccessEvent {
|
||||
@ -17,7 +18,6 @@ class TabChangedEvent extends AccessEvent {
|
||||
const TabChangedEvent(this.selectedIndex);
|
||||
}
|
||||
|
||||
|
||||
class SelectTime extends AccessEvent {
|
||||
final BuildContext context;
|
||||
final bool isStart;
|
||||
@ -26,7 +26,6 @@ class SelectTime extends AccessEvent {
|
||||
List<Object> get props => [context, isStart];
|
||||
}
|
||||
|
||||
|
||||
class FilterDataEvent extends AccessEvent {
|
||||
final String? passwordName;
|
||||
final int? startTime;
|
||||
@ -38,9 +37,5 @@ class FilterDataEvent extends AccessEvent {
|
||||
this.startTime,
|
||||
this.endTime,
|
||||
required this.selectedTabIndex, // Initialize this field
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -11,6 +11,7 @@ abstract class AccessState extends Equatable {
|
||||
class AccessInitial extends AccessState {}
|
||||
|
||||
class AccessLoaded extends AccessState {}
|
||||
|
||||
class FailedState extends AccessState {
|
||||
final String message;
|
||||
|
||||
|
@ -50,5 +50,4 @@ class PasswordModel {
|
||||
'deviceUuid': deviceUuid,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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/date_time_widget.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/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
@ -94,6 +94,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
// emit(FailureForgetState(error: failure.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
//925207
|
||||
String? validateCode(String? value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
|
@ -13,7 +13,11 @@ class LoginButtonPressed extends AuthEvent {
|
||||
final String password;
|
||||
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
|
||||
List<Object> get props => [username, password, regionUuid];
|
||||
@ -22,10 +26,14 @@ class LoginButtonPressed extends AuthEvent {
|
||||
class CheckBoxEvent extends AuthEvent {
|
||||
final bool? newValue;
|
||||
|
||||
const CheckBoxEvent({required this.newValue,});
|
||||
const CheckBoxEvent({
|
||||
required this.newValue,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object> get props => [newValue!,];
|
||||
List<Object> get props => [
|
||||
newValue!,
|
||||
];
|
||||
}
|
||||
|
||||
class GetCodeEvent extends AuthEvent {}
|
||||
@ -39,7 +47,8 @@ class StopTimerEvent extends AuthEvent{}
|
||||
class UpdateTimerEvent extends AuthEvent {
|
||||
final int remainingTime;
|
||||
final bool isButtonEnabled;
|
||||
const UpdateTimerEvent({required this.remainingTime, required this.isButtonEnabled});
|
||||
const UpdateTimerEvent(
|
||||
{required this.remainingTime, required this.isButtonEnabled});
|
||||
}
|
||||
|
||||
class ChangePasswordEvent extends AuthEvent {}
|
||||
@ -49,11 +58,15 @@ class SendOtpEvent extends AuthEvent{}
|
||||
class PasswordVisibleEvent extends AuthEvent {
|
||||
final bool? newValue;
|
||||
|
||||
const PasswordVisibleEvent({required this.newValue,});
|
||||
const PasswordVisibleEvent({
|
||||
required this.newValue,
|
||||
});
|
||||
}
|
||||
|
||||
class RegionInitialEvent extends AuthEvent {}
|
||||
|
||||
class CheckEnableEvent extends AuthEvent {}
|
||||
|
||||
class ChangeValidateEvent extends AuthEvent {}
|
||||
|
||||
class SelectRegionEvent extends AuthEvent {
|
||||
@ -62,4 +75,3 @@ class SelectRegionEvent extends AuthEvent {
|
||||
@override
|
||||
List<Object> get props => [val];
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ class LoginInitial extends AuthState {}
|
||||
class AuthTokenLoading extends AuthState {}
|
||||
|
||||
class AuthLoading extends AuthState {}
|
||||
|
||||
class AuthInitialState extends AuthState {}
|
||||
|
||||
class LoginSuccess extends AuthState {}
|
||||
@ -55,7 +56,8 @@ class TimerState extends AuthState {
|
||||
final bool isButtonEnabled;
|
||||
final int remainingTime;
|
||||
|
||||
const TimerState({required this.isButtonEnabled, required this.remainingTime});
|
||||
const TimerState(
|
||||
{required this.isButtonEnabled, required this.remainingTime});
|
||||
|
||||
@override
|
||||
List<Object> get props => [isButtonEnabled, remainingTime];
|
||||
@ -74,6 +76,7 @@ class AuthTokenError extends AuthError {
|
||||
class AuthSuccess extends AuthState {}
|
||||
|
||||
class AuthTokenSuccess extends AuthSuccess {}
|
||||
|
||||
class TimerUpdated extends AuthState {
|
||||
final String formattedTime;
|
||||
final bool isButtonEnabled;
|
||||
|
@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
class RegionModel {
|
||||
final String name;
|
||||
final String id;
|
||||
|
@ -42,14 +42,11 @@ class Token {
|
||||
//save token to secure storage
|
||||
var storage = const FlutterSecureStorage();
|
||||
storage.write(
|
||||
key: loginAccessTokenKey,
|
||||
value: json[loginAccessTokenKey] ?? '');
|
||||
key: loginAccessTokenKey, value: json[loginAccessTokenKey] ?? '');
|
||||
storage.write(
|
||||
key: loginRefreshTokenKey,
|
||||
value: json[loginRefreshTokenKey] ?? '');
|
||||
key: loginRefreshTokenKey, value: json[loginRefreshTokenKey] ?? '');
|
||||
//create token object ?
|
||||
return Token(
|
||||
json[loginAccessTokenKey] ?? '',
|
||||
return Token(json[loginAccessTokenKey] ?? '',
|
||||
json[loginRefreshTokenKey] ?? '', '', 0, 0);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
import 'package:syncrow_web/pages/auth/model/token.dart';
|
||||
|
||||
class UserModel {
|
||||
|
@ -10,7 +10,10 @@ class VerifyPassCode {
|
||||
final String deviceId;
|
||||
|
||||
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(
|
||||
phone: json[verificationPhone],
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ForgetPasswordMobilePage extends StatelessWidget {
|
||||
|
@ -1,10 +1,8 @@
|
||||
|
||||
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_web_page.dart';
|
||||
import 'package:syncrow_web/utils/responsive_layout.dart';
|
||||
|
||||
|
||||
class ForgetPasswordPage extends StatelessWidget {
|
||||
const ForgetPasswordPage({super.key});
|
||||
|
||||
@ -12,8 +10,6 @@ class ForgetPasswordPage extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return const ResponsiveLayout(
|
||||
desktopBody: ForgetPasswordWebPage(),
|
||||
mobileBody:ForgetPasswordWebPage()
|
||||
);
|
||||
mobileBody: ForgetPasswordWebPage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,8 @@ class ForgetPasswordWebPage extends StatelessWidget {
|
||||
borderRadius:
|
||||
const BorderRadius.all(Radius.circular(30)),
|
||||
border: Border.all(
|
||||
color: ColorsManager.graysColor.withOpacity(0.2)),
|
||||
color:
|
||||
ColorsManager.graysColor.withOpacity(0.2)),
|
||||
),
|
||||
child: Form(
|
||||
key: forgetBloc.forgetFormKey,
|
||||
@ -108,7 +109,8 @@ class ForgetPasswordWebPage extends StatelessWidget {
|
||||
horizontal: size.width * 0.02,
|
||||
vertical: size.width * 0.003),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceEvenly,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
const SizedBox(height: 10),
|
||||
@ -122,21 +124,27 @@ class ForgetPasswordWebPage extends StatelessWidget {
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
'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,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Country/Region",
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400),
|
||||
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
SizedBox(
|
||||
@ -145,7 +153,8 @@ class ForgetPasswordWebPage extends StatelessWidget {
|
||||
icon: const Icon(
|
||||
Icons.keyboard_arrow_down_outlined,
|
||||
),
|
||||
decoration: textBoxDecoration()!.copyWith(
|
||||
decoration:
|
||||
textBoxDecoration()!.copyWith(
|
||||
hintText: null,
|
||||
),
|
||||
hint: SizedBox(
|
||||
@ -160,15 +169,14 @@ class ForgetPasswordWebPage extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
isDense: true,
|
||||
style:
|
||||
const TextStyle(color: Colors.black),
|
||||
style: const TextStyle(
|
||||
color: Colors.black),
|
||||
items: forgetBloc.regionList!
|
||||
.map((RegionModel region) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: region.id,
|
||||
child: SizedBox(
|
||||
width: size.width * 0.06,
|
||||
|
||||
child: Text(region.name)),
|
||||
);
|
||||
}).toList(),
|
||||
@ -183,13 +191,18 @@ class ForgetPasswordWebPage extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"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),
|
||||
SizedBox(
|
||||
@ -197,22 +210,29 @@ class ForgetPasswordWebPage extends StatelessWidget {
|
||||
validator: forgetBloc.validateEmail,
|
||||
controller:
|
||||
forgetBloc.forgetEmailController,
|
||||
decoration: textBoxDecoration()!.copyWith(
|
||||
decoration: textBoxDecoration()!
|
||||
.copyWith(
|
||||
hintText: 'Enter your email'),
|
||||
style:
|
||||
const TextStyle(color: Colors.black),
|
||||
style: const TextStyle(
|
||||
color: Colors.black),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20.0),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"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),
|
||||
SizedBox(
|
||||
@ -221,65 +241,88 @@ class ForgetPasswordWebPage extends StatelessWidget {
|
||||
keyboardType:
|
||||
TextInputType.visiblePassword,
|
||||
controller: forgetBloc.forgetOtp,
|
||||
decoration: textBoxDecoration()!.copyWith(
|
||||
decoration:
|
||||
textBoxDecoration()!.copyWith(
|
||||
hintText: 'Enter Code',
|
||||
suffixIcon: SizedBox(
|
||||
width: 100,
|
||||
child: Center(
|
||||
child: InkWell(
|
||||
onTap:state is TimerState && !state.isButtonEnabled && state.remainingTime!=1?null: () {
|
||||
forgetBloc.add(StartTimerEvent());
|
||||
onTap: state is TimerState &&
|
||||
!state
|
||||
.isButtonEnabled &&
|
||||
state.remainingTime !=
|
||||
1
|
||||
? null
|
||||
: () {
|
||||
forgetBloc.add(
|
||||
StartTimerEvent());
|
||||
},
|
||||
child: Text(
|
||||
'Get Code ${state is TimerState && !state.isButtonEnabled && state.remainingTime != 1 ? "(${forgetBloc.formattedTime(state.remainingTime)}) " : ""}',
|
||||
style: TextStyle(
|
||||
color: state is TimerState &&
|
||||
!state.isButtonEnabled
|
||||
color: state
|
||||
is TimerState &&
|
||||
!state
|
||||
.isButtonEnabled
|
||||
? Colors.grey
|
||||
: ColorsManager.btnColor,
|
||||
: ColorsManager
|
||||
.btnColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
style:
|
||||
const TextStyle(color: Colors.black),
|
||||
style: const TextStyle(
|
||||
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: const EdgeInsets.only(top: 8.0),
|
||||
padding:
|
||||
const EdgeInsets.only(top: 8.0),
|
||||
child: Text(
|
||||
forgetBloc.forgetValidate,
|
||||
style: const TextStyle(
|
||||
color: ColorsManager.red,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w700
|
||||
),
|
||||
fontWeight: FontWeight.w700),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20.0),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"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),
|
||||
SizedBox(
|
||||
child: TextFormField(
|
||||
validator: forgetBloc.passwordValidator,
|
||||
keyboardType: TextInputType.visiblePassword,
|
||||
controller: forgetBloc.forgetPasswordController,
|
||||
decoration: textBoxDecoration()!.copyWith(
|
||||
validator:
|
||||
forgetBloc.passwordValidator,
|
||||
keyboardType:
|
||||
TextInputType.visiblePassword,
|
||||
controller: forgetBloc
|
||||
.forgetPasswordController,
|
||||
decoration:
|
||||
textBoxDecoration()!.copyWith(
|
||||
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),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: size.width * 0.2,
|
||||
child: DefaultButton(
|
||||
backgroundColor: ColorsManager.btnColor,
|
||||
backgroundColor:
|
||||
ColorsManager.btnColor,
|
||||
child: const Text('Submit'),
|
||||
onPressed: () {
|
||||
if (forgetBloc.forgetFormKey.currentState!.validate()) {
|
||||
forgetBloc.add(ChangePasswordEvent());
|
||||
if (forgetBloc
|
||||
.forgetFormKey.currentState!
|
||||
.validate()) {
|
||||
forgetBloc
|
||||
.add(ChangePasswordEvent());
|
||||
}
|
||||
},
|
||||
),
|
||||
@ -321,8 +369,10 @@ class ForgetPasswordWebPage extends StatelessWidget {
|
||||
SizedBox(
|
||||
width: size.width * 0.2,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
children: [
|
||||
const Flexible(
|
||||
child: Text(
|
||||
|
@ -148,14 +148,14 @@ class LoginMobilePage extends StatelessWidget {
|
||||
),
|
||||
isDense: true,
|
||||
style: const TextStyle(color: Colors.black),
|
||||
items:loginBloc.regionList!.map((RegionModel region) {
|
||||
items: loginBloc.regionList!
|
||||
.map((RegionModel region) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: region.name,
|
||||
child: Text(region.name),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (String? value) {
|
||||
},
|
||||
onChanged: (String? value) {},
|
||||
),
|
||||
)
|
||||
],
|
||||
@ -194,7 +194,8 @@ class LoginMobilePage extends StatelessWidget {
|
||||
validator: loginBloc.validatePassword,
|
||||
obscureText: loginBloc.obscureText,
|
||||
keyboardType: TextInputType.visiblePassword,
|
||||
controller: loginBloc.loginPasswordController,
|
||||
controller:
|
||||
loginBloc.loginPasswordController,
|
||||
decoration: textBoxDecoration()!.copyWith(
|
||||
hintText: 'At least 8 characters',
|
||||
),
|
||||
@ -220,7 +221,8 @@ class LoginMobilePage extends StatelessWidget {
|
||||
},
|
||||
child: Text(
|
||||
"Forgot Password?",
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
style:
|
||||
Theme.of(context).textTheme.bodySmall,
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -295,12 +297,15 @@ class LoginMobilePage extends StatelessWidget {
|
||||
: ColorsManager.grayColor,
|
||||
child: const Text('Sign in'),
|
||||
onPressed: () {
|
||||
if (loginBloc.loginFormKey.currentState!.validate()) {
|
||||
if (loginBloc.loginFormKey.currentState!
|
||||
.validate()) {
|
||||
loginBloc.add(
|
||||
LoginButtonPressed(
|
||||
regionUuid: '',
|
||||
username: loginBloc.loginEmailController.text,
|
||||
password: loginBloc.loginPasswordController.text,
|
||||
username:
|
||||
loginBloc.loginEmailController.text,
|
||||
password: loginBloc
|
||||
.loginPasswordController.text,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -9,8 +9,6 @@ class LoginPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const ResponsiveLayout(
|
||||
desktopBody: LoginWebPage(),
|
||||
mobileBody:LoginWebPage()
|
||||
);
|
||||
desktopBody: LoginWebPage(), mobileBody: LoginWebPage());
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ class LoginWebPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _LoginWebPageState extends State<LoginWebPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@ -61,13 +60,15 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
late ScrollController _scrollController;
|
||||
_scrollController = ScrollController();
|
||||
void _scrollToCenter() {
|
||||
final double middlePosition = _scrollController.position.maxScrollExtent / 2;
|
||||
final double middlePosition =
|
||||
_scrollController.position.maxScrollExtent / 2;
|
||||
_scrollController.animateTo(
|
||||
middlePosition,
|
||||
duration: const Duration(seconds: 1),
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
}
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_scrollToCenter();
|
||||
});
|
||||
@ -104,8 +105,11 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.1),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(30)),
|
||||
border: Border.all(color: ColorsManager.graysColor.withOpacity(0.2))),
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(30)),
|
||||
border: Border.all(
|
||||
color: ColorsManager.graysColor
|
||||
.withOpacity(0.2))),
|
||||
child: Form(
|
||||
key: loginBloc.loginFormKey,
|
||||
child: Padding(
|
||||
@ -113,80 +117,125 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
horizontal: size.width * 0.02,
|
||||
vertical: size.width * 0.003),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceEvenly,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
const SizedBox(height: 40),
|
||||
Text(
|
||||
'Login',
|
||||
style:Theme.of(context).textTheme.headlineLarge),
|
||||
Text('Login',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.headlineLarge),
|
||||
SizedBox(height: size.height * 0.03),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"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(
|
||||
child: DropdownButtonFormField<String>(
|
||||
child: DropdownButtonFormField<
|
||||
String>(
|
||||
padding: EdgeInsets.zero,
|
||||
value: loginBloc.regionList!.any((region) => region.id == loginBloc.regionUuid)
|
||||
value: loginBloc.regionList!
|
||||
.any((region) =>
|
||||
region.id ==
|
||||
loginBloc
|
||||
.regionUuid)
|
||||
? loginBloc.regionUuid
|
||||
: null,
|
||||
|
||||
validator: loginBloc.validateRegion,
|
||||
validator:
|
||||
loginBloc.validateRegion,
|
||||
icon: const Icon(
|
||||
Icons.keyboard_arrow_down_outlined,
|
||||
Icons
|
||||
.keyboard_arrow_down_outlined,
|
||||
),
|
||||
decoration: textBoxDecoration()!.copyWith(
|
||||
errorStyle: const TextStyle(height: 0),
|
||||
decoration: textBoxDecoration()!
|
||||
.copyWith(
|
||||
errorStyle: const TextStyle(
|
||||
height: 0),
|
||||
hintText: null,
|
||||
),
|
||||
hint: SizedBox(
|
||||
width: size.width * 0.12,
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
alignment:
|
||||
Alignment.centerLeft,
|
||||
child: Text(
|
||||
'Select your region/country',
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
fontWeight: FontWeight.w400),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
textAlign:
|
||||
TextAlign.center,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
color:
|
||||
ColorsManager
|
||||
.grayColor,
|
||||
fontWeight:
|
||||
FontWeight
|
||||
.w400),
|
||||
overflow:
|
||||
TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
isDense: true,
|
||||
style: const TextStyle(color: Colors.black),
|
||||
items: loginBloc.regionList!.map((RegionModel region) {
|
||||
return DropdownMenuItem<String>(
|
||||
style: const TextStyle(
|
||||
color: Colors.black),
|
||||
items: loginBloc.regionList!
|
||||
.map((RegionModel region) {
|
||||
return DropdownMenuItem<
|
||||
String>(
|
||||
value: region.id,
|
||||
child: SizedBox(
|
||||
width: size.width*0.08,
|
||||
child: Text(region.name)),
|
||||
width:
|
||||
size.width * 0.08,
|
||||
child:
|
||||
Text(region.name)),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (String? value) {
|
||||
loginBloc.add(CheckEnableEvent());
|
||||
loginBloc.add(SelectRegionEvent(val: value!));
|
||||
loginBloc
|
||||
.add(CheckEnableEvent());
|
||||
loginBloc.add(
|
||||
SelectRegionEvent(
|
||||
val: value!));
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20.0),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.start,
|
||||
children: [
|
||||
Text("Email",
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(fontSize: 14,fontWeight: FontWeight.w400),
|
||||
Text(
|
||||
"Email",
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
fontSize: 14,
|
||||
fontWeight:
|
||||
FontWeight.w400),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
@ -194,30 +243,53 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
SizedBox(
|
||||
child: TextFormField(
|
||||
onChanged: (value) {
|
||||
loginBloc.add(CheckEnableEvent());
|
||||
loginBloc
|
||||
.add(CheckEnableEvent());
|
||||
// print(loginBloc.checkEnable());
|
||||
},
|
||||
validator:loginBloc.loginValidateEmail ,
|
||||
controller:loginBloc.loginEmailController,
|
||||
decoration: textBoxDecoration()!.copyWith(
|
||||
errorStyle: const TextStyle(height: 0), // Hide the error text space
|
||||
hintText: 'Enter your email address',
|
||||
hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
fontWeight: FontWeight.w400)
|
||||
),
|
||||
style: const TextStyle(color: Colors.black),
|
||||
validator: loginBloc
|
||||
.loginValidateEmail,
|
||||
controller: loginBloc
|
||||
.loginEmailController,
|
||||
decoration: textBoxDecoration()!
|
||||
.copyWith(
|
||||
errorStyle: const TextStyle(
|
||||
height:
|
||||
0), // Hide the error text space
|
||||
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),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.start,
|
||||
children: [
|
||||
Text("Password",
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(fontSize: 14,fontWeight: FontWeight.w400),
|
||||
Text(
|
||||
"Password",
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
fontSize: 14,
|
||||
fontWeight:
|
||||
FontWeight.w400),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
@ -225,33 +297,54 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
SizedBox(
|
||||
child: TextFormField(
|
||||
onChanged: (value) {
|
||||
loginBloc.add(CheckEnableEvent());
|
||||
loginBloc
|
||||
.add(CheckEnableEvent());
|
||||
},
|
||||
validator:loginBloc.validatePassword,
|
||||
obscureText:loginBloc.obscureText,
|
||||
keyboardType: TextInputType.visiblePassword,
|
||||
controller:loginBloc.loginPasswordController,
|
||||
decoration: textBoxDecoration()!.copyWith(
|
||||
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));
|
||||
validator:
|
||||
loginBloc.validatePassword,
|
||||
obscureText:
|
||||
loginBloc.obscureText,
|
||||
keyboardType: TextInputType
|
||||
.visiblePassword,
|
||||
controller: loginBloc
|
||||
.loginPasswordController,
|
||||
decoration: textBoxDecoration()!
|
||||
.copyWith(
|
||||
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(
|
||||
child: SvgPicture.asset(
|
||||
loginBloc.obscureText?
|
||||
Assets.visiblePassword :
|
||||
Assets.invisiblePassword,
|
||||
loginBloc.obscureText
|
||||
? Assets
|
||||
.visiblePassword
|
||||
: Assets
|
||||
.invisiblePassword,
|
||||
height: 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(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.end,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).push(MaterialPageRoute(builder: (context) => const ForgetPasswordPage(),));
|
||||
Navigator.of(context)
|
||||
.push(MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
const ForgetPasswordPage(),
|
||||
));
|
||||
},
|
||||
child: Text(
|
||||
"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,15 +386,18 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
Row(
|
||||
children: [
|
||||
Transform.scale(
|
||||
scale: 1.2, // Adjust the scale as needed
|
||||
scale:
|
||||
1.2, // Adjust the scale as needed
|
||||
child: Checkbox(
|
||||
fillColor: MaterialStateProperty.all<Color>(Colors.white),
|
||||
fillColor: MaterialStateProperty
|
||||
.all<Color>(Colors.white),
|
||||
activeColor: Colors.white,
|
||||
value: loginBloc.isChecked,
|
||||
checkColor: Colors.black,
|
||||
shape: const CircleBorder(),
|
||||
onChanged: (bool? newValue) {
|
||||
loginBloc.add(CheckBoxEvent(newValue: newValue));
|
||||
loginBloc.add(CheckBoxEvent(
|
||||
newValue: newValue));
|
||||
},
|
||||
),
|
||||
),
|
||||
@ -298,32 +406,41 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
text: 'Agree to ',
|
||||
style: const TextStyle(color: Colors.white),
|
||||
style: const TextStyle(
|
||||
color: Colors.white),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '(Terms of Service)',
|
||||
text:
|
||||
'(Terms of Service)',
|
||||
style: const TextStyle(
|
||||
color: Colors.black,),
|
||||
recognizer: TapGestureRecognizer()
|
||||
color: Colors.black,
|
||||
),
|
||||
recognizer:
|
||||
TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
loginBloc.launchURL(
|
||||
'https://example.com/terms');
|
||||
},
|
||||
),
|
||||
TextSpan(
|
||||
text: ' (Legal Statement)',
|
||||
style: const TextStyle(color: Colors.black),
|
||||
recognizer: TapGestureRecognizer()
|
||||
text:
|
||||
' (Legal Statement)',
|
||||
style: const TextStyle(
|
||||
color: Colors.black),
|
||||
recognizer:
|
||||
TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
loginBloc.launchURL(
|
||||
'https://example.com/legal');
|
||||
},
|
||||
),
|
||||
TextSpan(
|
||||
text: ' (Privacy Statement)',
|
||||
text:
|
||||
' (Privacy Statement)',
|
||||
style: const TextStyle(
|
||||
color: Colors.black),
|
||||
recognizer: TapGestureRecognizer()
|
||||
recognizer:
|
||||
TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
loginBloc.launchURL(
|
||||
'https://example.com/privacy');
|
||||
@ -337,30 +454,49 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
),
|
||||
const SizedBox(height: 20.0),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: size.width * 0.2,
|
||||
child: DefaultButton(
|
||||
enabled: loginBloc.checkValidate,
|
||||
enabled:
|
||||
loginBloc.checkValidate,
|
||||
child: Text('Sign in',
|
||||
style: Theme.of(context).textTheme.labelLarge !.copyWith(
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.labelLarge!
|
||||
.copyWith(
|
||||
fontSize: 14,
|
||||
color:
|
||||
loginBloc.checkValidate ?
|
||||
ColorsManager.whiteColors:ColorsManager.whiteColors.withOpacity(0.2),
|
||||
)
|
||||
),
|
||||
color: loginBloc
|
||||
.checkValidate
|
||||
? ColorsManager
|
||||
.whiteColors
|
||||
: ColorsManager
|
||||
.whiteColors
|
||||
.withOpacity(
|
||||
0.2),
|
||||
)),
|
||||
onPressed: () {
|
||||
if(loginBloc.loginFormKey.currentState!.validate() ){
|
||||
loginBloc.add(LoginButtonPressed(
|
||||
regionUuid:loginBloc.regionUuid,
|
||||
username: loginBloc.loginEmailController.text,
|
||||
password: loginBloc.loginPasswordController.text,
|
||||
if (loginBloc.loginFormKey
|
||||
.currentState!
|
||||
.validate()) {
|
||||
loginBloc
|
||||
.add(LoginButtonPressed(
|
||||
regionUuid:
|
||||
loginBloc.regionUuid,
|
||||
username: loginBloc
|
||||
.loginEmailController
|
||||
.text,
|
||||
password: loginBloc
|
||||
.loginPasswordController
|
||||
.text,
|
||||
));
|
||||
} else {
|
||||
loginBloc.add(ChangeValidateEvent());
|
||||
loginBloc.add(
|
||||
ChangeValidateEvent());
|
||||
}
|
||||
},
|
||||
),
|
||||
@ -369,18 +505,29 @@ class _LoginWebPageState extends State<LoginWebPage> {
|
||||
),
|
||||
const SizedBox(height: 15.0),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [ SizedBox(child: Text(loginBloc.validate,
|
||||
style: const TextStyle(fontWeight: FontWeight.w700,color: ColorsManager.red ),),)],)
|
||||
],
|
||||
),
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
child: Text(
|
||||
loginBloc.validate,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w700,
|
||||
color: ColorsManager.red),
|
||||
),
|
||||
)
|
||||
)),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
))),
|
||||
const Spacer(),
|
||||
],
|
||||
),),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -40,14 +40,12 @@ class DefaultButton extends StatelessWidget {
|
||||
: customButtonStyle ??
|
||||
ButtonStyle(
|
||||
textStyle: MaterialStateProperty.all(
|
||||
customTextStyle
|
||||
?? Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
customTextStyle ??
|
||||
Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
fontSize: 13,
|
||||
color: foregroundColor,
|
||||
fontWeight: FontWeight.normal
|
||||
fontWeight: FontWeight.normal),
|
||||
),
|
||||
),
|
||||
|
||||
foregroundColor: MaterialStateProperty.all(
|
||||
isSecondary
|
||||
? Colors.black
|
||||
|
@ -11,7 +11,8 @@ Future<void> showCustomDialog({
|
||||
double? iconHeight,
|
||||
double? iconWidth,
|
||||
VoidCallback? onOkPressed,
|
||||
bool barrierDismissible = false, required actions,
|
||||
bool barrierDismissible = false,
|
||||
required actions,
|
||||
}) {
|
||||
return showDialog(
|
||||
context: context,
|
||||
|
@ -224,8 +224,14 @@ class _DynamicTableState extends State<DynamicTable> {
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
content,
|
||||
style: const TextStyle(
|
||||
color: Colors.black, fontSize: 10, fontWeight: FontWeight.w400),
|
||||
style: TextStyle(
|
||||
color: content == 'Online'
|
||||
? ColorsManager.green
|
||||
: content == 'Offline'
|
||||
? ColorsManager.red
|
||||
: Colors.black,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -1,7 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
|
||||
class DateTimeWebWidget extends StatelessWidget {
|
||||
@ -42,15 +41,22 @@ class DateTimeWebWidget extends StatelessWidget {
|
||||
.bodyMedium!
|
||||
.copyWith(color: Colors.red),
|
||||
),
|
||||
Text(title??'' ,
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
color: Colors.black,fontSize: 13),),
|
||||
Text(
|
||||
title,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(color: Colors.black, fontSize: 13),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8,),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
Container(
|
||||
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,
|
||||
child: FittedBox(
|
||||
child: Column(
|
||||
@ -61,25 +67,41 @@ class DateTimeWebWidget extends StatelessWidget {
|
||||
InkWell(
|
||||
onTap: startTime,
|
||||
child: FittedBox(
|
||||
child: Text(firstString,
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
color: ColorsManager.grayColor,fontSize: 12,fontWeight: FontWeight.w400),),
|
||||
)
|
||||
child: Text(
|
||||
firstString,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
)),
|
||||
const SizedBox(
|
||||
width: 30,
|
||||
),
|
||||
SizedBox(width: 30,),
|
||||
const Icon(Icons.arrow_right_alt),
|
||||
SizedBox(width: 30,),
|
||||
|
||||
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),
|
||||
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,
|
||||
),
|
||||
SvgPicture.asset(
|
||||
icon,
|
||||
),
|
||||
|
@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class HourPickerDialog extends StatefulWidget {
|
||||
@ -17,7 +15,9 @@ class _HourPickerDialogState extends State<HourPickerDialog> {
|
||||
@override
|
||||
void 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;
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,6 @@ class InfoDialog extends StatelessWidget {
|
||||
width: 35,
|
||||
),
|
||||
),
|
||||
|
||||
Text(
|
||||
title,
|
||||
style: Theme.of(context).textTheme.headlineLarge!.copyWith(
|
||||
|
@ -8,37 +8,25 @@ class StatefulTextField extends StatefulWidget {
|
||||
this.hintText = 'Please enter',
|
||||
required this.width,
|
||||
this.elevation = 0,
|
||||
required this.controller, // Add the controller
|
||||
});
|
||||
|
||||
final String title;
|
||||
final String hintText;
|
||||
final double width;
|
||||
final double elevation;
|
||||
final TextEditingController controller;
|
||||
|
||||
@override
|
||||
State<StatefulTextField> createState() => _StatefulTextFieldState();
|
||||
}
|
||||
|
||||
class _StatefulTextFieldState extends State<StatefulTextField> {
|
||||
late TextEditingController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = TextEditingController();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomTextField(
|
||||
title: widget.title,
|
||||
controller: _controller,
|
||||
controller: widget.controller,
|
||||
hintText: widget.hintText,
|
||||
width: widget.width,
|
||||
elevation: widget.elevation,
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
|
||||
class CustomWebTextField extends StatelessWidget {
|
||||
const CustomWebTextField({
|
||||
super.key,
|
||||
@ -18,7 +18,6 @@ class CustomWebTextField extends StatelessWidget {
|
||||
final TextEditingController? controller;
|
||||
final String? Function(String?)? validator;
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
@ -31,48 +30,56 @@ class CustomWebTextField extends StatelessWidget {
|
||||
if (isRequired)
|
||||
Row(
|
||||
children: [
|
||||
Text('* ',
|
||||
Text(
|
||||
'* ',
|
||||
style: Theme.of(context)
|
||||
.textTheme.bodyMedium!
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(color: Colors.red),
|
||||
),
|
||||
Text(textFieldName, style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
color: Colors.black,fontSize: 13),),
|
||||
Text(
|
||||
textFieldName,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(color: Colors.black, fontSize: 13),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(width: 10,),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
description ?? '',
|
||||
style: Theme.of(context)
|
||||
.textTheme.bodySmall!
|
||||
.copyWith(fontSize: 9,
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
fontSize: 9,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: ColorsManager.textGray),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 7,),
|
||||
const SizedBox(
|
||||
height: 7,
|
||||
),
|
||||
Container(
|
||||
decoration: containerDecoration.copyWith(
|
||||
color: const Color(0xFFF5F6F7),
|
||||
boxShadow: [
|
||||
decoration: containerDecoration
|
||||
.copyWith(color: const Color(0xFFF5F6F7), boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withOpacity(0.3),
|
||||
spreadRadius: 2,
|
||||
blurRadius: 3,
|
||||
offset: const Offset(1, 1), // changes position of shadow
|
||||
),
|
||||
]
|
||||
),
|
||||
]),
|
||||
child: TextFormField(
|
||||
validator: validator,
|
||||
controller: controller,
|
||||
style: const TextStyle(color: Colors.black),
|
||||
decoration: textBoxDecoration()!
|
||||
.copyWith(
|
||||
errorStyle: const TextStyle(height: 0), // Hide the error text space
|
||||
decoration: textBoxDecoration()!.copyWith(
|
||||
errorStyle:
|
||||
const TextStyle(height: 0), // Hide the error text space
|
||||
|
||||
hintText: 'Please enter'),
|
||||
),
|
||||
|
@ -1,13 +1,130 @@
|
||||
import 'package:bloc/bloc.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_state.dart';
|
||||
|
||||
class DeviceManagmentBloc extends Bloc<DeviceManagmentEvent, DeviceManagmentState> {
|
||||
DeviceManagmentBloc() : super(DeviceManagmentInitial()) {
|
||||
on<DeviceManagmentEvent>((event, emit) {
|
||||
// TODO: implement event handler
|
||||
});
|
||||
class DeviceManagementBloc
|
||||
extends Bloc<DeviceManagementEvent, DeviceManagementState> {
|
||||
int _selectedIndex = 0;
|
||||
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,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,43 @@
|
||||
part of 'device_managment_bloc.dart';
|
||||
|
||||
sealed class DeviceManagmentEvent extends Equatable {
|
||||
const DeviceManagmentEvent();
|
||||
abstract class DeviceManagementEvent extends Equatable {
|
||||
const DeviceManagementEvent();
|
||||
|
||||
@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];
|
||||
}
|
||||
|
@ -1,10 +1,57 @@
|
||||
part of 'device_managment_bloc.dart';
|
||||
|
||||
sealed class DeviceManagmentState extends Equatable {
|
||||
const DeviceManagmentState();
|
||||
abstract class DeviceManagementState extends Equatable {
|
||||
const DeviceManagementState();
|
||||
|
||||
@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
|
||||
];
|
||||
}
|
||||
|
157
lib/pages/device_managment/models/devices_model.dart
Normal file
157
lib/pages/device_managment/models/devices_model.dart
Normal 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;
|
||||
}
|
||||
}
|
26
lib/pages/device_managment/models/room.dart
Normal file
26
lib/pages/device_managment/models/room.dart
Normal 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;
|
||||
}
|
||||
}
|
26
lib/pages/device_managment/models/unit.dart
Normal file
26
lib/pages/device_managment/models/unit.dart
Normal 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;
|
||||
}
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
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/web_layout/web_scaffold.dart';
|
||||
|
||||
@ -7,17 +9,31 @@ class DeviceManagementPage extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return WebScaffold(
|
||||
enableMenuSideba: true,
|
||||
appBarTitle: Row(
|
||||
children: [
|
||||
Text(
|
||||
return BlocProvider(
|
||||
create: (context) => DeviceManagementBloc()..add(FetchDevices()),
|
||||
child: WebScaffold(
|
||||
appBarTitle: Text(
|
||||
'Device Management',
|
||||
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'));
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,53 @@
|
||||
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/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/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/style.dart';
|
||||
|
||||
class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
||||
const DeviceManagementBody({super.key});
|
||||
const DeviceManagementBody({super.key, required this.devices});
|
||||
|
||||
final List<AllDevicesModel> devices;
|
||||
|
||||
@override
|
||||
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(
|
||||
padding: const EdgeInsets.all(30),
|
||||
height: context.screenHeight,
|
||||
@ -20,68 +56,34 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
FilterWidget(
|
||||
size: context.screenSize,
|
||||
tabs: ['All', 'Online', 'Offline', 'Low Battery'],
|
||||
selectedIndex: 0,
|
||||
onTabChanged: (index) {},
|
||||
size: MediaQuery.of(context).size,
|
||||
tabs: tabs,
|
||||
selectedIndex: selectedIndex,
|
||||
onTabChanged: (index) {
|
||||
context
|
||||
.read<DeviceManagementBloc>()
|
||||
.add(SelectedFilterChanged(index));
|
||||
},
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
if (isLargeScreenSize(context)) ...[
|
||||
Row(
|
||||
children: [
|
||||
const StatefulTextField(
|
||||
title: "Community",
|
||||
width: 200,
|
||||
elevation: 2,
|
||||
const DeviceSearchFilters(),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
const StatefulTextField(
|
||||
title: "Unit Name",
|
||||
width: 200,
|
||||
elevation: 2,
|
||||
Container(
|
||||
height: 43,
|
||||
width: 100,
|
||||
decoration: containerDecoration,
|
||||
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(
|
||||
height: 12,
|
||||
),
|
||||
@ -111,19 +113,28 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
||||
'Status',
|
||||
'Last Offline Date and Time',
|
||||
],
|
||||
data: []
|
||||
// state.data.map((item) {
|
||||
// return [
|
||||
// item.name.toString(),
|
||||
// item.uuid.toString(),
|
||||
// item.productType.toString(),
|
||||
// '',
|
||||
// item.online.value.toString(),
|
||||
// ];
|
||||
// }).toList(),
|
||||
)),
|
||||
data: devicesToShow.map((device) {
|
||||
return [
|
||||
device.categoryName ?? '',
|
||||
device.name ?? '',
|
||||
device.uuid ?? '',
|
||||
device.unit?.name ?? '',
|
||||
device.room?.name ?? '',
|
||||
device.batteryLevel?.toString() ?? '',
|
||||
formatDateTime(DateTime.fromMillisecondsSinceEpoch(
|
||||
device.createTime ?? 0)),
|
||||
device.online == true ? 'Online' : 'Offline',
|
||||
formatDateTime(DateTime.fromMillisecondsSinceEpoch(
|
||||
device.updateTime ?? 0)),
|
||||
];
|
||||
}).toList(),
|
||||
isEmpty: devicesToShow.isEmpty,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@ class HomeUpdateTree extends HomeState {
|
||||
@override
|
||||
List<Object> get props => [graph, builder];
|
||||
}
|
||||
|
||||
class HomeUserInfoLoaded extends HomeState {
|
||||
final UserModel user;
|
||||
|
||||
|
@ -1,7 +1,3 @@
|
||||
|
||||
|
||||
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
class HomeItemModel {
|
||||
@ -11,7 +7,6 @@ class HomeItemModel {
|
||||
final bool? active;
|
||||
final void Function(BuildContext context) onPress;
|
||||
|
||||
|
||||
HomeItemModel({
|
||||
this.title,
|
||||
this.icon,
|
||||
|
@ -24,9 +24,10 @@ class HomeCard extends StatelessWidget {
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(left: 10, right: 10, bottom: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: evenNumbers && active?
|
||||
ColorsManager.blueColor.withOpacity(0.8) :
|
||||
(active ?ColorsManager.blueColor
|
||||
color: evenNumbers && active
|
||||
? ColorsManager.blueColor.withOpacity(0.8)
|
||||
: (active
|
||||
? ColorsManager.blueColor
|
||||
: ColorsManager.blueColor.withOpacity(0.2)),
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
),
|
||||
|
@ -9,8 +9,6 @@ class HomePage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ResponsiveLayout(
|
||||
desktopBody: HomeWebPage(),
|
||||
mobileBody:HomeMobilePage()
|
||||
);
|
||||
desktopBody: HomeWebPage(), mobileBody: HomeMobilePage());
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,8 @@ class HomeMobilePage extends StatelessWidget {
|
||||
width: size.width * 0.68,
|
||||
child: GridView.builder(
|
||||
itemCount: 8,
|
||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
gridDelegate:
|
||||
const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2,
|
||||
crossAxisSpacing: 20.0,
|
||||
mainAxisSpacing: 20.0,
|
||||
|
@ -39,7 +39,8 @@ class HomeWebPage extends StatelessWidget {
|
||||
Text(
|
||||
'ACCESS YOUR APPS',
|
||||
style: Theme.of(context)
|
||||
.textTheme.headlineLarge!
|
||||
.textTheme
|
||||
.headlineLarge!
|
||||
.copyWith(color: Colors.black, fontSize: 40),
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
@ -63,7 +64,8 @@ class HomeWebPage extends StatelessWidget {
|
||||
active: homeBloc.homeItems[index].active!,
|
||||
name: homeBloc.homeItems[index].title!,
|
||||
img: homeBloc.homeItems[index].icon!,
|
||||
onTap: () => homeBloc.homeItems[index].onPress(context),
|
||||
onTap: () =>
|
||||
homeBloc.homeItems[index].onPress(context),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -32,8 +32,8 @@ class TreeWidget extends StatelessWidget {
|
||||
SizedBox(
|
||||
width: 100,
|
||||
child: TextFormField(
|
||||
decoration:
|
||||
const InputDecoration(labelText: "Subtree separation"),
|
||||
decoration: const InputDecoration(
|
||||
labelText: "Subtree separation"),
|
||||
onChanged: (text) {
|
||||
firstNodeName = text;
|
||||
},
|
||||
@ -73,9 +73,7 @@ class TreeWidget extends StatelessWidget {
|
||||
child: GraphView(
|
||||
graph: state.graph,
|
||||
algorithm: BuchheimWalkerAlgorithm(
|
||||
state.builder,
|
||||
TreeEdgeRenderer(state.builder)
|
||||
),
|
||||
state.builder, TreeEdgeRenderer(state.builder)),
|
||||
paint: Paint()
|
||||
..color = Colors.green
|
||||
..strokeWidth = 1
|
||||
|
@ -220,7 +220,6 @@ class VisitorPasswordBloc
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Future<void> postOnlineMultipleTimePassword(
|
||||
OnlineMultipleTimePasswordEvent event,
|
||||
Emitter<VisitorPasswordState> emit) async {
|
||||
@ -250,7 +249,6 @@ class VisitorPasswordBloc
|
||||
throw Exception('Failed to create password');
|
||||
}
|
||||
emit(TableLoaded(data));
|
||||
|
||||
} catch (e) {
|
||||
emit(FailedState(e.toString()));
|
||||
Navigator.pop(event.context!);
|
||||
@ -277,7 +275,6 @@ class VisitorPasswordBloc
|
||||
throw Exception('Failed to create password');
|
||||
}
|
||||
emit(TableLoaded(data));
|
||||
|
||||
} catch (e) {
|
||||
emit(FailedState(e.toString()));
|
||||
Navigator.pop(event.context!);
|
||||
@ -307,14 +304,14 @@ class VisitorPasswordBloc
|
||||
throw Exception('Failed to create password');
|
||||
}
|
||||
emit(TableLoaded(data));
|
||||
|
||||
} catch (e) {
|
||||
emit(FailedState(e.toString()));
|
||||
Navigator.pop(event.context!);
|
||||
stateDialog(
|
||||
context: event.context!,
|
||||
message: e.toString(),
|
||||
title: 'Something Wrong'); }
|
||||
title: 'Something Wrong');
|
||||
}
|
||||
}
|
||||
|
||||
void selectDevice(
|
||||
|
@ -26,19 +26,19 @@ class SelectUsageFrequency extends VisitorPasswordEvent {
|
||||
@override
|
||||
List<Object> get props => [usageType];
|
||||
}
|
||||
|
||||
class SelectTimeVisitorPassword extends VisitorPasswordEvent {
|
||||
final BuildContext context;
|
||||
final bool isStart;
|
||||
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
|
||||
List<Object> get props => [context, isStart, isRepeat];
|
||||
}
|
||||
|
||||
|
||||
|
||||
class ToggleDaySelectionEvent extends VisitorPasswordEvent {
|
||||
final String key;
|
||||
|
||||
@ -47,12 +47,11 @@ class ToggleDaySelectionEvent extends VisitorPasswordEvent {
|
||||
List<Object> get props => [key];
|
||||
}
|
||||
|
||||
|
||||
class ToggleRepeatEvent extends VisitorPasswordEvent {}
|
||||
|
||||
class GeneratePasswordEvent extends VisitorPasswordEvent {}
|
||||
|
||||
class FetchDevice extends VisitorPasswordEvent {
|
||||
}
|
||||
class FetchDevice extends VisitorPasswordEvent {}
|
||||
|
||||
//online password
|
||||
class OnlineOneTimePasswordEvent extends VisitorPasswordEvent {
|
||||
@ -60,20 +59,31 @@ class OnlineOneTimePasswordEvent extends VisitorPasswordEvent {
|
||||
final String? passwordName;
|
||||
final BuildContext? context;
|
||||
|
||||
const OnlineOneTimePasswordEvent({this.email,this.passwordName,this.context});
|
||||
const OnlineOneTimePasswordEvent(
|
||||
{this.email, this.passwordName, this.context});
|
||||
|
||||
@override
|
||||
List<Object> get props => [email!,passwordName!,];
|
||||
List<Object> get props => [
|
||||
email!,
|
||||
passwordName!,
|
||||
];
|
||||
}
|
||||
|
||||
class OnlineMultipleTimePasswordEvent extends VisitorPasswordEvent {
|
||||
final String? email;
|
||||
final String? passwordName;
|
||||
final String? invalidTime;
|
||||
final String? effectiveTime;
|
||||
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
|
||||
List<Object> get props => [email!,passwordName!,invalidTime!,effectiveTime!,context!];
|
||||
List<Object> get props =>
|
||||
[email!, passwordName!, invalidTime!, effectiveTime!, context!];
|
||||
}
|
||||
|
||||
//offline password
|
||||
@ -81,9 +91,14 @@ class OfflineOneTimePasswordEvent extends VisitorPasswordEvent {
|
||||
final BuildContext? context;
|
||||
final String? email;
|
||||
final String? passwordName;
|
||||
const OfflineOneTimePasswordEvent({this.email,this.passwordName,this.context});
|
||||
const OfflineOneTimePasswordEvent(
|
||||
{this.email, this.passwordName, this.context});
|
||||
@override
|
||||
List<Object> get props => [email!,passwordName!,context!,];
|
||||
List<Object> get props => [
|
||||
email!,
|
||||
passwordName!,
|
||||
context!,
|
||||
];
|
||||
}
|
||||
|
||||
class OfflineMultipleTimePasswordEvent extends VisitorPasswordEvent {
|
||||
@ -93,13 +108,18 @@ class OfflineMultipleTimePasswordEvent extends VisitorPasswordEvent {
|
||||
final String? effectiveTime;
|
||||
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
|
||||
List<Object> get props => [email!,passwordName!,invalidTime!,effectiveTime!,context!];
|
||||
List<Object> get props =>
|
||||
[email!, passwordName!, invalidTime!, effectiveTime!, context!];
|
||||
}
|
||||
|
||||
|
||||
class SelectDeviceEvent extends VisitorPasswordEvent {
|
||||
final String deviceId;
|
||||
const SelectDeviceEvent(this.deviceId);
|
||||
@ -116,17 +136,21 @@ class FilterDataEvent extends VisitorPasswordEvent {
|
||||
this.endTime,
|
||||
});
|
||||
}
|
||||
|
||||
class UpdateFilteredDevicesEvent extends VisitorPasswordEvent {
|
||||
final List<DeviceModel> filteredData;
|
||||
|
||||
UpdateFilteredDevicesEvent(this.filteredData);
|
||||
}class SelectTimeEvent extends VisitorPasswordEvent {
|
||||
}
|
||||
|
||||
class SelectTimeEvent extends VisitorPasswordEvent {
|
||||
final BuildContext context;
|
||||
final bool isEffective;
|
||||
const SelectTimeEvent({required this.context, required this.isEffective});
|
||||
@override
|
||||
List<Object> get props => [context, isEffective];
|
||||
}
|
||||
|
||||
class ChangeTimeEvent extends VisitorPasswordEvent {
|
||||
final dynamic val;
|
||||
final bool isStartEndTime;
|
||||
|
@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
import 'package:equatable/equatable.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 PasswordTypeSelected extends VisitorPasswordState {
|
||||
final String selectedType;
|
||||
const PasswordTypeSelected(this.selectedType);
|
||||
@ -36,13 +32,16 @@ class IsRepeatState extends VisitorPasswordState {
|
||||
|
||||
@override
|
||||
List<Object> get props => [repeat];
|
||||
|
||||
}
|
||||
|
||||
class LoadingInitialState extends VisitorPasswordState {}
|
||||
|
||||
class ChangeTimeState extends VisitorPasswordState {}
|
||||
|
||||
class TimeSelectedState extends VisitorPasswordState {}
|
||||
|
||||
class DeviceLoaded extends VisitorPasswordState {}
|
||||
|
||||
class SuccessState extends VisitorPasswordState {}
|
||||
|
||||
class FailedState extends VisitorPasswordState {
|
||||
|
@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
import 'package:syncrow_web/utils/constants/const.dart';
|
||||
|
||||
class DeviceModel {
|
||||
|
@ -44,7 +44,8 @@ class RepeatWidget extends StatelessWidget {
|
||||
value: visitorBloc.selectedDays.contains(day['key']),
|
||||
onChanged: (bool? value) {
|
||||
if (value != null) {
|
||||
visitorBloc.add(ToggleDaySelectionEvent(key: day['key']!));
|
||||
visitorBloc
|
||||
.add(ToggleDaySelectionEvent(key: day['key']!));
|
||||
}
|
||||
},
|
||||
),
|
||||
@ -60,18 +61,20 @@ class RepeatWidget extends StatelessWidget {
|
||||
title: '',
|
||||
size: size,
|
||||
endTime: () {
|
||||
visitorBloc.add(SelectTimeEvent(
|
||||
context: context,
|
||||
isEffective: false));
|
||||
visitorBloc
|
||||
.add(SelectTimeEvent(context: context, isEffective: false));
|
||||
Future.delayed(const Duration(milliseconds: 500), () {
|
||||
visitorBloc.add(ChangeTimeEvent(val: visitorBloc.endTime, isStartEndTime: true));
|
||||
visitorBloc.add(ChangeTimeEvent(
|
||||
val: visitorBloc.endTime, isStartEndTime: true));
|
||||
});
|
||||
},
|
||||
startTime: () {
|
||||
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,
|
||||
secondString: visitorBloc.expirationTime,
|
||||
@ -80,7 +83,6 @@ class RepeatWidget extends StatelessWidget {
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ import 'package:syncrow_web/services/api/http_service.dart';
|
||||
import 'package:syncrow_web/utils/constants/api_const.dart';
|
||||
|
||||
class AccessMangApi {
|
||||
|
||||
Future<List<PasswordModel>> fetchVisitorPassword() async {
|
||||
try {
|
||||
final response = await HTTPService().get(
|
||||
@ -49,8 +48,8 @@ class AccessMangApi{
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> postOnlineOneTime({
|
||||
String? email,
|
||||
Future<bool> postOnlineOneTime(
|
||||
{String? email,
|
||||
String? passwordName,
|
||||
String? password,
|
||||
String? effectiveTime,
|
||||
@ -84,8 +83,8 @@ class AccessMangApi{
|
||||
}
|
||||
}
|
||||
|
||||
Future postOnlineMultipleTime({
|
||||
String? effectiveTime,
|
||||
Future postOnlineMultipleTime(
|
||||
{String? effectiveTime,
|
||||
String? invalidTime,
|
||||
String? email,
|
||||
String? password,
|
||||
@ -102,14 +101,16 @@ class AccessMangApi{
|
||||
"invalidTime": invalidTime,
|
||||
};
|
||||
if (scheduleList != null) {
|
||||
body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList();
|
||||
body["scheduleList"] =
|
||||
scheduleList.map((schedule) => schedule.toJson()).toList();
|
||||
}
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.sendOnlineMultipleTime,
|
||||
body: jsonEncode(body),
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
if(json['data']['successOperations'][0]['success'].toString()=='true'){
|
||||
if (json['data']['successOperations'][0]['success'].toString() ==
|
||||
'true') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@ -126,7 +127,8 @@ class AccessMangApi{
|
||||
|
||||
// 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 {
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.sendOffLineOneTime,
|
||||
@ -143,8 +145,7 @@ class AccessMangApi{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
return response;
|
||||
} catch (e) {
|
||||
debugPrint('Error fetching $e');
|
||||
@ -152,14 +153,12 @@ class AccessMangApi{
|
||||
}
|
||||
}
|
||||
|
||||
Future postOffLineMultipleTime({
|
||||
String? email,
|
||||
Future postOffLineMultipleTime(
|
||||
{String? email,
|
||||
String? passwordName,
|
||||
String? effectiveTime,
|
||||
String? invalidTime,
|
||||
List<String>? devicesUuid
|
||||
|
||||
}) async {
|
||||
List<String>? devicesUuid}) async {
|
||||
try {
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.sendOffLineOneTime,
|
||||
@ -178,8 +177,7 @@ class AccessMangApi{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
return response;
|
||||
} catch (e) {
|
||||
debugPrint('Error fetching $e');
|
||||
|
@ -22,16 +22,19 @@ class HTTPInterceptor extends InterceptorsWrapper {
|
||||
if (await validateResponse(response)) {
|
||||
super.onResponse(response, handler);
|
||||
} else {
|
||||
handler.reject(DioException(requestOptions: response.requestOptions, response: response));
|
||||
handler.reject(DioException(
|
||||
requestOptions: response.requestOptions, response: response));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
|
||||
void onRequest(
|
||||
RequestOptions options, RequestInterceptorHandler handler) async {
|
||||
var storage = const FlutterSecureStorage();
|
||||
var token = await storage.read(key: Token.loginAccessTokenKey);
|
||||
if (checkHeaderExclusionListOfAddedParameters(options.path)) {
|
||||
options.headers.putIfAbsent(HttpHeaders.authorizationHeader, () => "Bearer $token");
|
||||
options.headers
|
||||
.putIfAbsent(HttpHeaders.authorizationHeader, () => "Bearer $token");
|
||||
}
|
||||
// options.headers['Authorization'] = 'Bearer ${'${token!}123'}';
|
||||
super.onRequest(options, handler);
|
||||
|
@ -31,8 +31,7 @@ class ServerFailure extends Failure {
|
||||
{
|
||||
// var document = parser.parse(dioError.response!.data.toString());
|
||||
// var message = document.body!.text;
|
||||
return ServerFailure.fromResponse(
|
||||
dioError.response!.statusCode!,
|
||||
return ServerFailure.fromResponse(dioError.response!.statusCode!,
|
||||
dioError.response?.data['message'] ?? "Error");
|
||||
}
|
||||
case DioExceptionType.cancel:
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:syncrow_web/pages/auth/model/region_model.dart';
|
||||
@ -18,34 +17,28 @@ class AuthenticationAPI {
|
||||
return response;
|
||||
}
|
||||
|
||||
static Future forgetPassword(
|
||||
{required var email, required var password,}) async {
|
||||
static Future forgetPassword({
|
||||
required var email,
|
||||
required var password,
|
||||
}) async {
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.forgetPassword,
|
||||
body: {
|
||||
"email": email,
|
||||
"password": password
|
||||
},
|
||||
body: {"email": email, "password": password},
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {});
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
static Future<int?> sendOtp({required String email, required String regionUuid}) async {
|
||||
static Future<int?> sendOtp(
|
||||
{required String email, required String regionUuid}) async {
|
||||
try {
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.sendOtp,
|
||||
body: {
|
||||
"email": email,
|
||||
"type": "PASSWORD",
|
||||
"regionUuid": regionUuid
|
||||
},
|
||||
body: {"email": email, "type": "PASSWORD", "regionUuid": regionUuid},
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
return 30;
|
||||
}
|
||||
);
|
||||
});
|
||||
return 30;
|
||||
} on DioException catch (e) {
|
||||
if (e.response != null) {
|
||||
@ -59,7 +52,8 @@ class AuthenticationAPI {
|
||||
return cooldown;
|
||||
}
|
||||
} else {
|
||||
debugPrint('Error: ${e.response!.statusCode} - ${e.response!.statusMessage}');
|
||||
debugPrint(
|
||||
'Error: ${e.response!.statusCode} - ${e.response!.statusMessage}');
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
@ -105,10 +99,10 @@ class AuthenticationAPI {
|
||||
path: ApiEndpoints.getRegion,
|
||||
showServerMessage: true,
|
||||
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>;
|
||||
}
|
||||
|
||||
}
|
||||
|
26
lib/services/devices_mang_api.dart
Normal file
26
lib/services/devices_mang_api.dart
Normal 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 [];
|
||||
}
|
||||
}
|
||||
}
|
@ -9,8 +9,7 @@ class HomeApi{
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
return UserModel.fromJson(json);
|
||||
}
|
||||
);
|
||||
});
|
||||
return response;
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@ abstract class ColorsManager {
|
||||
static const Color slidingBlueColor = Color(0x99023DFE);
|
||||
static const Color blackColor = Color(0xFF000000);
|
||||
static const Color lightGreen = Color(0xFF00FF0A);
|
||||
static const Color green = Color(0xFF008905);
|
||||
static const Color grayColor = Color(0xFF999999);
|
||||
static const Color red = Color(0xFFFF0000);
|
||||
static const Color graysColor = Color(0xffEBEBEB);
|
||||
|
@ -5,21 +5,28 @@ abstract class ApiEndpoints {
|
||||
////////////////////////////////////// Authentication ///////////////////////////////
|
||||
static const String signUp = '$baseUrl/authentication/user/signup';
|
||||
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 verifyOtp = '$baseUrl/authentication/user/verify-otp';
|
||||
static const String getRegion = '$baseUrl/region';
|
||||
static const String visitorPassword = '$baseUrl/visitor-password';
|
||||
static const String getDevices = '$baseUrl/visitor-password/devices';
|
||||
|
||||
|
||||
static const String sendOnlineOneTime = '$baseUrl/visitor-password/temporary-password/online/one-time';
|
||||
static const String sendOnlineMultipleTime = '$baseUrl/visitor-password/temporary-password/online/multiple-time';
|
||||
static const String sendOnlineOneTime =
|
||||
'$baseUrl/visitor-password/temporary-password/online/one-time';
|
||||
static const String sendOnlineMultipleTime =
|
||||
'$baseUrl/visitor-password/temporary-password/online/multiple-time';
|
||||
|
||||
//offline Password
|
||||
static const String sendOffLineOneTime = '$baseUrl/visitor-password/temporary-password/offline/one-time';
|
||||
static const String sendOffLineMultipleTime = '$baseUrl/visitor-password/temporary-password/offline/multiple-time';
|
||||
|
||||
static const String sendOffLineOneTime =
|
||||
'$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}';
|
||||
|
||||
////// Devices Management ////////////////
|
||||
|
||||
static const String getAllDevices = '$baseUrl/device';
|
||||
}
|
||||
|
@ -13,10 +13,12 @@ class Assets {
|
||||
static const String rightLine = "assets/images/right_line.png";
|
||||
static const String google = "assets/images/google.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 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 moveinIcon = "assets/images/movein_icon.svg";
|
||||
static const String constructionIcon = "assets/images/construction_icon.svg";
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
enum AccessType {
|
||||
onlineOnetime,
|
||||
onlineMultiple,
|
||||
@ -36,11 +35,6 @@ extension AccessTypeExtension on AccessType {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
enum DeviseStatus {
|
||||
online,
|
||||
offline,
|
||||
@ -53,7 +47,6 @@ extension OnlineTypeExtension on DeviseStatus {
|
||||
return "Online";
|
||||
case DeviseStatus.offline:
|
||||
return "Offline";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,7 +62,6 @@ extension OnlineTypeExtension on DeviseStatus {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum AccessStatus {
|
||||
expired,
|
||||
effective,
|
||||
@ -85,7 +77,6 @@ extension AccessStatusExtension on AccessStatus {
|
||||
return "Effective";
|
||||
case AccessStatus.toBeEffective:
|
||||
return "To be effective";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,8 +93,3 @@ extension AccessStatusExtension on AccessStatus {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
11
lib/utils/format_date_time.dart
Normal file
11
lib/utils/format_date_time.dart
Normal 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)}';
|
||||
}
|
@ -1,13 +1,14 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
||||
class ResponsiveLayout extends StatelessWidget {
|
||||
final Widget desktopBody;
|
||||
final Widget mobileBody;
|
||||
const ResponsiveLayout({super.key,required this.desktopBody,required this.mobileBody});
|
||||
const ResponsiveLayout(
|
||||
{super.key, required this.desktopBody, required this.mobileBody});
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(builder: (context, constraints) {
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
if (constraints.maxWidth < 600) {
|
||||
return mobileBody;
|
||||
} else {
|
||||
|
@ -16,7 +16,6 @@ class CustomSnackBar {
|
||||
BuildContext? currentContext = key?.currentContext;
|
||||
if (key != null && currentContext != null) {
|
||||
final snackBar = SnackBar(
|
||||
|
||||
padding: const EdgeInsets.all(16),
|
||||
backgroundColor: Colors.green,
|
||||
content: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
|
@ -1,7 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'color_manager.dart';
|
||||
|
||||
InputDecoration? textBoxDecoration({bool suffixIcon = false}) => InputDecoration(
|
||||
InputDecoration? textBoxDecoration({bool suffixIcon = false}) =>
|
||||
InputDecoration(
|
||||
focusColor: ColorsManager.grayColor,
|
||||
suffixIcon: suffixIcon ? const Icon(Icons.search) : null,
|
||||
hintText: 'Search',
|
||||
@ -29,18 +30,14 @@ InputDecoration? textBoxDecoration({bool suffixIcon = false}) => InputDecoration
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
BoxDecoration containerDecoration = BoxDecoration(
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withOpacity(0.5),
|
||||
spreadRadius: 5,
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0,
|
||||
3), // changes position of shadow
|
||||
offset: const Offset(0, 3), // changes position of shadow
|
||||
),
|
||||
],
|
||||
color: ColorsManager.boxColor,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(10)));
|
||||
|
||||
|
||||
|
@ -28,23 +28,28 @@ class MenuSidebar extends StatelessWidget {
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text('Community',style: TextStyle(fontSize: 20),),
|
||||
const Text(
|
||||
'Community',
|
||||
style: TextStyle(fontSize: 20),
|
||||
),
|
||||
CircleAvatar(
|
||||
backgroundColor: Colors.grey.shade200,
|
||||
child: IconButton(
|
||||
color: ColorsManager.onSecondaryColor,
|
||||
onPressed: () {},
|
||||
icon: const Icon(Icons.add)
|
||||
),
|
||||
icon: const Icon(Icons.add)),
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20,),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
TextFormField(
|
||||
controller: TextEditingController(),
|
||||
decoration:textBoxDecoration(suffixIcon: true)
|
||||
),
|
||||
Container(height: 100,)
|
||||
decoration: textBoxDecoration(suffixIcon: true)),
|
||||
Container(
|
||||
height: 100,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -3,12 +3,18 @@ import 'package:flutter_svg/svg.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/web_layout/web_app_bar.dart';
|
||||
import 'menu_sidebar.dart';
|
||||
|
||||
class WebScaffold extends StatelessWidget {
|
||||
final bool enableMenuSideba;
|
||||
final Widget? appBarTitle;
|
||||
final List<Widget>? appBarBody;
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@ -22,7 +28,9 @@ class WebScaffold extends StatelessWidget {
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
Container(color: Colors.white.withOpacity(0.7),),
|
||||
Container(
|
||||
color: Colors.white.withOpacity(0.7),
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
@ -31,17 +39,12 @@ class WebScaffold extends StatelessWidget {
|
||||
child: WebAppBar(
|
||||
title: appBarTitle,
|
||||
body: appBarBody,
|
||||
)
|
||||
),
|
||||
)),
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
if(enableMenuSideba)
|
||||
const MenuSidebar(),
|
||||
Expanded(
|
||||
flex: 5,
|
||||
child: scaffoldBody!
|
||||
)
|
||||
if (enableMenuSideba) const MenuSidebar(),
|
||||
Expanded(flex: 5, child: scaffoldBody!)
|
||||
],
|
||||
),
|
||||
)
|
||||
|
Reference in New Issue
Block a user