Compare commits

..

16 Commits

Author SHA1 Message Date
3102c3823a Bug fixes 2024-10-09 21:29:20 +03:00
d5395f4fe7 Merge pull request #39 from SyncrowIOT/bug_fixes_sprint_10
Bug fixes sprint 10
2024-10-09 20:35:05 +03:00
13e90abf76 access_bug_fixes 2024-10-09 17:43:17 +03:00
308c8a44c5 pull changes 2024-10-09 13:29:12 +03:00
7ca6e60d02 fix notification toggle 2024-10-09 13:28:19 +03:00
853cccbcce Merge pull request #36 from SyncrowIOT/bug_fixes_sprint_10
Bug fixes
2024-10-08 23:18:06 +03:00
03dfeabde4 Bug fixes 2024-10-08 23:14:41 +03:00
62e03bac27 Merge pull request #35 from SyncrowIOT/bug_fixes_sprint_10
fix oct/8 issues
2024-10-08 20:41:01 +03:00
79ec890244 fix oct/8 issues 2024-10-08 20:15:52 +03:00
4653c519c4 Merge pull request #34 from SyncrowIOT/bug_fixes_sprint_10
Bug fixes sprint 10
2024-10-08 12:40:26 +03:00
66f6b1cba9 fix bugs 2024-10-08 11:48:35 +03:00
c06f3d5a58 Changed the color of the device control container 2024-10-08 02:19:59 +03:00
813f2f2693 Fixed design issues 2024-10-08 01:56:09 +03:00
d05328e998 Bug fixes 2024-10-07 22:53:18 +03:00
ab22e15736 Merge pull request #33 from SyncrowIOT/garage_water_leack_devices
push water leak device
2024-10-07 11:58:25 +03:00
889d3dbd02 Merge pull request #32 from SyncrowIOT/garage_water_leack_devices
Garage water leack devices
2024-10-07 10:16:18 +03:00
66 changed files with 1496 additions and 1323 deletions

5
assets/icons/1gang.svg Normal file
View File

@ -0,0 +1,5 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M38.0142 39.2553L35.3682 40H20.9308H19.9999H19.0691H1.24111C0.555643 40 0 39.4444 0 38.7589V1.24111C0 0.555643 0.555643 0 1.24111 0H19.0682H20.1226H20.9543H35.4255L38.2625 1.24111C38.9479 1.24111 39.5036 1.79675 39.5036 2.48221L39.2553 38.0142C39.2553 38.6997 38.6997 39.2553 38.0142 39.2553Z" fill="#E9E9E9"/>
<path d="M38.7589 0H35.0356C35.721 0 36.2767 0.555643 36.2767 1.24111V38.7589C36.2767 39.4444 35.721 40 35.0356 40H38.7589C39.4444 40 40 39.4444 40 38.7589V1.24111C40 0.555643 39.4444 0 38.7589 0Z" fill="#D1D1D1"/>
<path opacity="0.6" d="M21.375 31.8319V33.3213C21.375 34.0067 20.9553 34.5624 20.4375 34.5624H16.3125C15.7947 34.5624 15.375 34.0067 15.375 33.3213V31.8319C15.375 31.1465 15.7947 30.5908 16.3125 30.5908H20.4375C20.9553 30.5908 21.375 31.1465 21.375 31.8319Z" fill="#023DFE" fill-opacity="0.5"/>
</svg>

After

Width:  |  Height:  |  Size: 933 B

7
assets/icons/2gang.svg Normal file
View File

@ -0,0 +1,7 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M38.0142 39.2553L35.3682 40H20.9308H19.9999H19.0691H1.24111C0.555643 40 0 39.4444 0 38.7589V1.24111C0 0.555643 0.555643 0 1.24111 0H19.0682H20.1226H20.9543H35.4255L38.2625 1.24111C38.9479 1.24111 39.5036 1.79675 39.5036 2.48221L39.2553 38.0142C39.2553 38.6997 38.6997 39.2553 38.0142 39.2553Z" fill="#E9E9E9"/>
<path d="M38.7589 0H35.0356C35.721 0 36.2767 0.555643 36.2767 1.24111V38.7589C36.2767 39.4444 35.721 40 35.0356 40H38.7589C39.4444 40 40 39.4444 40 38.7589V1.24111C40 0.555643 39.4444 0 38.7589 0Z" fill="#D1D1D1"/>
<path opacity="0.6" d="M12.0284 31.8319V33.3213C12.0284 34.0067 11.6087 34.5624 11.0909 34.5624H6.96594C6.44816 34.5624 6.02844 34.0067 6.02844 33.3213V31.8319C6.02844 31.1465 6.44816 30.5908 6.96594 30.5908H11.0909C11.6087 30.5908 12.0284 31.1465 12.0284 31.8319Z" fill="#023DFE" fill-opacity="0.5"/>
<path opacity="0.6" d="M26.0285 31.8319V33.3213C26.0285 34.0067 26.4482 34.5624 26.966 34.5624H31.091C31.6088 34.5624 32.0285 34.0067 32.0285 33.3213V31.8319C32.0285 31.1465 31.6088 30.5908 31.091 30.5908H26.966C26.4482 30.5908 26.0285 31.1465 26.0285 31.8319Z" fill="#023DFE" fill-opacity="0.5"/>
<path d="M19.0691 0H20.9308V40H19.0691V0Z" fill="#D1D1D1"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -5,7 +5,6 @@ import 'package:syncrow_web/pages/access_management/bloc/access_state.dart';
import 'package:syncrow_web/pages/access_management/model/password_model.dart'; import 'package:syncrow_web/pages/access_management/model/password_model.dart';
import 'package:syncrow_web/pages/common/hour_picker_dialog.dart'; import 'package:syncrow_web/pages/common/hour_picker_dialog.dart';
import 'package:syncrow_web/services/access_mang_api.dart'; import 'package:syncrow_web/services/access_mang_api.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/app_enum.dart'; import 'package:syncrow_web/utils/constants/app_enum.dart';
import 'package:syncrow_web/utils/snack_bar.dart'; import 'package:syncrow_web/utils/snack_bar.dart';
@ -64,8 +63,10 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
} }
} }
Future<void> selectTime(
Future<void> selectTime(SelectTime event, Emitter<AccessState> emit,) async { SelectTime event,
Emitter<AccessState> emit,
) async {
emit(AccessLoaded()); emit(AccessLoaded());
final DateTime? picked = await showDatePicker( final DateTime? picked = await showDatePicker(
context: event.context, context: event.context,
@ -97,7 +98,8 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
} }
} else { } else {
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) { if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) {
CustomSnackBar.displaySnackBar('Expiration Time cannot be earlier than Effective Time.'); CustomSnackBar.displaySnackBar(
'Expiration Time cannot be earlier than Effective Time.');
} else { } else {
endTime = selectedDateTime.toString().split('.').first; endTime = selectedDateTime.toString().split('.').first;
expirationTimeTimeStamp = selectedTimestamp; expirationTimeTimeStamp = selectedTimestamp;
@ -106,14 +108,11 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
} }
} }
emit(ChangeTimeState()); emit(ChangeTimeState());
} }
Future<void> _filterData(FilterDataEvent event, Emitter<AccessState> emit) async { Future<void> _filterData(FilterDataEvent event, Emitter<AccessState> emit) async {
emit(AccessLoaded()); emit(AccessLoaded());
try { try {
print(event.emailAuthorizer?.toLowerCase());
// Convert search text to lower case for case-insensitive search // Convert search text to lower case for case-insensitive search
final searchText = event.passwordName?.toLowerCase() ?? ''; final searchText = event.passwordName?.toLowerCase() ?? '';
final searchEmailText = event.emailAuthorizer?.toLowerCase() ?? ''; final searchEmailText = event.emailAuthorizer?.toLowerCase() ?? '';
@ -128,8 +127,10 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
DateTime.fromMillisecondsSinceEpoch(int.parse(item.invalidTime.toString()) * 1000) DateTime.fromMillisecondsSinceEpoch(int.parse(item.invalidTime.toString()) * 1000)
.toUtc() .toUtc()
.toLocal(); .toLocal();
DateTime effectiveDateAndTime = DateTime(effectiveDate.year, effectiveDate.month, effectiveDate.day,effectiveDate.hour,effectiveDate.minute); DateTime effectiveDateAndTime = DateTime(effectiveDate.year, effectiveDate.month,
DateTime invalidDateAndTime = DateTime(invalidDate.year, invalidDate.month, invalidDate.day,invalidDate.hour,invalidDate.minute); effectiveDate.day, effectiveDate.hour, effectiveDate.minute);
DateTime invalidDateAndTime = DateTime(invalidDate.year, invalidDate.month, invalidDate.day,
invalidDate.hour, invalidDate.minute);
// Filter by password name, making the search case-insensitive // Filter by password name, making the search case-insensitive
if (searchText.isNotEmpty) { if (searchText.isNotEmpty) {
@ -139,7 +140,8 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
} }
} }
if (searchEmailText.isNotEmpty) { if (searchEmailText.isNotEmpty) {
final bool matchesName = item.authorizerEmail.toString().toLowerCase().contains(searchEmailText); final bool matchesName =
item.authorizerEmail.toString().toLowerCase().contains(searchEmailText);
if (!matchesName) { if (!matchesName) {
matchesCriteria = false; matchesCriteria = false;
} }
@ -148,12 +150,8 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
if (event.startTime != null && event.endTime == null) { if (event.startTime != null && event.endTime == null) {
DateTime startDateTime = DateTime startDateTime =
DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal(); DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal();
startDateTime = DateTime( startDateTime = DateTime(startDateTime.year, startDateTime.month, startDateTime.day,
startDateTime.year, startDateTime.hour, startDateTime.minute);
startDateTime.month,
startDateTime.day,
startDateTime.hour,
startDateTime.minute);
if (effectiveDateAndTime.isBefore(startDateTime)) { if (effectiveDateAndTime.isBefore(startDateTime)) {
matchesCriteria = false; matchesCriteria = false;
} }
@ -162,13 +160,8 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
if (event.endTime != null && event.startTime == null) { if (event.endTime != null && event.startTime == null) {
DateTime startDateTime = DateTime startDateTime =
DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000).toUtc().toLocal(); DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000).toUtc().toLocal();
startDateTime = DateTime( startDateTime = DateTime(startDateTime.year, startDateTime.month, startDateTime.day,
startDateTime.year, startDateTime.hour, startDateTime.minute);
startDateTime.month,
startDateTime.day,
startDateTime.hour,
startDateTime.minute
);
if (invalidDateAndTime.isAfter(startDateTime)) { if (invalidDateAndTime.isAfter(startDateTime)) {
matchesCriteria = false; matchesCriteria = false;
} }
@ -180,9 +173,12 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal(); DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal();
DateTime endDateTime = DateTime endDateTime =
DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000).toUtc().toLocal(); DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000).toUtc().toLocal();
startDateTime = DateTime(startDateTime.year, startDateTime.month, startDateTime.day,startDateTime.hour,startDateTime.minute); startDateTime = DateTime(startDateTime.year, startDateTime.month, startDateTime.day,
endDateTime = DateTime(endDateTime.year, endDateTime.month, endDateTime.day,endDateTime.hour,endDateTime.minute); startDateTime.hour, startDateTime.minute);
if (effectiveDateAndTime.isBefore(startDateTime) || invalidDateAndTime.isAfter(endDateTime)) { endDateTime = DateTime(endDateTime.year, endDateTime.month, endDateTime.day,
endDateTime.hour, endDateTime.minute);
if (effectiveDateAndTime.isBefore(startDateTime) ||
invalidDateAndTime.isAfter(endDateTime)) {
matchesCriteria = false; matchesCriteria = false;
} }
} }
@ -205,7 +201,6 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
} }
} }
resetSearch(ResetSearch event, Emitter<AccessState> emit) async { resetSearch(ResetSearch event, Emitter<AccessState> emit) async {
emit(AccessLoaded()); emit(AccessLoaded());
startTime = 'Start Time'; startTime = 'Start Time';
@ -224,7 +219,6 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
" ${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}"; " ${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}";
} }
Future<void> onTabChanged(TabChangedEvent event, Emitter<AccessState> emit) async { Future<void> onTabChanged(TabChangedEvent event, Emitter<AccessState> emit) async {
try { try {
emit(AccessLoaded()); emit(AccessLoaded());
@ -257,6 +251,4 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
emit(FailedState(e.toString())); emit(FailedState(e.toString()));
} }
} }
} }

View File

@ -24,7 +24,6 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isLargeScreen = isLargeScreenSize(context); final isLargeScreen = isLargeScreenSize(context);
final isSmallScreen = isSmallScreenSize(context); final isSmallScreen = isSmallScreenSize(context);
final isHalfMediumScreen = isHafMediumScreenSize(context); final isHalfMediumScreen = isHafMediumScreenSize(context);
@ -169,7 +168,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
} }
Row _buildNormalSearchWidgets(BuildContext context, AccessBloc accessBloc) { Row _buildNormalSearchWidgets(BuildContext context, AccessBloc accessBloc) {
TimeOfDay _selectedTime = TimeOfDay.now(); // TimeOfDay _selectedTime = TimeOfDay.now();
return Row( return Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -268,8 +267,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex, selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
passwordName: accessBloc.passwordName.text.toLowerCase(), passwordName: accessBloc.passwordName.text.toLowerCase(),
startTime: accessBloc.effectiveTimeTimeStamp, startTime: accessBloc.effectiveTimeTimeStamp,
endTime: accessBloc.expirationTimeTimeStamp endTime: accessBloc.expirationTimeTimeStamp));
));
}, },
onReset: () { onReset: () {
accessBloc.add(ResetSearch()); accessBloc.add(ResetSearch());
@ -278,6 +276,4 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
], ],
); );
} }
} }

View File

@ -101,32 +101,19 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
email: forgetEmailController.text, otpCode: forgetOtp.text); email: forgetEmailController.text, otpCode: forgetOtp.text);
if (response == true) { if (response == true) {
await AuthenticationAPI.forgetPassword( await AuthenticationAPI.forgetPassword(
password: forgetPasswordController.text, password: forgetPasswordController.text, email: forgetEmailController.text);
email: forgetEmailController.text);
_timer?.cancel(); _timer?.cancel();
emit(const TimerState(isButtonEnabled: true, remainingTime: 0)); emit(const TimerState(isButtonEnabled: true, remainingTime: 0));
emit(SuccessForgetState()); emit(SuccessForgetState());
} }
} on DioException catch (e) { } on DioException catch (e) {
final errorData = e.response!.data; final errorData = e.response!.data;
String errorMessage = errorData['message']; String errorMessage = errorData['error']['message'] ?? 'something went wrong';
if (errorMessage == 'this email is not registered') { validate = errorMessage;
validate = 'Invalid Credentials!';
emit(AuthInitialState());
} else if (errorMessage == "You entered wrong otp") {
forgetValidate = 'Wrong one time password.';
emit(AuthInitialState());
} else if (errorMessage == "OTP expired") {
forgetValidate = 'One time password has been expired.';
emit(AuthInitialState());
} else {
validate = '';
emit(AuthInitialState()); emit(AuthInitialState());
} }
} }
}
String? validateCode(String? value) { String? validateCode(String? value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Code is required'; return 'Code is required';

View File

@ -48,8 +48,7 @@ class ForgetPasswordWebPage extends StatelessWidget {
late ScrollController _scrollController; late ScrollController _scrollController;
_scrollController = ScrollController(); _scrollController = ScrollController();
void _scrollToCenter() { void _scrollToCenter() {
final double middlePosition = final double middlePosition = _scrollController.position.maxScrollExtent / 2;
_scrollController.position.maxScrollExtent / 2;
_scrollController.animateTo( _scrollController.animateTo(
middlePosition, middlePosition,
duration: const Duration(seconds: 1), duration: const Duration(seconds: 1),
@ -66,8 +65,7 @@ class ForgetPasswordWebPage extends StatelessWidget {
second: Center( second: Center(
child: Stack( child: Stack(
children: [ children: [
if (state is AuthLoading) if (state is AuthLoading) const Center(child: CircularProgressIndicator()),
const Center(child: CircularProgressIndicator()),
ListView( ListView(
shrinkWrap: true, shrinkWrap: true,
controller: _scrollController, controller: _scrollController,
@ -97,21 +95,16 @@ class ForgetPasswordWebPage extends StatelessWidget {
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white.withOpacity(0.1), color: Colors.white.withOpacity(0.1),
borderRadius: borderRadius: const BorderRadius.all(Radius.circular(30)),
const BorderRadius.all(Radius.circular(30)), border: Border.all(color: ColorsManager.graysColor.withOpacity(0.2)),
border: Border.all(
color:
ColorsManager.graysColor.withOpacity(0.2)),
), ),
child: Form( child: Form(
key: forgetBloc.forgetFormKey, key: forgetBloc.forgetFormKey,
child: Padding( child: Padding(
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
horizontal: size.width * 0.02, horizontal: size.width * 0.02, vertical: size.width * 0.003),
vertical: size.width * 0.003),
child: Column( child: Column(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.spaceEvenly,
MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
const SizedBox(height: 10), const SizedBox(height: 10),
@ -128,66 +121,55 @@ class ForgetPasswordWebPage extends StatelessWidget {
style: Theme.of(context) style: Theme.of(context)
.textTheme .textTheme
.bodySmall! .bodySmall!
.copyWith( .copyWith(fontSize: 14, fontWeight: FontWeight.w400),
fontSize: 14,
fontWeight: FontWeight.w400),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
Column( Column(
crossAxisAlignment: crossAxisAlignment: CrossAxisAlignment.start,
CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
const SizedBox(height: 10), const SizedBox(height: 10),
Form( Form(
key: forgetBloc.forgetRegionKey, key: forgetBloc.forgetRegionKey,
child: SizedBox( child: SizedBox(
child: _buildDropdownField( child:
context, forgetBloc, size))) _buildDropdownField(context, forgetBloc, size)))
], ],
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
Form( Form(
key: forgetBloc.forgetEmailKey, key: forgetBloc.forgetEmailKey,
child: Column( child: Column(
crossAxisAlignment: crossAxisAlignment: CrossAxisAlignment.start,
CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.start,
children: [ children: [
Text( Text(
"Account", "Account",
style: Theme.of(context) style: Theme.of(context).textTheme.bodySmall!.copyWith(
.textTheme fontSize: 14, fontWeight: FontWeight.w400),
.bodySmall!
.copyWith(
fontSize: 14,
fontWeight:
FontWeight.w400),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
SizedBox( SizedBox(
child: TextFormField( child: TextFormField(
controller: forgetBloc.forgetEmailController, controller: forgetBloc.forgetEmailController,
validator: forgetBloc.validateEmail, validator: forgetBloc.validateEmail,
decoration: decoration: textBoxDecoration()!.copyWith(
textBoxDecoration()!.copyWith(
hintText: 'Enter your email', hintText: 'Enter your email',
hintStyle: Theme.of(context) hintStyle: Theme.of(context)
.textTheme.bodySmall!.copyWith( .textTheme
.bodySmall!
.copyWith(
color: ColorsManager.grayColor, color: ColorsManager.grayColor,
fontWeight: FontWeight.w400), fontWeight: FontWeight.w400),
), ),
style: const TextStyle( style: const TextStyle(color: Colors.black),
color: Colors.black),
), ),
), ),
], ],
)), )),
const SizedBox(height: 20.0), const SizedBox(height: 20.0),
Column( Column(
crossAxisAlignment: crossAxisAlignment: CrossAxisAlignment.start,
CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Text( Text(
@ -195,22 +177,20 @@ class ForgetPasswordWebPage extends StatelessWidget {
style: Theme.of(context) style: Theme.of(context)
.textTheme .textTheme
.bodySmall! .bodySmall!
.copyWith( .copyWith(fontSize: 14, fontWeight: FontWeight.w400),
fontSize: 14,
fontWeight: FontWeight.w400),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
SizedBox( SizedBox(
child: TextFormField( child: TextFormField(
validator: forgetBloc.validateCode, validator: forgetBloc.validateCode,
keyboardType: keyboardType: TextInputType.visiblePassword,
TextInputType.visiblePassword,
controller: forgetBloc.forgetOtp, controller: forgetBloc.forgetOtp,
decoration: decoration: textBoxDecoration()!.copyWith(
textBoxDecoration()!.copyWith(
hintText: 'Enter Code', hintText: 'Enter Code',
hintStyle: Theme.of(context).textTheme hintStyle: Theme.of(context)
.bodySmall!.copyWith( .textTheme
.bodySmall!
.copyWith(
color: ColorsManager.grayColor, color: ColorsManager.grayColor,
fontWeight: FontWeight.w400), fontWeight: FontWeight.w400),
suffixIcon: SizedBox( suffixIcon: SizedBox(
@ -222,8 +202,15 @@ class ForgetPasswordWebPage extends StatelessWidget {
state.remainingTime != 1 state.remainingTime != 1
? null ? null
: () { : () {
if (forgetBloc.forgetEmailKey.currentState!.validate()||forgetBloc.forgetRegionKey.currentState!.validate()) { if (forgetBloc
if(forgetBloc.forgetRegionKey.currentState!.validate()){ .forgetEmailKey.currentState!
.validate() ||
forgetBloc
.forgetRegionKey.currentState!
.validate()) {
if (forgetBloc
.forgetRegionKey.currentState!
.validate()) {
forgetBloc.add(StartTimerEvent()); forgetBloc.add(StartTimerEvent());
} }
} }
@ -231,28 +218,23 @@ class ForgetPasswordWebPage extends StatelessWidget {
child: Text( child: Text(
'Get Code ${state is TimerState && !state.isButtonEnabled && state.remainingTime != 1 ? "(${forgetBloc.formattedTime(state.remainingTime)}) " : ""}', 'Get Code ${state is TimerState && !state.isButtonEnabled && state.remainingTime != 1 ? "(${forgetBloc.formattedTime(state.remainingTime)}) " : ""}',
style: TextStyle( style: TextStyle(
color: state color: state is TimerState &&
is TimerState && !state.isButtonEnabled
!state
.isButtonEnabled
? Colors.grey ? Colors.grey
: ColorsManager : ColorsManager.btnColor,
.btnColor,
), ),
), ),
), ),
), ),
), ),
), ),
style: const TextStyle( style: const TextStyle(color: Colors.black),
color: Colors.black),
), ),
), ),
if (forgetBloc.forgetValidate != if (forgetBloc.forgetValidate !=
'') // Check if there is a validation message '') // Check if there is a validation message
Padding( Padding(
padding: padding: const EdgeInsets.only(top: 8.0),
const EdgeInsets.only(top: 8.0),
child: Text( child: Text(
forgetBloc.forgetValidate, forgetBloc.forgetValidate,
style: const TextStyle( style: const TextStyle(
@ -265,8 +247,7 @@ class ForgetPasswordWebPage extends StatelessWidget {
), ),
const SizedBox(height: 20.0), const SizedBox(height: 20.0),
Column( Column(
crossAxisAlignment: crossAxisAlignment: CrossAxisAlignment.start,
CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Text( Text(
@ -274,35 +255,26 @@ class ForgetPasswordWebPage extends StatelessWidget {
style: Theme.of(context) style: Theme.of(context)
.textTheme .textTheme
.bodySmall! .bodySmall!
.copyWith( .copyWith(fontSize: 14, fontWeight: FontWeight.w400),
fontSize: 14,
fontWeight: FontWeight.w400),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
SizedBox( SizedBox(
child: TextFormField( child: TextFormField(
obscureText: forgetBloc.obscureText, obscureText: forgetBloc.obscureText,
keyboardType: keyboardType: TextInputType.visiblePassword,
TextInputType.visiblePassword, validator: forgetBloc.passwordValidator,
validator: controller: forgetBloc.forgetPasswordController,
forgetBloc.passwordValidator, decoration: textBoxDecoration()!.copyWith(
controller: forgetBloc
.forgetPasswordController,
decoration:
textBoxDecoration()!.copyWith(
suffixIcon: IconButton( suffixIcon: IconButton(
onPressed: () { onPressed: () {
forgetBloc.add( forgetBloc.add(PasswordVisibleEvent(
PasswordVisibleEvent( newValue: forgetBloc.obscureText));
newValue: forgetBloc
.obscureText));
}, },
icon: SizedBox( icon: SizedBox(
child: SvgPicture.asset( child: SvgPicture.asset(
forgetBloc.obscureText forgetBloc.obscureText
? Assets.visiblePassword ? Assets.visiblePassword
: Assets : Assets.invisiblePassword,
.invisiblePassword,
height: 15, height: 15,
width: 15, width: 15,
), ),
@ -313,13 +285,10 @@ class ForgetPasswordWebPage extends StatelessWidget {
.textTheme .textTheme
.bodySmall! .bodySmall!
.copyWith( .copyWith(
color: color: ColorsManager.grayColor,
ColorsManager.grayColor, fontWeight: FontWeight.w400),
fontWeight:
FontWeight.w400),
), ),
style: const TextStyle( style: const TextStyle(color: Colors.black),
color: Colors.black),
), ),
), ),
], ],
@ -329,21 +298,22 @@ class ForgetPasswordWebPage extends StatelessWidget {
), ),
const SizedBox(height: 20.0), const SizedBox(height: 20.0),
Row( Row(
crossAxisAlignment: crossAxisAlignment: CrossAxisAlignment.center,
CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
SizedBox( SizedBox(
width: size.width * 0.2, width: size.width * 0.2,
child: DefaultButton( child: DefaultButton(
backgroundColor: backgroundColor: ColorsManager.btnColor,
ColorsManager.btnColor,
child: const Text('Submit'), child: const Text('Submit'),
onPressed: () { onPressed: () {
if (forgetBloc.forgetFormKey.currentState!.validate() || if (forgetBloc.forgetFormKey.currentState!.validate() ||
forgetBloc.forgetEmailKey.currentState!.validate() ) { forgetBloc.forgetEmailKey.currentState!
if( forgetBloc.forgetEmailKey.currentState!.validate() .validate()) {
&&forgetBloc.forgetFormKey.currentState!.validate() ){ if (forgetBloc.forgetEmailKey.currentState!
.validate() &&
forgetBloc.forgetFormKey.currentState!
.validate()) {
forgetBloc.add(ChangePasswordEvent()); forgetBloc.add(ChangePasswordEvent());
} }
} }
@ -358,8 +328,7 @@ class ForgetPasswordWebPage extends StatelessWidget {
child: Text( child: Text(
forgetBloc.validate, forgetBloc.validate,
style: const TextStyle( style: const TextStyle(
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700, color: ColorsManager.red),
color: ColorsManager.red),
), ),
), ),
), ),
@ -372,8 +341,7 @@ class ForgetPasswordWebPage extends StatelessWidget {
children: [ children: [
const Text( const Text(
"Do you have an account? ", "Do you have an account? ",
style: style: TextStyle(color: Colors.white),
TextStyle(color: Colors.white),
), ),
InkWell( InkWell(
onTap: () { onTap: () {
@ -407,8 +375,7 @@ class ForgetPasswordWebPage extends StatelessWidget {
)); ));
} }
Widget _buildDropdownField( Widget _buildDropdownField(BuildContext context, AuthBloc loginBloc, Size size) {
BuildContext context, AuthBloc loginBloc, Size size) {
final TextEditingController textEditingController = TextEditingController(); final TextEditingController textEditingController = TextEditingController();
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -434,13 +401,10 @@ class ForgetPasswordWebPage extends StatelessWidget {
builder: (FormFieldState<String> field) { builder: (FormFieldState<String> field) {
return InputDecorator( return InputDecorator(
decoration: InputDecoration( decoration: InputDecoration(
contentPadding: contentPadding: const EdgeInsets.symmetric(horizontal: 2, vertical: 10),
const EdgeInsets.symmetric(horizontal: 2, vertical: 10),
errorText: field.errorText, errorText: field.errorText,
filled: filled: true, // Ensure the dropdown is filled with the background color
true, // Ensure the dropdown is filled with the background color fillColor: ColorsManager.boxColor, // Match the dropdown container color
fillColor: ColorsManager
.boxColor, // Match the dropdown container color
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0), borderRadius: BorderRadius.circular(8.0),
borderSide: BorderSide( borderSide: BorderSide(
@ -451,22 +415,20 @@ class ForgetPasswordWebPage extends StatelessWidget {
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0), borderRadius: BorderRadius.circular(8.0),
borderSide: BorderSide( borderSide: BorderSide(
color: color: field.hasError ? Colors.red : ColorsManager.grayColor,
field.hasError ? Colors.red : ColorsManager.grayColor,
width: 1.5, width: 1.5,
), ),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0), borderRadius: BorderRadius.circular(8.0),
borderSide: BorderSide( borderSide: BorderSide(
color: color: field.hasError ? Colors.red : ColorsManager.grayColor,
field.hasError ? Colors.red : ColorsManager.grayColor,
width: 1.5, width: 1.5,
), ),
), ),
errorBorder: OutlineInputBorder( errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0), borderRadius: BorderRadius.circular(8.0),
borderSide: BorderSide( borderSide: const BorderSide(
color: Colors.red, color: Colors.red,
width: 1.5, width: 1.5,
), ),
@ -497,15 +459,13 @@ class ForgetPasswordWebPage extends StatelessWidget {
), ),
); );
}).toList(), }).toList(),
value: loginBloc.regionList! value: loginBloc.regionList!.any((region) => region.id == loginBloc.regionUuid)
.any((region) => region.id == loginBloc.regionUuid)
? loginBloc.regionUuid ? loginBloc.regionUuid
: null, : null,
onChanged: (String? value) { onChanged: (String? value) {
if (value != null) { if (value != null) {
loginBloc.add(SelectRegionEvent(val: value)); loginBloc.add(SelectRegionEvent(val: value));
field.didChange( field.didChange(value); // Notify the form field of the change
value); // Notify the form field of the change
} }
}, },
buttonStyleData: const ButtonStyleData( buttonStyleData: const ButtonStyleData(
@ -529,8 +489,7 @@ class ForgetPasswordWebPage extends StatelessWidget {
searchInnerWidgetHeight: 50, searchInnerWidgetHeight: 50,
searchInnerWidget: Container( searchInnerWidget: Container(
height: 50, height: 50,
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
horizontal: 8, vertical: 4),
child: TextFormField( child: TextFormField(
style: const TextStyle(color: Colors.black), style: const TextStyle(color: Colors.black),
controller: textEditingController, controller: textEditingController,
@ -544,8 +503,7 @@ class ForgetPasswordWebPage extends StatelessWidget {
), ),
), ),
searchMatchFn: (item, searchValue) { searchMatchFn: (item, searchValue) {
final regionName = final regionName = (item.child as Text).data?.toLowerCase() ?? '';
(item.child as Text).data?.toLowerCase() ?? '';
final search = searchValue.toLowerCase().trim(); final search = searchValue.toLowerCase().trim();
return regionName.contains(search); return regionName.contains(search);
}, },
@ -564,6 +522,4 @@ class ForgetPasswordWebPage extends StatelessWidget {
], ],
); );
} }
} }

View File

@ -24,8 +24,7 @@ class LoginWebPage extends StatefulWidget {
State<LoginWebPage> createState() => _LoginWebPageState(); State<LoginWebPage> createState() => _LoginWebPageState();
} }
class _LoginWebPageState extends State<LoginWebPage> class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout {
with HelperResponsiveLayout {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -60,8 +59,7 @@ class _LoginWebPageState extends State<LoginWebPage>
_scrollController = ScrollController(); _scrollController = ScrollController();
void _scrollToCenter() { void _scrollToCenter() {
final double middlePosition = final double middlePosition = _scrollController.position.maxScrollExtent / 2;
_scrollController.position.maxScrollExtent / 2;
_scrollController.animateTo( _scrollController.animateTo(
middlePosition, middlePosition,
duration: const Duration(seconds: 1), duration: const Duration(seconds: 1),
@ -123,8 +121,7 @@ class _LoginWebPageState extends State<LoginWebPage>
const Spacer(), const Spacer(),
Expanded( Expanded(
flex: 2, flex: 2,
child: _buildLoginFormFields( child: _buildLoginFormFields(context, loginBloc, size),
context, loginBloc, size),
), ),
const Spacer(), const Spacer(),
], ],
@ -135,14 +132,12 @@ class _LoginWebPageState extends State<LoginWebPage>
), ),
), ),
), ),
if (state is AuthLoading) if (state is AuthLoading) const Center(child: CircularProgressIndicator())
const Center(child: CircularProgressIndicator())
], ],
); );
} }
Widget _buildLoginFormFields( Widget _buildLoginFormFields(BuildContext context, AuthBloc loginBloc, Size size) {
BuildContext context, AuthBloc loginBloc, Size size) {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white.withOpacity(0.1), color: Colors.white.withOpacity(0.1),
@ -152,8 +147,8 @@ class _LoginWebPageState extends State<LoginWebPage>
child: Form( child: Form(
key: loginBloc.loginFormKey, key: loginBloc.loginFormKey,
child: Padding( child: Padding(
padding: EdgeInsets.symmetric( padding:
horizontal: size.width * 0.02, vertical: size.width * 0.003), EdgeInsets.symmetric(horizontal: size.width * 0.02, vertical: size.width * 0.003),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -181,9 +176,7 @@ class _LoginWebPageState extends State<LoginWebPage>
); );
} }
Widget _buildDropdownField(BuildContext context, AuthBloc loginBloc, Size size) {
Widget _buildDropdownField(
BuildContext context, AuthBloc loginBloc, Size size) {
final TextEditingController textEditingController = TextEditingController(); final TextEditingController textEditingController = TextEditingController();
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -227,7 +220,8 @@ class _LoginWebPageState extends State<LoginWebPage>
); );
}).toList(), }).toList(),
value: loginBloc.regionList!.any( value: loginBloc.regionList!.any(
(region) => region.id == loginBloc.regionUuid,) (region) => region.id == loginBloc.regionUuid,
)
? loginBloc.regionUuid ? loginBloc.regionUuid
: null, : null,
onChanged: (String? value) { onChanged: (String? value) {
@ -286,7 +280,6 @@ class _LoginWebPageState extends State<LoginWebPage>
); );
} }
Widget _buildEmailField(BuildContext context, AuthBloc loginBloc) { Widget _buildEmailField(BuildContext context, AuthBloc loginBloc) {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -310,9 +303,10 @@ class _LoginWebPageState extends State<LoginWebPage>
decoration: textBoxDecoration()!.copyWith( decoration: textBoxDecoration()!.copyWith(
errorStyle: const TextStyle(height: 0), errorStyle: const TextStyle(height: 0),
hintText: 'Enter your email address', hintText: 'Enter your email address',
hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith( hintStyle: Theme.of(context)
color: ColorsManager.grayColor, .textTheme
fontWeight: FontWeight.w400)), .bodySmall!
.copyWith(color: ColorsManager.grayColor, fontWeight: FontWeight.w400)),
style: const TextStyle(color: Colors.black), style: const TextStyle(color: Colors.black),
), ),
), ),
@ -344,18 +338,17 @@ class _LoginWebPageState extends State<LoginWebPage>
controller: loginBloc.loginPasswordController, controller: loginBloc.loginPasswordController,
decoration: textBoxDecoration()!.copyWith( decoration: textBoxDecoration()!.copyWith(
hintText: 'At least 8 characters', hintText: 'At least 8 characters',
hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith( hintStyle: Theme.of(context)
color: ColorsManager.grayColor, fontWeight: FontWeight.w400), .textTheme
.bodySmall!
.copyWith(color: ColorsManager.grayColor, fontWeight: FontWeight.w400),
suffixIcon: IconButton( suffixIcon: IconButton(
onPressed: () { onPressed: () {
loginBloc.add( loginBloc.add(PasswordVisibleEvent(newValue: loginBloc.obscureText));
PasswordVisibleEvent(newValue: loginBloc.obscureText));
}, },
icon: SizedBox( icon: SizedBox(
child: SvgPicture.asset( child: SvgPicture.asset(
loginBloc.obscureText loginBloc.obscureText ? Assets.visiblePassword : Assets.invisiblePassword,
? Assets.visiblePassword
: Assets.invisiblePassword,
height: 15, height: 15,
width: 15, width: 15,
), ),
@ -383,10 +376,10 @@ class _LoginWebPageState extends State<LoginWebPage>
}, },
child: Text( child: Text(
"Forgot Password?", "Forgot Password?",
style: Theme.of(context).textTheme.bodySmall!.copyWith( style: Theme.of(context)
color: Colors.black, .textTheme
fontSize: 14, .bodySmall!
fontWeight: FontWeight.w400), .copyWith(color: Colors.black, fontSize: 14, fontWeight: FontWeight.w400),
), ),
), ),
], ],
@ -450,8 +443,7 @@ class _LoginWebPageState extends State<LoginWebPage>
); );
} }
Widget _buildSignInButton( Widget _buildSignInButton(BuildContext context, AuthBloc loginBloc, Size size) {
BuildContext context, AuthBloc loginBloc, Size size) {
return Row( return Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@ -492,8 +484,7 @@ class _LoginWebPageState extends State<LoginWebPage>
SizedBox( SizedBox(
child: Text( child: Text(
loginBloc.validate, loginBloc.validate,
style: const TextStyle( style: const TextStyle(fontWeight: FontWeight.w700, color: ColorsManager.red),
fontWeight: FontWeight.w700, color: ColorsManager.red),
), ),
) )
], ],

View File

@ -0,0 +1,304 @@
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';
class AccessDeviceTable extends StatefulWidget {
final List<String> headers;
final String? tableName;
final List<List<dynamic>> data;
final BoxDecoration? headerDecoration;
final BoxDecoration? cellDecoration;
final Size size;
final bool withCheckBox;
final bool withSelectAll;
final bool isEmpty;
final void Function(bool?)? selectAll;
final void Function(int, bool, dynamic)? onRowSelected;
final List<String>? initialSelectedIds;
final int uuidIndex;
const AccessDeviceTable({
super.key,
required this.headers,
required this.data,
required this.size,
this.tableName,
required this.isEmpty,
required this.withCheckBox,
required this.withSelectAll,
this.headerDecoration,
this.cellDecoration,
this.selectAll,
this.onRowSelected,
this.initialSelectedIds,
required this.uuidIndex,
});
@override
_DynamicTableState createState() => _DynamicTableState();
}
class _DynamicTableState extends State<AccessDeviceTable> {
late List<bool> _selected;
bool _selectAll = false;
@override
void initState() {
super.initState();
_initializeSelection();
}
@override
void didUpdateWidget(AccessDeviceTable oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.data != widget.data) {
_initializeSelection();
}
}
void _initializeSelection() {
if (widget.data.isEmpty) {
_selected = [];
_selectAll = false;
} else {
_selected = List<bool>.generate(widget.data.length, (index) {
// Check if the initialSelectedIds contains the deviceUuid
// uuidIndex is the index of the column containing the deviceUuid
final deviceUuid = widget.data[index][widget.uuidIndex];
return widget.initialSelectedIds != null &&
widget.initialSelectedIds!.contains(deviceUuid);
});
_selectAll = _selected.every((element) => element == true);
}
}
void _toggleRowSelection(int index) {
setState(() {
_selected[index] = !_selected[index];
if (widget.onRowSelected != null) {
widget.onRowSelected!(index, _selected[index], widget.data[index]);
}
});
}
void _toggleSelectAll(bool? value) {
setState(() {
_selectAll = value ?? false;
_selected = List<bool>.filled(widget.data.length, _selectAll);
if (widget.selectAll != null) {
widget.selectAll!(_selectAll);
}
});
}
@override
Widget build(BuildContext context) {
return Container(
decoration: widget.cellDecoration,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SizedBox(
width: widget.size.width,
child: Column(
children: [
Container(
decoration: widget.headerDecoration ??
BoxDecoration(color: Colors.grey[200]),
child: Row(
children: [
if (widget.withCheckBox) _buildSelectAllCheckbox(),
...widget.headers
.map((header) => _buildTableHeaderCell(header)),
],
),
),
widget.isEmpty
? Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
children: [
SvgPicture.asset(Assets.emptyTable),
const SizedBox(
height: 15,
),
Text(
// no password
widget.tableName == 'AccessManagement'
? 'No Password '
: 'No Devices',
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
color: ColorsManager.grayColor),
)
],
),
],
),
],
),
)
: Expanded(
child: Container(
color: Colors.white,
child: ListView.builder(
shrinkWrap: true,
itemCount: widget.data.length,
itemBuilder: (context, index) {
final row = widget.data[index];
return Row(
children: [
if (widget.withCheckBox)
_buildRowCheckbox(
index, widget.size.height * 0.10),
...row.map((cell) => _buildTableCell(
cell.toString(),
widget.size.height * 0.10)),
],
);
},
),
),
),
],
),
),
),
);
}
Widget _buildSelectAllCheckbox() {
return Container(
width: 50,
padding: const EdgeInsets.all(8.0),
decoration: const BoxDecoration(
border: Border.symmetric(
vertical: BorderSide(color: ColorsManager.boxDivider),
),
),
child: Checkbox(
value: widget.data.isNotEmpty &&
_selected.every((element) => element == true),
onChanged: widget.withSelectAll && widget.data.isNotEmpty
? _toggleSelectAll
: null,
),
);
}
Widget _buildRowCheckbox(int index, double size) {
return Container(
width: 50,
padding: const EdgeInsets.all(8.0),
height: size,
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(
color: ColorsManager.boxDivider,
width: 1.0,
),
),
),
alignment: Alignment.centerLeft,
child: Center(
child: Checkbox(
value: _selected[index],
onChanged: (bool? value) {
_toggleRowSelection(index);
},
),
),
);
}
Widget _buildTableHeaderCell(String title) {
return Expanded(
child: Container(
decoration: const BoxDecoration(
border: Border.symmetric(
vertical: BorderSide(color: ColorsManager.boxDivider),
),
),
alignment: Alignment.centerLeft,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
title,
style: const TextStyle(
fontWeight: FontWeight.w400,
fontSize: 13,
color: Color(0xFF999999),
),
maxLines: 2,
),
),
),
);
}
Widget _buildTableCell(String content, double size) {
bool isBatteryLevel = content.endsWith('%');
double? batteryLevel;
if (isBatteryLevel) {
batteryLevel = double.tryParse(content.replaceAll('%', '').trim());
}
Color? statusColor;
switch (content) {
case 'Effective':
statusColor = ColorsManager.textGreen;
break;
case 'Expired':
statusColor = ColorsManager.red;
break;
case 'To be effective':
statusColor = ColorsManager.yaGreen;
break;
case 'Online':
statusColor = ColorsManager.green;
break;
case 'Offline':
statusColor = ColorsManager.red;
break;
default:
statusColor = Colors.black;
}
return Expanded(
child: Container(
height: size,
padding: const EdgeInsets.all(5.0),
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(
color: ColorsManager.boxDivider,
width: 1.0,
),
),
),
alignment: Alignment.centerLeft,
child: Text(
content,
style: TextStyle(
color: (batteryLevel != null && batteryLevel < 20)
? ColorsManager.red
: (batteryLevel != null && batteryLevel > 20)
? ColorsManager.green
: statusColor,
fontSize: 10,
fontWeight: FontWeight.w400),
maxLines: 2,
),
),
);
}
}

View File

@ -1,6 +1,6 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_web/pages/device_managment/shared/device_controls_container.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/assets.dart';
@ -22,13 +22,7 @@ class CurtainToggle extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return DeviceControlsContainer(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: ColorsManager.greyColor.withOpacity(0.2),
border: Border.all(color: ColorsManager.boxDivider),
),
padding: const EdgeInsets.all(16),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [

View File

@ -1,5 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_managment_bloc.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/assets.dart';
@ -53,30 +55,47 @@ class _DynamicTableState extends State<DynamicTable> {
@override @override
void didUpdateWidget(DynamicTable oldWidget) { void didUpdateWidget(DynamicTable oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
if (oldWidget.data.length != widget.data.length) { if (!_compareListOfLists(oldWidget.data, widget.data)) {
_initializeSelection(); _initializeSelection();
} }
} }
bool _compareListOfLists(List<List<dynamic>> oldList, List<List<dynamic>> newList) {
// Check if the old and new lists are the same
if (oldList.length != newList.length) return false;
for (int i = 0; i < oldList.length; i++) {
if (oldList[i].length != newList[i].length) return false;
for (int j = 0; j < oldList[i].length; j++) {
if (oldList[i][j] != newList[i][j]) return false;
}
}
return true;
}
void _initializeSelection() { void _initializeSelection() {
_selectedRows = List<bool>.filled(widget.data.length, false); _selectedRows = List<bool>.filled(widget.data.length, false);
_selectAll = false; _selectAll = false;
} }
void _toggleSelectAll(bool? value) {
setState(() {
_selectAll = value ?? false;
_selectedRows = List<bool>.filled(widget.data.length, _selectAll);
});
widget.onSelectionChanged?.call(_selectedRows);
}
void _toggleRowSelection(int index) { void _toggleRowSelection(int index) {
setState(() { setState(() {
_selectedRows[index] = !_selectedRows[index]; _selectedRows[index] = !_selectedRows[index];
_selectAll = _selectedRows.every((isSelected) => isSelected); _selectAll = _selectedRows.every((isSelected) => isSelected);
}); });
widget.onSelectionChanged?.call(_selectedRows); widget.onSelectionChanged?.call(_selectedRows);
context.read<DeviceManagementBloc>().add(UpdateSelection(_selectedRows));
}
void _toggleSelectAll(bool? value) {
setState(() {
_selectAll = value ?? false;
_selectedRows = List<bool>.filled(widget.data.length, _selectAll);
});
widget.onSelectionChanged?.call(_selectedRows);
context.read<DeviceManagementBloc>().add(UpdateSelection(_selectedRows));
} }
@override @override
@ -90,13 +109,11 @@ class _DynamicTableState extends State<DynamicTable> {
child: Column( child: Column(
children: [ children: [
Container( Container(
decoration: widget.headerDecoration ?? decoration: widget.headerDecoration ?? BoxDecoration(color: Colors.grey[200]),
BoxDecoration(color: Colors.grey[200]),
child: Row( child: Row(
children: [ children: [
if (widget.withCheckBox) _buildSelectAllCheckbox(), if (widget.withCheckBox) _buildSelectAllCheckbox(),
...widget.headers ...widget.headers.map((header) => _buildTableHeaderCell(header)),
.map((header) => _buildTableHeaderCell(header)),
], ],
), ),
), ),
@ -117,14 +134,9 @@ class _DynamicTableState extends State<DynamicTable> {
), ),
Text( Text(
// no password // no password
widget.tableName == 'AccessManagement' widget.tableName == 'AccessManagement' ? 'No Password ' : 'No Devices',
? 'No Password ' style:
: 'No Devices', Theme.of(context).textTheme.bodySmall!.copyWith(color: ColorsManager.grayColor),
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
color: ColorsManager.grayColor),
) )
], ],
), ),
@ -143,12 +155,8 @@ class _DynamicTableState extends State<DynamicTable> {
final row = widget.data[index]; final row = widget.data[index];
return Row( return Row(
children: [ children: [
if (widget.withCheckBox) if (widget.withCheckBox) _buildRowCheckbox(index, widget.size.height * 0.10),
_buildRowCheckbox( ...row.map((cell) => _buildTableCell(cell.toString(), widget.size.height * 0.10)),
index, widget.size.height * 0.10),
...row.map((cell) => _buildTableCell(
cell.toString(),
widget.size.height * 0.10)),
], ],
); );
}, },
@ -173,9 +181,7 @@ class _DynamicTableState extends State<DynamicTable> {
), ),
child: Checkbox( child: Checkbox(
value: _selectAll, value: _selectAll,
onChanged: widget.withSelectAll && widget.data.isNotEmpty onChanged: widget.withSelectAll && widget.data.isNotEmpty ? _toggleSelectAll : null,
? _toggleSelectAll
: null,
), ),
); );
} }

View File

@ -2,20 +2,21 @@ import 'package:flutter/material.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/extension/build_context_x.dart';
class StatefulTextField extends StatefulWidget { class StatefulTextField extends StatefulWidget {
const StatefulTextField({ const StatefulTextField(
super.key, {super.key,
required this.title, required this.title,
this.hintText = 'Please enter', this.hintText = 'Please enter',
required this.width, required this.width,
this.elevation = 0, this.elevation = 0,
required this.controller, required this.controller,
}); this.onSubmitted});
final String title; final String title;
final String hintText; final String hintText;
final double width; final double width;
final double elevation; final double elevation;
final TextEditingController controller; final TextEditingController controller;
final Function? onSubmitted;
@override @override
State<StatefulTextField> createState() => _StatefulTextFieldState(); State<StatefulTextField> createState() => _StatefulTextFieldState();
@ -30,25 +31,26 @@ class _StatefulTextFieldState extends State<StatefulTextField> {
hintText: widget.hintText, hintText: widget.hintText,
width: widget.width, width: widget.width,
elevation: widget.elevation, elevation: widget.elevation,
); onSubmittedFun: widget.onSubmitted);
} }
} }
class CustomTextField extends StatelessWidget { class CustomTextField extends StatelessWidget {
const CustomTextField({ const CustomTextField(
super.key, {super.key,
required this.title, required this.title,
required this.controller, required this.controller,
this.hintText = 'Please enter', this.hintText = 'Please enter',
required this.width, required this.width,
this.elevation = 0, this.elevation = 0,
}); this.onSubmittedFun});
final String title; final String title;
final TextEditingController controller; final TextEditingController controller;
final String hintText; final String hintText;
final double width; final double width;
final double elevation; final double elevation;
final Function? onSubmittedFun;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -81,10 +83,12 @@ class CustomTextField extends StatelessWidget {
decoration: InputDecoration( decoration: InputDecoration(
hintText: hintText, hintText: hintText,
hintStyle: const TextStyle(fontSize: 12), hintStyle: const TextStyle(fontSize: 12),
contentPadding: contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
border: InputBorder.none, border: InputBorder.none,
), ),
onFieldSubmitted: (_) {
onSubmittedFun!();
},
), ),
), ),
), ),

View File

@ -15,8 +15,7 @@ import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/extension/build_context_x.dart';
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
class AcDeviceBatchControlView extends StatelessWidget class AcDeviceBatchControlView extends StatelessWidget with HelperResponsiveLayout {
with HelperResponsiveLayout {
const AcDeviceBatchControlView({super.key, required this.devicesIds}); const AcDeviceBatchControlView({super.key, required this.devicesIds});
final List<String> devicesIds; final List<String> devicesIds;
@ -27,8 +26,7 @@ class AcDeviceBatchControlView extends StatelessWidget
final isLarge = isLargeScreenSize(context); final isLarge = isLargeScreenSize(context);
final isMedium = isMediumScreenSize(context); final isMedium = isMediumScreenSize(context);
return BlocProvider( return BlocProvider(
create: (context) => AcBloc(deviceId: devicesIds.first) create: (context) => AcBloc(deviceId: devicesIds.first)..add(AcFetchBatchStatusEvent(devicesIds)),
..add(AcFetchBatchStatusEvent(devicesIds)),
child: BlocBuilder<AcBloc, AcsState>( child: BlocBuilder<AcBloc, AcsState>(
builder: (context, state) { builder: (context, state) {
if (state is ACStatusLoaded) { if (state is ACStatusLoaded) {
@ -66,6 +64,7 @@ class AcDeviceBatchControlView extends StatelessWidget
tempSet: state.status.tempSet, tempSet: state.status.tempSet,
code: 'temp_set', code: 'temp_set',
devicesIds: devicesIds, devicesIds: devicesIds,
isBatch: true,
), ),
BatchAcMode( BatchAcMode(
value: state.status.acMode, value: state.status.acMode,
@ -99,8 +98,7 @@ class AcDeviceBatchControlView extends StatelessWidget
), ),
Text( Text(
'h', 'h',
style: context.textTheme.bodySmall! style: context.textTheme.bodySmall!.copyWith(color: ColorsManager.blackColor),
.copyWith(color: ColorsManager.blackColor),
), ),
Text( Text(
'30', '30',
@ -109,9 +107,7 @@ class AcDeviceBatchControlView extends StatelessWidget
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
Text('m', Text('m', style: context.textTheme.bodySmall!.copyWith(color: ColorsManager.blackColor)),
style: context.textTheme.bodySmall!
.copyWith(color: ColorsManager.blackColor)),
IconButton( IconButton(
onPressed: () {}, onPressed: () {},
icon: const Icon( icon: const Icon(
@ -133,7 +129,7 @@ class AcDeviceBatchControlView extends StatelessWidget
code: 'child_lock', code: 'child_lock',
value: state.status.childLock, value: state.status.childLock,
label: 'Child Lock', label: 'Child Lock',
icon: state.status.childLock ? Assets.unlock : Assets.acLock, icon: state.status.childLock ? Assets.acLock : Assets.unlock,
onChange: (value) { onChange: (value) {
context.read<AcBloc>().add(AcBatchControlEvent( context.read<AcBloc>().add(AcBatchControlEvent(
devicesIds: devicesIds, devicesIds: devicesIds,
@ -147,8 +143,7 @@ class AcDeviceBatchControlView extends StatelessWidget
callFactoryReset: () { callFactoryReset: () {
context.read<AcBloc>().add(AcFactoryResetEvent( context.read<AcBloc>().add(AcFactoryResetEvent(
deviceId: state.status.uuid, deviceId: state.status.uuid,
factoryResetModel: factoryResetModel: FactoryResetModel(devicesUuid: devicesIds),
FactoryResetModel(devicesUuid: devicesIds),
)); ));
}, },
), ),

View File

@ -24,8 +24,7 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
final isLarge = isLargeScreenSize(context); final isLarge = isLargeScreenSize(context);
final isMedium = isMediumScreenSize(context); final isMedium = isMediumScreenSize(context);
return BlocProvider( return BlocProvider(
create: (context) => AcBloc(deviceId: device.uuid!) create: (context) => AcBloc(deviceId: device.uuid!)..add(AcFetchDeviceStatusEvent(device.uuid!)),
..add(AcFetchDeviceStatusEvent(device.uuid!)),
child: BlocBuilder<AcBloc, AcsState>( child: BlocBuilder<AcBloc, AcsState>(
builder: (context, state) { builder: (context, state) {
if (state is ACStatusLoaded) { if (state is ACStatusLoaded) {
@ -98,8 +97,7 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
), ),
Text( Text(
'h', 'h',
style: context.textTheme.bodySmall! style: context.textTheme.bodySmall!.copyWith(color: ColorsManager.blackColor),
.copyWith(color: ColorsManager.blackColor),
), ),
Text( Text(
'30', '30',
@ -108,9 +106,7 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
Text('m', Text('m', style: context.textTheme.bodySmall!.copyWith(color: ColorsManager.blackColor)),
style: context.textTheme.bodySmall!
.copyWith(color: ColorsManager.blackColor)),
IconButton( IconButton(
onPressed: () {}, onPressed: () {},
icon: const Icon( icon: const Icon(
@ -132,7 +128,7 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
code: 'child_lock', code: 'child_lock',
value: state.status.childLock, value: state.status.childLock,
label: 'Child Lock', label: 'Child Lock',
icon: state.status.childLock ? Assets.unlock : Assets.acLock, icon: state.status.childLock ? Assets.acLock : Assets.unlock,
onChange: (value) { onChange: (value) {
context.read<AcBloc>().add( context.read<AcBloc>().add(
AcControlEvent( AcControlEvent(

View File

@ -1,11 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/ac/model/ac_model.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/pages/device_managment/ac/bloc/ac_bloc.dart'; import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_bloc.dart';
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart'; import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart';
import 'package:syncrow_web/pages/device_managment/ac/model/ac_model.dart';
import 'package:syncrow_web/pages/device_managment/shared/device_controls_container.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
class BatchAcMode extends StatelessWidget { class BatchAcMode extends StatelessWidget {
const BatchAcMode({ const BatchAcMode({
@ -21,30 +22,20 @@ class BatchAcMode extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return DeviceControlsContainer(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: ColorsManager.greyColor.withOpacity(0.2),
border: Border.all(color: ColorsManager.boxDivider),
),
padding: const EdgeInsets.all(16),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
_buildIconContainer(context, TempModes.cold, Assets.freezing, _buildIconContainer(context, TempModes.cold, Assets.freezing, value == TempModes.cold),
value == TempModes.cold), _buildIconContainer(context, TempModes.hot, Assets.acSun, value == TempModes.hot),
_buildIconContainer( _buildIconContainer(context, TempModes.wind, Assets.acAirConditioner, value == TempModes.wind),
context, TempModes.hot, Assets.acSun, value == TempModes.hot),
_buildIconContainer(context, TempModes.wind, Assets.acAirConditioner,
value == TempModes.wind),
], ],
), ),
); );
} }
Widget _buildIconContainer( Widget _buildIconContainer(BuildContext context, TempModes mode, String assetPath, bool isSelected) {
BuildContext context, TempModes mode, String assetPath, bool isSelected) {
return Flexible( return Flexible(
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {

View File

@ -1,11 +1,13 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_bloc.dart';
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart'; import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart';
import 'package:syncrow_web/pages/device_managment/shared/celciuse_symbol.dart'; import 'package:syncrow_web/pages/device_managment/shared/celciuse_symbol.dart';
import 'package:syncrow_web/pages/device_managment/shared/device_controls_container.dart';
import 'package:syncrow_web/pages/device_managment/shared/increament_decreament.dart'; import 'package:syncrow_web/pages/device_managment/shared/increament_decreament.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_bloc.dart';
class BatchCurrentTemp extends StatefulWidget { class BatchCurrentTemp extends StatefulWidget {
const BatchCurrentTemp({ const BatchCurrentTemp({
@ -14,12 +16,14 @@ class BatchCurrentTemp extends StatefulWidget {
required this.devicesIds, required this.devicesIds,
required this.currentTemp, required this.currentTemp,
required this.tempSet, required this.tempSet,
this.isBatch,
}); });
final String code; final String code;
final List<String> devicesIds; final List<String> devicesIds;
final int currentTemp; final int currentTemp;
final int tempSet; final int tempSet;
final bool? isBatch;
@override @override
State<BatchCurrentTemp> createState() => _CurrentTempState(); State<BatchCurrentTemp> createState() => _CurrentTempState();
@ -67,26 +71,22 @@ class _CurrentTempState extends State<BatchCurrentTemp> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return DeviceControlsContainer(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: ColorsManager.greyColor.withOpacity(0.2),
border: Border.all(color: ColorsManager.boxDivider),
),
padding: const EdgeInsets.all(16),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Column( widget.isBatch == true
? Text(
'Set Temperature',
style: Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.grey),
)
: Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
'Current Temperature', 'Current Temperature',
style: Theme.of(context) style: Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.grey),
.textTheme
.bodySmall!
.copyWith(color: Colors.grey),
), ),
const SizedBox( const SizedBox(
height: 5, height: 5,
@ -94,14 +94,8 @@ class _CurrentTempState extends State<BatchCurrentTemp> {
Row( Row(
children: [ children: [
Text( Text(
(widget.currentTemp > 99 (widget.currentTemp > 99 ? widget.currentTemp / 10 : widget.currentTemp).toString(),
? widget.currentTemp / 10 style: Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.grey),
: widget.currentTemp)
.toString(),
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: Colors.grey),
), ),
const CelsiusSymbol( const CelsiusSymbol(
color: Colors.grey, color: Colors.grey,

View File

@ -1,11 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/ac/model/ac_model.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/pages/device_managment/ac/bloc/ac_bloc.dart'; import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_bloc.dart';
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart'; import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart';
import 'package:syncrow_web/pages/device_managment/ac/model/ac_model.dart';
import 'package:syncrow_web/pages/device_managment/shared/device_controls_container.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
class BatchFanSpeedControl extends StatelessWidget { class BatchFanSpeedControl extends StatelessWidget {
const BatchFanSpeedControl({ const BatchFanSpeedControl({
@ -21,23 +22,16 @@ class BatchFanSpeedControl extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return DeviceControlsContainer(
decoration: BoxDecoration( padding: 8,
borderRadius: BorderRadius.circular(20),
color: ColorsManager.greyColor.withOpacity(0.2),
border: Border.all(color: ColorsManager.boxDivider),
),
padding: const EdgeInsets.all(8),
child: Column( child: Column(
children: [ children: [
Wrap( Wrap(
runSpacing: 8, runSpacing: 8,
spacing: 8, spacing: 8,
children: [ children: [
_buildIconContainer(context, FanSpeeds.auto, Assets.acFanAuto, _buildIconContainer(context, FanSpeeds.auto, Assets.acFanAuto, value == FanSpeeds.auto),
value == FanSpeeds.auto), _buildIconContainer(context, FanSpeeds.low, Assets.acFanLow, value == FanSpeeds.low),
_buildIconContainer(context, FanSpeeds.low, Assets.acFanLow,
value == FanSpeeds.low),
], ],
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
@ -45,10 +39,8 @@ class BatchFanSpeedControl extends StatelessWidget {
runSpacing: 8, runSpacing: 8,
spacing: 8, spacing: 8,
children: [ children: [
_buildIconContainer(context, FanSpeeds.middle, Assets.acFanMiddle, _buildIconContainer(context, FanSpeeds.middle, Assets.acFanMiddle, value == FanSpeeds.middle),
value == FanSpeeds.middle), _buildIconContainer(context, FanSpeeds.high, Assets.acFanHigh, value == FanSpeeds.high),
_buildIconContainer(context, FanSpeeds.high, Assets.acFanHigh,
value == FanSpeeds.high),
], ],
) )
], ],
@ -56,8 +48,7 @@ class BatchFanSpeedControl extends StatelessWidget {
); );
} }
Widget _buildIconContainer(BuildContext context, FanSpeeds speed, Widget _buildIconContainer(BuildContext context, FanSpeeds speed, String assetPath, bool isSelected) {
String assetPath, bool isSelected) {
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
context.read<AcBloc>().add( context.read<AcBloc>().add(

View File

@ -1,11 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/ac/model/ac_model.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/pages/device_managment/ac/bloc/ac_bloc.dart'; import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_bloc.dart';
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart'; import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart';
import 'package:syncrow_web/pages/device_managment/ac/model/ac_model.dart';
import 'package:syncrow_web/pages/device_managment/shared/device_controls_container.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
class AcMode extends StatelessWidget { class AcMode extends StatelessWidget {
const AcMode({ const AcMode({
@ -21,30 +22,20 @@ class AcMode extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return DeviceControlsContainer(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: ColorsManager.greyColor.withOpacity(0.2),
border: Border.all(color: ColorsManager.boxDivider),
),
padding: const EdgeInsets.all(16),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
_buildIconContainer(context, TempModes.cold, Assets.freezing, _buildIconContainer(context, TempModes.cold, Assets.freezing, value == TempModes.cold),
value == TempModes.cold), _buildIconContainer(context, TempModes.hot, Assets.acSun, value == TempModes.hot),
_buildIconContainer( _buildIconContainer(context, TempModes.wind, Assets.acAirConditioner, value == TempModes.wind),
context, TempModes.hot, Assets.acSun, value == TempModes.hot),
_buildIconContainer(context, TempModes.wind, Assets.acAirConditioner,
value == TempModes.wind),
], ],
), ),
); );
} }
Widget _buildIconContainer( Widget _buildIconContainer(BuildContext context, TempModes mode, String assetPath, bool isSelected) {
BuildContext context, TempModes mode, String assetPath, bool isSelected) {
return Flexible( return Flexible(
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {

View File

@ -1,9 +1,9 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_bloc.dart'; import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_bloc.dart';
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart'; import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart';
import 'package:syncrow_web/pages/device_managment/shared/device_controls_container.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/assets.dart';
@ -25,13 +25,7 @@ class AcToggle extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return DeviceControlsContainer(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: ColorsManager.greyColor.withOpacity(0.2),
border: Border.all(color: ColorsManager.boxDivider),
),
padding: const EdgeInsets.all(16),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [

View File

@ -1,11 +1,13 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_bloc.dart';
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart'; import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart';
import 'package:syncrow_web/pages/device_managment/shared/celciuse_symbol.dart'; import 'package:syncrow_web/pages/device_managment/shared/celciuse_symbol.dart';
import 'package:syncrow_web/pages/device_managment/shared/device_controls_container.dart';
import 'package:syncrow_web/pages/device_managment/shared/increament_decreament.dart'; import 'package:syncrow_web/pages/device_managment/shared/increament_decreament.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_bloc.dart';
class CurrentTemp extends StatefulWidget { class CurrentTemp extends StatefulWidget {
const CurrentTemp({ const CurrentTemp({
@ -67,13 +69,7 @@ class _CurrentTempState extends State<CurrentTemp> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return DeviceControlsContainer(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: ColorsManager.greyColor.withOpacity(0.2),
border: Border.all(color: ColorsManager.boxDivider),
),
padding: const EdgeInsets.all(16),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -83,10 +79,7 @@ class _CurrentTempState extends State<CurrentTemp> {
children: [ children: [
Text( Text(
'Current Temperature', 'Current Temperature',
style: Theme.of(context) style: Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.grey),
.textTheme
.bodySmall!
.copyWith(color: Colors.grey),
), ),
const SizedBox( const SizedBox(
height: 5, height: 5,
@ -94,14 +87,8 @@ class _CurrentTempState extends State<CurrentTemp> {
Row( Row(
children: [ children: [
Text( Text(
(widget.currentTemp > 99 (widget.currentTemp > 99 ? widget.currentTemp / 10 : widget.currentTemp).toString(),
? widget.currentTemp / 10 style: Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.grey),
: widget.currentTemp)
.toString(),
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: Colors.grey),
), ),
const CelsiusSymbol( const CelsiusSymbol(
color: Colors.grey, color: Colors.grey,

View File

@ -1,11 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/ac/model/ac_model.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/pages/device_managment/ac/bloc/ac_bloc.dart'; import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_bloc.dart';
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart'; import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart';
import 'package:syncrow_web/pages/device_managment/ac/model/ac_model.dart';
import 'package:syncrow_web/pages/device_managment/shared/device_controls_container.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
class FanSpeedControl extends StatelessWidget { class FanSpeedControl extends StatelessWidget {
const FanSpeedControl({ const FanSpeedControl({
@ -21,23 +22,15 @@ class FanSpeedControl extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return DeviceControlsContainer(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: ColorsManager.greyColor.withOpacity(0.2),
border: Border.all(color: ColorsManager.boxDivider),
),
padding: const EdgeInsets.all(8),
child: Column( child: Column(
children: [ children: [
Wrap( Wrap(
runSpacing: 8, runSpacing: 8,
spacing: 8, spacing: 8,
children: [ children: [
_buildIconContainer(context, FanSpeeds.auto, Assets.acFanAuto, _buildIconContainer(context, FanSpeeds.auto, Assets.acFanAuto, value == FanSpeeds.auto),
value == FanSpeeds.auto), _buildIconContainer(context, FanSpeeds.low, Assets.acFanLow, value == FanSpeeds.low),
_buildIconContainer(context, FanSpeeds.low, Assets.acFanLow,
value == FanSpeeds.low),
], ],
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
@ -45,10 +38,8 @@ class FanSpeedControl extends StatelessWidget {
runSpacing: 8, runSpacing: 8,
spacing: 8, spacing: 8,
children: [ children: [
_buildIconContainer(context, FanSpeeds.middle, Assets.acFanMiddle, _buildIconContainer(context, FanSpeeds.middle, Assets.acFanMiddle, value == FanSpeeds.middle),
value == FanSpeeds.middle), _buildIconContainer(context, FanSpeeds.high, Assets.acFanHigh, value == FanSpeeds.high),
_buildIconContainer(context, FanSpeeds.high, Assets.acFanHigh,
value == FanSpeeds.high),
], ],
) )
], ],
@ -56,8 +47,7 @@ class FanSpeedControl extends StatelessWidget {
); );
} }
Widget _buildIconContainer(BuildContext context, FanSpeeds speed, Widget _buildIconContainer(BuildContext context, FanSpeeds speed, String assetPath, bool isSelected) {
String assetPath, bool isSelected) {
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
context.read<AcBloc>().add( context.read<AcBloc>().add(

View File

@ -6,8 +6,7 @@ import 'package:syncrow_web/services/devices_mang_api.dart';
part 'device_managment_event.dart'; part 'device_managment_event.dart';
part 'device_managment_state.dart'; part 'device_managment_state.dart';
class DeviceManagementBloc class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementState> {
extends Bloc<DeviceManagementEvent, DeviceManagementState> {
int _selectedIndex = 0; int _selectedIndex = 0;
List<AllDevicesModel> _devices = []; List<AllDevicesModel> _devices = [];
int _onlineCount = 0; int _onlineCount = 0;
@ -15,7 +14,9 @@ class DeviceManagementBloc
int _lowBatteryCount = 0; int _lowBatteryCount = 0;
List<AllDevicesModel> _selectedDevices = []; List<AllDevicesModel> _selectedDevices = [];
List<AllDevicesModel> _filteredDevices = []; List<AllDevicesModel> _filteredDevices = [];
String productName = ''; String currentProductName = '';
String? currentCommunity;
String? currentUnitName;
DeviceManagementBloc() : super(DeviceManagementInitial()) { DeviceManagementBloc() : super(DeviceManagementInitial()) {
on<FetchDevices>(_onFetchDevices); on<FetchDevices>(_onFetchDevices);
@ -28,8 +29,7 @@ class DeviceManagementBloc
on<UpdateSelection>(_onUpdateSelection); on<UpdateSelection>(_onUpdateSelection);
} }
Future<void> _onFetchDevices( Future<void> _onFetchDevices(FetchDevices event, Emitter<DeviceManagementState> emit) async {
FetchDevices event, Emitter<DeviceManagementState> emit) async {
emit(DeviceManagementLoading()); emit(DeviceManagementLoading());
try { try {
final devices = await DevicesManagementApi().fetchDevices(); final devices = await DevicesManagementApi().fetchDevices();
@ -51,8 +51,7 @@ class DeviceManagementBloc
} }
} }
void _onFilterDevices( void _onFilterDevices(FilterDevices event, Emitter<DeviceManagementState> emit) async {
FilterDevices event, Emitter<DeviceManagementState> emit) async {
if (_devices.isNotEmpty) { if (_devices.isNotEmpty) {
_filteredDevices = List.from(_devices.where((device) { _filteredDevices = List.from(_devices.where((device) {
switch (event.filter) { switch (event.filter) {
@ -77,15 +76,14 @@ class DeviceManagementBloc
isControlButtonEnabled: _selectedDevices.isNotEmpty, isControlButtonEnabled: _selectedDevices.isNotEmpty,
)); ));
if (productName.isNotEmpty) { if (currentProductName.isNotEmpty) {
add(SearchDevices(productName: productName)); add(SearchDevices(productName: currentProductName));
} }
} }
} }
Future<void> _onResetFilters( Future<void> _onResetFilters(ResetFilters event, Emitter<DeviceManagementState> emit) async {
ResetFilters event, Emitter<DeviceManagementState> emit) async { currentProductName = '';
productName = '';
_selectedDevices.clear(); _selectedDevices.clear();
_filteredDevices = List.from(_devices); _filteredDevices = List.from(_devices);
_selectedIndex = 0; _selectedIndex = 0;
@ -100,8 +98,7 @@ class DeviceManagementBloc
)); ));
} }
void _onResetSelectedDevices( void _onResetSelectedDevices(ResetSelectedDevices event, Emitter<DeviceManagementState> emit) {
ResetSelectedDevices event, Emitter<DeviceManagementState> emit) {
_selectedDevices.clear(); _selectedDevices.clear();
if (state is DeviceManagementLoaded) { if (state is DeviceManagementLoaded) {
@ -127,14 +124,12 @@ class DeviceManagementBloc
} }
} }
void _onSelectedFilterChanged( void _onSelectedFilterChanged(SelectedFilterChanged event, Emitter<DeviceManagementState> emit) {
SelectedFilterChanged event, Emitter<DeviceManagementState> emit) {
_selectedIndex = event.selectedIndex; _selectedIndex = event.selectedIndex;
add(FilterDevices(_getFilterFromIndex(_selectedIndex))); add(FilterDevices(_getFilterFromIndex(_selectedIndex)));
} }
void _onSelectDevice( void _onSelectDevice(SelectDevice event, Emitter<DeviceManagementState> emit) {
SelectDevice event, Emitter<DeviceManagementState> emit) {
final selectedUuid = event.selectedDevice.uuid; final selectedUuid = event.selectedDevice.uuid;
if (_selectedDevices.any((device) => device.uuid == selectedUuid)) { if (_selectedDevices.any((device) => device.uuid == selectedUuid)) {
@ -145,8 +140,7 @@ class DeviceManagementBloc
List<AllDevicesModel> clonedSelectedDevices = List.from(_selectedDevices); List<AllDevicesModel> clonedSelectedDevices = List.from(_selectedDevices);
bool isControlButtonEnabled = bool isControlButtonEnabled = _checkIfControlButtonEnabled(clonedSelectedDevices);
_checkIfControlButtonEnabled(clonedSelectedDevices);
if (state is DeviceManagementLoaded) { if (state is DeviceManagementLoaded) {
emit(DeviceManagementLoaded( emit(DeviceManagementLoaded(
@ -155,8 +149,7 @@ class DeviceManagementBloc
onlineCount: _onlineCount, onlineCount: _onlineCount,
offlineCount: _offlineCount, offlineCount: _offlineCount,
lowBatteryCount: _lowBatteryCount, lowBatteryCount: _lowBatteryCount,
selectedDevice: selectedDevice: clonedSelectedDevices.isNotEmpty ? clonedSelectedDevices : null,
clonedSelectedDevices.isNotEmpty ? clonedSelectedDevices : null,
isControlButtonEnabled: isControlButtonEnabled, isControlButtonEnabled: isControlButtonEnabled,
)); ));
} else if (state is DeviceManagementFiltered) { } else if (state is DeviceManagementFiltered) {
@ -166,15 +159,13 @@ class DeviceManagementBloc
onlineCount: _onlineCount, onlineCount: _onlineCount,
offlineCount: _offlineCount, offlineCount: _offlineCount,
lowBatteryCount: _lowBatteryCount, lowBatteryCount: _lowBatteryCount,
selectedDevice: selectedDevice: clonedSelectedDevices.isNotEmpty ? clonedSelectedDevices : null,
clonedSelectedDevices.isNotEmpty ? clonedSelectedDevices : null,
isControlButtonEnabled: isControlButtonEnabled, isControlButtonEnabled: isControlButtonEnabled,
)); ));
} }
} }
void _onUpdateSelection( void _onUpdateSelection(UpdateSelection event, Emitter<DeviceManagementState> emit) {
UpdateSelection event, Emitter<DeviceManagementState> emit) {
List<AllDevicesModel> selectedDevices = []; List<AllDevicesModel> selectedDevices = [];
List<AllDevicesModel> devicesToSelectFrom = []; List<AllDevicesModel> devicesToSelectFrom = [];
@ -217,8 +208,7 @@ class DeviceManagementBloc
bool _checkIfControlButtonEnabled(List<AllDevicesModel> selectedDevices) { bool _checkIfControlButtonEnabled(List<AllDevicesModel> selectedDevices) {
if (selectedDevices.length > 1) { if (selectedDevices.length > 1) {
final productTypes = final productTypes = selectedDevices.map((device) => device.productType).toSet();
selectedDevices.map((device) => device.productType).toSet();
return productTypes.length == 1; return productTypes.length == 1;
} else if (selectedDevices.length == 1) { } else if (selectedDevices.length == 1) {
return true; return true;
@ -229,10 +219,8 @@ class DeviceManagementBloc
void _calculateDeviceCounts() { void _calculateDeviceCounts() {
_onlineCount = _devices.where((device) => device.online == true).length; _onlineCount = _devices.where((device) => device.online == true).length;
_offlineCount = _devices.where((device) => device.online == false).length; _offlineCount = _devices.where((device) => device.online == false).length;
_lowBatteryCount = _devices _lowBatteryCount =
.where((device) => _devices.where((device) => device.batteryLevel != null && device.batteryLevel! < 20).length;
device.batteryLevel != null && device.batteryLevel! < 20)
.length;
} }
String _getFilterFromIndex(int index) { String _getFilterFromIndex(int index) {
@ -248,53 +236,48 @@ class DeviceManagementBloc
} }
} }
void _onSearchDevices( void _onSearchDevices(SearchDevices event, Emitter<DeviceManagementState> emit) {
SearchDevices event, Emitter<DeviceManagementState> emit) {
if ((event.community == null || event.community!.isEmpty) && if ((event.community == null || event.community!.isEmpty) &&
(event.unitName == null || event.unitName!.isEmpty) && (event.unitName == null || event.unitName!.isEmpty) &&
(event.productName == null || event.productName!.isEmpty)) { (event.productName == null || event.productName!.isEmpty)) {
productName = ''; currentProductName = '';
if (state is DeviceManagementFiltered) { if (state is DeviceManagementFiltered) {
add(FilterDevices(_getFilterFromIndex(_selectedIndex))); add(FilterDevices(_getFilterFromIndex(_selectedIndex)));
} else {
return;
} }
} }
productName = event.productName ?? ''; if (event.productName == currentProductName &&
event.community == currentCommunity &&
event.unitName == currentUnitName &&
event.searchField) {
return;
}
currentProductName = event.productName ?? '';
currentCommunity = event.community;
currentUnitName = event.unitName;
List<AllDevicesModel> devicesToSearch = _filteredDevices; List<AllDevicesModel> devicesToSearch = _filteredDevices;
if (devicesToSearch.isNotEmpty) { if (devicesToSearch.isNotEmpty) {
_selectedDevices.clear();
_selectedIndex = _selectedIndex;
final filteredDevices = devicesToSearch.where((device) { final filteredDevices = devicesToSearch.where((device) {
final matchesCommunity = event.community == null || final matchesCommunity = event.community == null ||
event.community!.isEmpty || event.community!.isEmpty ||
(device.room?.name (device.room?.name?.toLowerCase().contains(event.community!.toLowerCase()) ?? false);
?.toLowerCase()
.contains(event.community!.toLowerCase()) ??
false);
final matchesUnit = event.unitName == null || final matchesUnit = event.unitName == null ||
event.unitName!.isEmpty || event.unitName!.isEmpty ||
(device.unit?.name (device.unit?.name?.toLowerCase().contains(event.unitName!.toLowerCase()) ?? false);
?.toLowerCase()
.contains(event.unitName!.toLowerCase()) ??
false);
final matchesProductName = event.productName == null || final matchesProductName = event.productName == null ||
event.productName!.isEmpty || event.productName!.isEmpty ||
(device.name (device.name?.toLowerCase().contains(event.productName!.toLowerCase()) ?? false);
?.toLowerCase()
.contains(event.productName!.toLowerCase()) ??
false);
final matchesDeviceName = event.productName == null || final matchesDeviceName = event.productName == null ||
event.productName!.isEmpty || event.productName!.isEmpty ||
(device.categoryName (device.categoryName?.toLowerCase().contains(event.productName!.toLowerCase()) ??
?.toLowerCase()
.contains(event.productName!.toLowerCase()) ??
false); false);
return matchesCommunity && return matchesCommunity && matchesUnit && (matchesProductName || matchesDeviceName);
matchesUnit &&
(matchesProductName || matchesDeviceName);
}).toList(); }).toList();
emit(DeviceManagementFiltered( emit(DeviceManagementFiltered(

View File

@ -31,11 +31,13 @@ class SearchDevices extends DeviceManagementEvent {
final String? community; final String? community;
final String? unitName; final String? unitName;
final String? productName; final String? productName;
final bool searchField;
const SearchDevices({ const SearchDevices({
this.community, this.community,
this.unitName, this.unitName,
this.productName, this.productName,
this.searchField = false,
}); });
@override @override

View File

@ -1,14 +1,14 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/shared/device_batch_control_dialog.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart';
import 'package:syncrow_web/pages/common/buttons/default_button.dart'; import 'package:syncrow_web/pages/common/buttons/default_button.dart';
import 'package:syncrow_web/pages/common/custom_table.dart'; import 'package:syncrow_web/pages/common/custom_table.dart';
import 'package:syncrow_web/pages/common/filter/filter_widget.dart'; import 'package:syncrow_web/pages/common/filter/filter_widget.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_managment_bloc.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_managment_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
import 'package:syncrow_web/pages/device_managment/shared/device_control_dialog.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_search_filters.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_search_filters.dart';
import 'package:syncrow_web/pages/device_managment/shared/device_batch_control_dialog.dart';
import 'package:syncrow_web/pages/device_managment/shared/device_control_dialog.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart';
import 'package:syncrow_web/utils/format_date_time.dart'; import 'package:syncrow_web/utils/format_date_time.dart';
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
import 'package:syncrow_web/utils/style.dart'; import 'package:syncrow_web/utils/style.dart';
@ -37,8 +37,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
offlineCount = state.offlineCount; offlineCount = state.offlineCount;
lowBatteryCount = state.lowBatteryCount; lowBatteryCount = state.lowBatteryCount;
isControlButtonEnabled = state.isControlButtonEnabled; isControlButtonEnabled = state.isControlButtonEnabled;
selectedDevices = state.selectedDevice ?? selectedDevices = state.selectedDevice ?? [];
context.read<DeviceManagementBloc>().selectedDevices;
} else if (state is DeviceManagementFiltered) { } else if (state is DeviceManagementFiltered) {
devicesToShow = state.filteredDevices; devicesToShow = state.filteredDevices;
selectedIndex = state.selectedIndex; selectedIndex = state.selectedIndex;
@ -46,14 +45,12 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
offlineCount = state.offlineCount; offlineCount = state.offlineCount;
lowBatteryCount = state.lowBatteryCount; lowBatteryCount = state.lowBatteryCount;
isControlButtonEnabled = state.isControlButtonEnabled; isControlButtonEnabled = state.isControlButtonEnabled;
selectedDevices = state.selectedDevice ?? selectedDevices = state.selectedDevice ?? [];
context.read<DeviceManagementBloc>().selectedDevices;
} else if (state is DeviceManagementInitial) { } else if (state is DeviceManagementInitial) {
devicesToShow = []; devicesToShow = [];
selectedIndex = 0; selectedIndex = 0;
isControlButtonEnabled = false; isControlButtonEnabled = false;
} }
final tabs = [ final tabs = [
'All', 'All',
'Online ($onlineCount)', 'Online ($onlineCount)',
@ -61,15 +58,12 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
'Low Battery ($lowBatteryCount)', 'Low Battery ($lowBatteryCount)',
]; ];
final buttonLabel = final buttonLabel = (selectedDevices.length > 1) ? 'Batch Control' : 'Control';
(selectedDevices.length > 1) ? 'Batch Control' : 'Control';
return Column( return Column(
children: [ children: [
Container( Container(
padding: isLargeScreenSize(context) padding: isLargeScreenSize(context) ? const EdgeInsets.all(30) : const EdgeInsets.all(15),
? const EdgeInsets.all(30)
: const EdgeInsets.all(15),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -78,9 +72,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
tabs: tabs, tabs: tabs,
selectedIndex: selectedIndex, selectedIndex: selectedIndex,
onTabChanged: (index) { onTabChanged: (index) {
context context.read<DeviceManagementBloc>().add(SelectedFilterChanged(index));
.read<DeviceManagementBloc>()
.add(SelectedFilterChanged(index));
}, },
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
@ -102,14 +94,11 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
), ),
); );
} else if (selectedDevices.length > 1) { } else if (selectedDevices.length > 1) {
final productTypes = selectedDevices final productTypes = selectedDevices.map((device) => device.productType).toSet();
.map((device) => device.productType)
.toSet();
if (productTypes.length == 1) { if (productTypes.length == 1) {
showDialog( showDialog(
context: context, context: context,
builder: (context) => builder: (context) => DeviceBatchControlDialog(
DeviceBatchControlDialog(
devices: selectedDevices, devices: selectedDevices,
), ),
); );
@ -123,9 +112,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
color: isControlButtonEnabled color: isControlButtonEnabled ? Colors.white : Colors.grey,
? Colors.white
: Colors.grey,
), ),
), ),
), ),
@ -136,17 +123,13 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
), ),
Expanded( Expanded(
child: Padding( child: Padding(
padding: isLargeScreenSize(context) padding: isLargeScreenSize(context) ? const EdgeInsets.all(30) : const EdgeInsets.all(15),
? const EdgeInsets.all(30)
: const EdgeInsets.all(15),
child: DynamicTable( child: DynamicTable(
withSelectAll: true, withSelectAll: true,
cellDecoration: containerDecoration, cellDecoration: containerDecoration,
onRowSelected: (index, isSelected, row) { onRowSelected: (index, isSelected, row) {
final selectedDevice = devicesToShow[index]; final selectedDevice = devicesToShow[index];
context context.read<DeviceManagementBloc>().add(SelectDevice(selectedDevice));
.read<DeviceManagementBloc>()
.add(SelectDevice(selectedDevice));
}, },
withCheckBox: true, withCheckBox: true,
size: context.screenSize, size: context.screenSize,
@ -169,26 +152,17 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
device.uuid ?? '', device.uuid ?? '',
device.unit?.name ?? '', device.unit?.name ?? '',
device.room?.name ?? '', device.room?.name ?? '',
device.batteryLevel != null device.batteryLevel != null ? '${device.batteryLevel}%' : '-',
? '${device.batteryLevel}%' formatDateTime(DateTime.fromMillisecondsSinceEpoch((device.createTime ?? 0) * 1000)),
: '-',
formatDateTime(DateTime.fromMillisecondsSinceEpoch(
(device.createTime ?? 0) * 1000)),
device.online == true ? 'Online' : 'Offline', device.online == true ? 'Online' : 'Offline',
formatDateTime(DateTime.fromMillisecondsSinceEpoch( formatDateTime(DateTime.fromMillisecondsSinceEpoch((device.updateTime ?? 0) * 1000)),
(device.updateTime ?? 0) * 1000)),
]; ];
}).toList(), }).toList(),
onSelectionChanged: (selectedRows) { onSelectionChanged: (selectedRows) {
context context.read<DeviceManagementBloc>().add(UpdateSelection(selectedRows));
.read<DeviceManagementBloc>()
.add(UpdateSelection(selectedRows));
}, },
initialSelectedIds: context initialSelectedIds:
.read<DeviceManagementBloc>() context.read<DeviceManagementBloc>().selectedDevices.map((device) => device.uuid!).toList(),
.selectedDevices
.map((device) => device.uuid!)
.toList(),
isEmpty: devicesToShow.isEmpty, isEmpty: devicesToShow.isEmpty,
), ),
), ),

View File

@ -12,8 +12,7 @@ class DeviceSearchFilters extends StatefulWidget {
State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState(); State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState();
} }
class _DeviceSearchFiltersState extends State<DeviceSearchFilters> class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperResponsiveLayout {
with HelperResponsiveLayout {
final TextEditingController communityController = TextEditingController(); final TextEditingController communityController = TextEditingController();
final TextEditingController unitNameController = TextEditingController(); final TextEditingController unitNameController = TextEditingController();
final TextEditingController productNameController = TextEditingController(); final TextEditingController productNameController = TextEditingController();
@ -35,8 +34,7 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
const SizedBox(width: 20), const SizedBox(width: 20),
_buildSearchField("Unit Name", unitNameController, 200), _buildSearchField("Unit Name", unitNameController, 200),
const SizedBox(width: 20), const SizedBox(width: 20),
_buildSearchField( _buildSearchField("Device Name / Product Name", productNameController, 300),
"Device Name / Product Name", productNameController, 300),
const SizedBox(width: 20), const SizedBox(width: 20),
_buildSearchResetButtons(), _buildSearchResetButtons(),
], ],
@ -45,22 +43,35 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
spacing: 20, spacing: 20,
runSpacing: 10, runSpacing: 10,
children: [ children: [
_buildSearchField("Community", communityController, 200), _buildSearchField(
"Community",
communityController,
200,
),
_buildSearchField("Unit Name", unitNameController, 200), _buildSearchField("Unit Name", unitNameController, 200),
_buildSearchField( _buildSearchField(
"Device Name / Product Name", productNameController, 300), "Device Name / Product Name",
productNameController,
300,
),
_buildSearchResetButtons(), _buildSearchResetButtons(),
], ],
); );
} }
Widget _buildSearchField( Widget _buildSearchField(String title, TextEditingController controller, double width) {
String title, TextEditingController controller, double width) {
return StatefulTextField( return StatefulTextField(
title: title, title: title,
width: width, width: width,
elevation: 2, elevation: 2,
controller: controller, controller: controller,
onSubmitted: () {
context.read<DeviceManagementBloc>().add(SearchDevices(
productName: productNameController.text,
unitName: unitNameController.text,
community: communityController.text,
searchField: true));
},
); );
} }
@ -71,7 +82,7 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
community: communityController.text, community: communityController.text,
unitName: unitNameController.text, unitName: unitNameController.text,
productName: productNameController.text, productName: productNameController.text,
)); searchField: true));
}, },
onReset: () { onReset: () {
communityController.clear(); communityController.clear();

View File

@ -1,8 +1,9 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/event.dart'; import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_event.dart';
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/state.dart'; import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_state.dart';
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart'; import 'package:syncrow_web/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart';
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/model/help_description.dart'; import 'package:syncrow_web/pages/device_managment/ceiling_sensor/model/help_description.dart';
import 'package:syncrow_web/services/devices_mang_api.dart'; import 'package:syncrow_web/services/devices_mang_api.dart';
@ -27,8 +28,7 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
CeilingInitialEvent event, Emitter<CeilingSensorState> emit) async { CeilingInitialEvent event, Emitter<CeilingSensorState> emit) async {
emit(CeilingLoadingInitialState()); emit(CeilingLoadingInitialState());
try { try {
var response = var response = await DevicesManagementApi().getDeviceStatus(event.deviceId);
await DevicesManagementApi().getDeviceStatus(event.deviceId);
deviceStatus = CeilingSensorModel.fromJson(response.status); deviceStatus = CeilingSensorModel.fromJson(response.status);
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus)); emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
// _listenToChanges(); // _listenToChanges();
@ -57,8 +57,7 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
// } catch (_) {} // } catch (_) {}
// } // }
void _changeValue( void _changeValue(CeilingChangeValueEvent event, Emitter<CeilingSensorState> emit) async {
CeilingChangeValueEvent event, Emitter<CeilingSensorState> emit) async {
emit(CeilingLoadingNewSate(ceilingSensorModel: deviceStatus)); emit(CeilingLoadingNewSate(ceilingSensorModel: deviceStatus));
if (event.code == 'sensitivity') { if (event.code == 'sensitivity') {
deviceStatus.sensitivity = event.value; deviceStatus.sensitivity = event.value;
@ -123,8 +122,7 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
try { try {
late bool response; late bool response;
if (isBatch) { if (isBatch) {
response = await DevicesManagementApi() response = await DevicesManagementApi().deviceBatchControl(deviceId, code, value);
.deviceBatchControl(deviceId, code, value);
} else { } else {
response = await DevicesManagementApi() response = await DevicesManagementApi()
.deviceControl(deviceId, Status(code: code, value: value)); .deviceControl(deviceId, Status(code: code, value: value));
@ -145,17 +143,19 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
}); });
} }
FutureOr<void> _getDeviceReports(GetCeilingDeviceReportsEvent event, FutureOr<void> _getDeviceReports(
Emitter<CeilingSensorState> emit) async { GetCeilingDeviceReportsEvent event, Emitter<CeilingSensorState> emit) async {
if (event.code.isEmpty) { if (event.code.isEmpty) {
emit(ShowCeilingDescriptionState(description: reportString)); emit(ShowCeilingDescriptionState(description: reportString));
return; return;
} else { } else {
emit(CeilingReportsLoadingState()); emit(CeilingReportsLoadingState());
// final from = DateTime.now().subtract(const Duration(days: 30)).millisecondsSinceEpoch;
// final to = DateTime.now().millisecondsSinceEpoch;
try { try {
await DevicesManagementApi.getDeviceReports(deviceId, event.code) // await DevicesManagementApi.getDeviceReportsByDate(deviceId, event.code, from.toString(), to.toString())
.then((value) { await DevicesManagementApi.getDeviceReports(deviceId, event.code).then((value) {
emit(CeilingReportsState(deviceReport: value)); emit(CeilingReportsState(deviceReport: value));
}); });
} catch (e) { } catch (e) {
@ -165,23 +165,19 @@ class CeilingSensorBloc extends Bloc<CeilingSensorEvent, CeilingSensorState> {
} }
} }
void _showDescription( void _showDescription(ShowCeilingDescriptionEvent event, Emitter<CeilingSensorState> emit) {
ShowCeilingDescriptionEvent event, Emitter<CeilingSensorState> emit) {
emit(ShowCeilingDescriptionState(description: event.description)); emit(ShowCeilingDescriptionState(description: event.description));
} }
void _backToGridView( void _backToGridView(BackToCeilingGridViewEvent event, Emitter<CeilingSensorState> emit) {
BackToCeilingGridViewEvent event, Emitter<CeilingSensorState> emit) {
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus)); emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
} }
FutureOr<void> _fetchCeilingSensorBatchControl( FutureOr<void> _fetchCeilingSensorBatchControl(
CeilingFetchDeviceStatusEvent event, CeilingFetchDeviceStatusEvent event, Emitter<CeilingSensorState> emit) async {
Emitter<CeilingSensorState> emit) async {
emit(CeilingLoadingInitialState()); emit(CeilingLoadingInitialState());
try { try {
var response = var response = await DevicesManagementApi().getBatchStatus(event.devicesIds);
await DevicesManagementApi().getBatchStatus(event.devicesIds);
deviceStatus = CeilingSensorModel.fromJson(response.status); deviceStatus = CeilingSensorModel.fromJson(response.status);
emit(CeilingUpdateState(ceilingSensorModel: deviceStatus)); emit(CeilingUpdateState(ceilingSensorModel: deviceStatus));
} catch (e) { } catch (e) {

View File

@ -46,22 +46,19 @@ class CeilingSensorModel {
_spaceType = getSpaceType(status.value ?? 'none'); _spaceType = getSpaceType(status.value ?? 'none');
break; break;
case 'sensitivity': case 'sensitivity':
_sensitivity = status.value is int _sensitivity =
? status.value status.value is int ? status.value : int.tryParse(status.value ?? '1') ?? 1;
: int.tryParse(status.value ?? '1') ?? 1;
break; break;
case 'checking_result': case 'checking_result':
_checkingResult = status.value ?? ''; _checkingResult = status.value ?? '';
break; break;
case 'presence_range': case 'presence_range':
_presenceRange = status.value is int _presenceRange =
? status.value status.value is int ? status.value : int.tryParse(status.value ?? '0') ?? 0;
: int.tryParse(status.value ?? '0') ?? 0;
break; break;
case 'sports_para': case 'sports_para':
_sportsPara = status.value is int _sportsPara =
? status.value status.value is int ? status.value : int.tryParse(status.value ?? '0') ?? 0;
: int.tryParse(status.value ?? '0') ?? 0;
break; break;
case 'body_movement': case 'body_movement':
_bodyMovement = status.value ?? ''; _bodyMovement = status.value ?? '';
@ -70,9 +67,7 @@ class CeilingSensorModel {
_noBodyTime = status.value ?? 'none'; _noBodyTime = status.value ?? 'none';
break; break;
case 'moving_max_dis': case 'moving_max_dis':
_maxDis = status.value is int _maxDis = status.value is int ? status.value : int.tryParse(status.value ?? '0') ?? 0;
? status.value
: int.tryParse(status.value ?? '0') ?? 0;
break; break;
} }
} }

View File

@ -1,9 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/bloc.dart'; import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_bloc.dart';
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/event.dart'; import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_event.dart';
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/state.dart'; import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_state.dart';
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart'; import 'package:syncrow_web/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart';
import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart'; import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart';
import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart'; import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart';
@ -12,8 +12,7 @@ import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presen
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presense_nobody_time.dart'; import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presense_nobody_time.dart';
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
class CeilingSensorBatchControlView extends StatelessWidget class CeilingSensorBatchControlView extends StatelessWidget with HelperResponsiveLayout {
with HelperResponsiveLayout {
const CeilingSensorBatchControlView({super.key, required this.devicesIds}); const CeilingSensorBatchControlView({super.key, required this.devicesIds});
final List<String> devicesIds; final List<String> devicesIds;
@ -28,12 +27,11 @@ class CeilingSensorBatchControlView extends StatelessWidget
..add(CeilingFetchDeviceStatusEvent(devicesIds)), ..add(CeilingFetchDeviceStatusEvent(devicesIds)),
child: BlocBuilder<CeilingSensorBloc, CeilingSensorState>( child: BlocBuilder<CeilingSensorBloc, CeilingSensorState>(
builder: (context, state) { builder: (context, state) {
if (state is CeilingLoadingInitialState || if (state is CeilingLoadingInitialState || state is CeilingReportsLoadingState) {
state is CeilingReportsLoadingState) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} else if (state is CeilingUpdateState) { } else if (state is CeilingUpdateState) {
return _buildGridView(context, state.ceilingSensorModel, return _buildGridView(
isExtraLarge, isLarge, isMedium); context, state.ceilingSensorModel, isExtraLarge, isLarge, isMedium);
} }
return const Center(child: Text('Error fetching status')); return const Center(child: Text('Error fetching status'));
}, },
@ -41,8 +39,8 @@ class CeilingSensorBatchControlView extends StatelessWidget
); );
} }
Widget _buildGridView(BuildContext context, CeilingSensorModel model, Widget _buildGridView(BuildContext context, CeilingSensorModel model, bool isExtraLarge,
bool isExtraLarge, bool isLarge, bool isMedium) { bool isLarge, bool isMedium) {
return GridView( return GridView(
padding: const EdgeInsets.symmetric(horizontal: 50), padding: const EdgeInsets.symmetric(horizontal: 50),
shrinkWrap: true, shrinkWrap: true,
@ -118,8 +116,7 @@ class CeilingSensorBatchControlView extends StatelessWidget
context.read<CeilingSensorBloc>().add( context.read<CeilingSensorBloc>().add(
CeilingFactoryResetEvent( CeilingFactoryResetEvent(
devicesId: devicesIds.first, devicesId: devicesIds.first,
factoryResetModel: factoryResetModel: FactoryResetModel(devicesUuid: devicesIds),
FactoryResetModel(devicesUuid: devicesIds),
), ),
); );
}, },

View File

@ -1,9 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/bloc.dart'; import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_bloc.dart';
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/event.dart'; import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_event.dart';
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/state.dart'; import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/ceiling_state.dart';
import 'package:syncrow_web/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart'; import 'package:syncrow_web/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart';
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_display_data.dart'; import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_display_data.dart';
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_space_type.dart'; import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_space_type.dart';
@ -16,8 +16,7 @@ import 'package:syncrow_web/pages/device_managment/shared/table/report_table.dar
import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
class CeilingSensorControlsView extends StatelessWidget class CeilingSensorControlsView extends StatelessWidget with HelperResponsiveLayout {
with HelperResponsiveLayout {
const CeilingSensorControlsView({super.key, required this.device}); const CeilingSensorControlsView({super.key, required this.device});
final AllDevicesModel device; final AllDevicesModel device;
@ -32,35 +31,29 @@ class CeilingSensorControlsView extends StatelessWidget
..add(CeilingInitialEvent(device.uuid ?? '')), ..add(CeilingInitialEvent(device.uuid ?? '')),
child: BlocBuilder<CeilingSensorBloc, CeilingSensorState>( child: BlocBuilder<CeilingSensorBloc, CeilingSensorState>(
builder: (context, state) { builder: (context, state) {
if (state is CeilingLoadingInitialState || if (state is CeilingLoadingInitialState || state is CeilingReportsLoadingState) {
state is CeilingReportsLoadingState) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} else if (state is CeilingUpdateState) { } else if (state is CeilingUpdateState) {
return _buildGridView(context, state.ceilingSensorModel, return _buildGridView(
isExtraLarge, isLarge, isMedium); context, state.ceilingSensorModel, isExtraLarge, isLarge, isMedium);
} else if (state is CeilingReportsState) { } else if (state is CeilingReportsState) {
return ReportsTable( return ReportsTable(
report: state.deviceReport, report: state.deviceReport,
onRowTap: (index) {}, onRowTap: (index) {},
onClose: () { onClose: () {
context context.read<CeilingSensorBloc>().add(BackToCeilingGridViewEvent());
.read<CeilingSensorBloc>()
.add(BackToCeilingGridViewEvent());
}, },
); );
} else if (state is ShowCeilingDescriptionState) { } else if (state is ShowCeilingDescriptionState) {
return DescriptionView( return DescriptionView(
description: state.description, description: state.description,
onClose: () { onClose: () {
context context.read<CeilingSensorBloc>().add(BackToCeilingGridViewEvent());
.read<CeilingSensorBloc>()
.add(BackToCeilingGridViewEvent());
}, },
); );
} else if (state is CeilingReportsFailedState) { } else if (state is CeilingReportsFailedState) {
final model = context.read<CeilingSensorBloc>().deviceStatus; final model = context.read<CeilingSensorBloc>().deviceStatus;
return _buildGridView( return _buildGridView(context, model, isExtraLarge, isLarge, isMedium);
context, model, isExtraLarge, isLarge, isMedium);
} }
return const Center(child: Text('Error fetching status')); return const Center(child: Text('Error fetching status'));
}, },
@ -68,8 +61,8 @@ class CeilingSensorControlsView extends StatelessWidget
); );
} }
Widget _buildGridView(BuildContext context, CeilingSensorModel model, Widget _buildGridView(BuildContext context, CeilingSensorModel model, bool isExtraLarge,
bool isExtraLarge, bool isLarge, bool isMedium) { bool isLarge, bool isMedium) {
return GridView( return GridView(
padding: const EdgeInsets.symmetric(horizontal: 50), padding: const EdgeInsets.symmetric(horizontal: 50),
shrinkWrap: true, shrinkWrap: true,
@ -150,8 +143,8 @@ class CeilingSensorControlsView extends StatelessWidget
), ),
GestureDetector( GestureDetector(
onTap: () { onTap: () {
context.read<CeilingSensorBloc>().add(GetCeilingDeviceReportsEvent( context.read<CeilingSensorBloc>().add(
code: 'presence_state', deviceUuid: device.uuid!)); GetCeilingDeviceReportsEvent(code: 'presence_state', deviceUuid: device.uuid!));
}, },
child: const PresenceStaticWidget( child: const PresenceStaticWidget(
icon: Assets.illuminanceRecordIcon, icon: Assets.illuminanceRecordIcon,
@ -160,8 +153,9 @@ class CeilingSensorControlsView extends StatelessWidget
), ),
GestureDetector( GestureDetector(
onTap: () { onTap: () {
context.read<CeilingSensorBloc>().add(GetCeilingDeviceReportsEvent( context
code: '', deviceUuid: device.uuid!)); .read<CeilingSensorBloc>()
.add(GetCeilingDeviceReportsEvent(code: '', deviceUuid: device.uuid!));
}, },
child: const PresenceStaticWidget( child: const PresenceStaticWidget(
icon: Assets.helpDescriptionIcon, icon: Assets.helpDescriptionIcon,

View File

@ -38,14 +38,13 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
on<GarageDoorBatchControlEvent>(_onBatchControl); on<GarageDoorBatchControlEvent>(_onBatchControl);
on<GarageDoorFetchBatchStatusEvent>(_onFetchBatchStatus); on<GarageDoorFetchBatchStatusEvent>(_onFetchBatchStatus);
on<GarageDoorFactoryResetEvent>(_onFactoryReset); on<GarageDoorFactoryResetEvent>(_onFactoryReset);
on<EditGarageDoorScheduleEvent>(_onEditSchedule);
} }
void _fetchGarageDoorStatus( void _fetchGarageDoorStatus(GarageDoorInitialEvent event, Emitter<GarageDoorState> emit) async {
GarageDoorInitialEvent event, Emitter<GarageDoorState> emit) async {
emit(GarageDoorLoadingState()); emit(GarageDoorLoadingState());
try { try {
var response = var response = await DevicesManagementApi().getDeviceStatus(event.deviceId);
await DevicesManagementApi().getDeviceStatus(event.deviceId);
deviceStatus = GarageDoorStatusModel.fromJson(deviceId, response.status); deviceStatus = GarageDoorStatusModel.fromJson(deviceId, response.status);
emit(GarageDoorLoadedState(status: deviceStatus)); emit(GarageDoorLoadedState(status: deviceStatus));
} catch (e) { } catch (e) {
@ -53,22 +52,18 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
} }
} }
Future<void> _onFetchBatchStatus(GarageDoorFetchBatchStatusEvent event, Future<void> _onFetchBatchStatus(GarageDoorFetchBatchStatusEvent event, Emitter<GarageDoorState> emit) async {
Emitter<GarageDoorState> emit) async {
emit(GarageDoorLoadingState()); emit(GarageDoorLoadingState());
try { try {
final status = final status = await DevicesManagementApi().getBatchStatus(event.deviceIds);
await DevicesManagementApi().getBatchStatus(event.deviceIds); deviceStatus = GarageDoorStatusModel.fromJson(event.deviceIds.first, status.status);
deviceStatus =
GarageDoorStatusModel.fromJson(event.deviceIds.first, status.status);
emit(GarageDoorBatchStatusLoaded(deviceStatus)); emit(GarageDoorBatchStatusLoaded(deviceStatus));
} catch (e) { } catch (e) {
emit(GarageDoorBatchControlError(e.toString())); emit(GarageDoorBatchControlError(e.toString()));
} }
} }
Future<void> _addSchedule( Future<void> _addSchedule(AddGarageDoorScheduleEvent event, Emitter<GarageDoorState> emit) async {
AddGarageDoorScheduleEvent event, Emitter<GarageDoorState> emit) async {
try { try {
ScheduleEntry newSchedule = ScheduleEntry( ScheduleEntry newSchedule = ScheduleEntry(
category: event.category, category: event.category,
@ -76,11 +71,9 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
function: Status(code: 'switch_1', value: event.functionOn), function: Status(code: 'switch_1', value: event.functionOn),
days: ScheduleModel.convertSelectedDaysToStrings(event.selectedDays), days: ScheduleModel.convertSelectedDaysToStrings(event.selectedDays),
); );
bool success = bool success = await DevicesManagementApi().addScheduleRecord(newSchedule, deviceId);
await DevicesManagementApi().addScheduleRecord(newSchedule, deviceId);
if (success) { if (success) {
add(FetchGarageDoorSchedulesEvent( add(FetchGarageDoorSchedulesEvent(deviceId: deviceId, category: 'switch_1'));
deviceId: deviceId, category: 'switch_1'));
} else { } else {
emit(GarageDoorLoadedState(status: deviceStatus)); emit(GarageDoorLoadedState(status: deviceStatus));
} }
@ -89,19 +82,16 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
} }
} }
void _onUpdateCountdownAlarm( void _onUpdateCountdownAlarm(UpdateCountdownAlarmEvent event, Emitter<GarageDoorState> emit) {
UpdateCountdownAlarmEvent event, Emitter<GarageDoorState> emit) {
final currentState = state; final currentState = state;
if (currentState is GarageDoorLoadedState) { if (currentState is GarageDoorLoadedState) {
emit(currentState.copyWith( emit(currentState.copyWith(
status: status: currentState.status.copyWith(countdownAlarm: event.countdownAlarm),
currentState.status.copyWith(countdownAlarm: event.countdownAlarm),
)); ));
} }
} }
void _onUpdateTrTimeCon( void _onUpdateTrTimeCon(UpdateTrTimeConEvent event, Emitter<GarageDoorState> emit) {
UpdateTrTimeConEvent event, Emitter<GarageDoorState> emit) {
final currentState = state; final currentState = state;
if (currentState is GarageDoorLoadedState) { if (currentState is GarageDoorLoadedState) {
emit(currentState.copyWith( emit(currentState.copyWith(
@ -110,8 +100,7 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
} }
} }
Future<void> _updateSchedule(UpdateGarageDoorScheduleEvent event, Future<void> _updateSchedule(UpdateGarageDoorScheduleEvent event, Emitter<GarageDoorState> emit) async {
Emitter<GarageDoorState> emit) async {
try { try {
final updatedSchedules = deviceStatus.schedules?.map((schedule) { final updatedSchedules = deviceStatus.schedules?.map((schedule) {
if (schedule.scheduleId == event.scheduleId) { if (schedule.scheduleId == event.scheduleId) {
@ -138,15 +127,12 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
} }
} }
Future<void> _deleteSchedule(DeleteGarageDoorScheduleEvent event, Future<void> _deleteSchedule(DeleteGarageDoorScheduleEvent event, Emitter<GarageDoorState> emit) async {
Emitter<GarageDoorState> emit) async {
try { try {
bool success = await DevicesManagementApi() bool success = await DevicesManagementApi().deleteScheduleRecord(deviceStatus.uuid, event.scheduleId);
.deleteScheduleRecord(deviceStatus.uuid, event.scheduleId);
if (success) { if (success) {
final updatedSchedules = deviceStatus.schedules final updatedSchedules =
?.where((schedule) => schedule.scheduleId != event.scheduleId) deviceStatus.schedules?.where((schedule) => schedule.scheduleId != event.scheduleId).toList();
.toList();
deviceStatus = deviceStatus.copyWith(schedules: updatedSchedules); deviceStatus = deviceStatus.copyWith(schedules: updatedSchedules);
emit(GarageDoorLoadedState(status: deviceStatus)); emit(GarageDoorLoadedState(status: deviceStatus));
} else { } else {
@ -157,12 +143,11 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
} }
} }
Future<void> _fetchSchedules(FetchGarageDoorSchedulesEvent event, Future<void> _fetchSchedules(FetchGarageDoorSchedulesEvent event, Emitter<GarageDoorState> emit) async {
Emitter<GarageDoorState> emit) async {
emit(ScheduleGarageLoadingState()); emit(ScheduleGarageLoadingState());
try { try {
List<ScheduleModel> schedules = await DevicesManagementApi() List<ScheduleModel> schedules =
.getDeviceSchedules(deviceStatus.uuid, event.category); await DevicesManagementApi().getDeviceSchedules(deviceStatus.uuid, event.category);
deviceStatus = deviceStatus.copyWith(schedules: schedules); deviceStatus = deviceStatus.copyWith(schedules: schedules);
emit( emit(
GarageDoorLoadedState( GarageDoorLoadedState(
@ -180,37 +165,30 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
} }
} }
Future<void> _updateSelectedTime( Future<void> _updateSelectedTime(UpdateSelectedTimeEvent event, Emitter<GarageDoorState> emit) async {
UpdateSelectedTimeEvent event, Emitter<GarageDoorState> emit) async {
final currentState = state; final currentState = state;
if (currentState is GarageDoorLoadedState) { if (currentState is GarageDoorLoadedState) {
emit(currentState.copyWith(selectedTime: event.selectedTime)); emit(currentState.copyWith(selectedTime: event.selectedTime));
} }
} }
Future<void> _updateSelectedDay( Future<void> _updateSelectedDay(UpdateSelectedDayEvent event, Emitter<GarageDoorState> emit) async {
UpdateSelectedDayEvent event, Emitter<GarageDoorState> emit) async {
final currentState = state; final currentState = state;
if (currentState is GarageDoorLoadedState) { if (currentState is GarageDoorLoadedState) {
List<bool> updatedDays = List.from(currentState.selectedDays); List<bool> updatedDays = List.from(currentState.selectedDays);
updatedDays[event.dayIndex] = event.isSelected; updatedDays[event.dayIndex] = event.isSelected;
emit(currentState.copyWith( emit(currentState.copyWith(selectedDays: updatedDays, selectedTime: currentState.selectedTime));
selectedDays: updatedDays, selectedTime: currentState.selectedTime));
} }
} }
Future<void> _updateFunctionOn( Future<void> _updateFunctionOn(UpdateFunctionOnEvent event, Emitter<GarageDoorState> emit) async {
UpdateFunctionOnEvent event, Emitter<GarageDoorState> emit) async {
final currentState = state; final currentState = state;
if (currentState is GarageDoorLoadedState) { if (currentState is GarageDoorLoadedState) {
emit(currentState.copyWith( emit(currentState.copyWith(functionOn: event.functionOn, selectedTime: currentState.selectedTime));
functionOn: event.functionOn,
selectedTime: currentState.selectedTime));
} }
} }
Future<void> _initializeAddSchedule( Future<void> _initializeAddSchedule(InitializeAddScheduleEvent event, Emitter<GarageDoorState> emit) async {
InitializeAddScheduleEvent event, Emitter<GarageDoorState> emit) async {
final currentState = state; final currentState = state;
if (currentState is GarageDoorLoadedState) { if (currentState is GarageDoorLoadedState) {
emit(currentState.copyWith( emit(currentState.copyWith(
@ -222,25 +200,20 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
} }
} }
Future<void> _fetchRecords( Future<void> _fetchRecords(FetchGarageDoorRecordsEvent event, Emitter<GarageDoorState> emit) async {
FetchGarageDoorRecordsEvent event, Emitter<GarageDoorState> emit) async {
emit(GarageDoorReportsLoadingState()); emit(GarageDoorReportsLoadingState());
try { try {
final from = DateTime.now() final from = DateTime.now().subtract(const Duration(days: 30)).millisecondsSinceEpoch;
.subtract(const Duration(days: 30))
.millisecondsSinceEpoch;
final to = DateTime.now().millisecondsSinceEpoch; final to = DateTime.now().millisecondsSinceEpoch;
final DeviceReport records = final DeviceReport records =
await DevicesManagementApi.getDeviceReportsByDate( await DevicesManagementApi.getDeviceReportsByDate(event.deviceId, 'switch_1', from.toString(), to.toString());
event.deviceId, 'switch_1', from.toString(), to.toString());
emit(GarageDoorReportsState(deviceReport: records)); emit(GarageDoorReportsState(deviceReport: records));
} catch (e) { } catch (e) {
emit(GarageDoorReportsFailedState(error: e.toString())); emit(GarageDoorReportsFailedState(error: e.toString()));
} }
} }
Future<void> _onBatchControl( Future<void> _onBatchControl(GarageDoorBatchControlEvent event, Emitter<GarageDoorState> emit) async {
GarageDoorBatchControlEvent event, Emitter<GarageDoorState> emit) async {
final oldValue = event.code == 'switch_1' ? deviceStatus.switch1 : false; final oldValue = event.code == 'switch_1' ? deviceStatus.switch1 : false;
_updateLocalValue(event.code, event.value); _updateLocalValue(event.code, event.value);
@ -260,13 +233,11 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
} }
} }
void _backToGridView( void _backToGridView(BackToGarageDoorGridViewEvent event, Emitter<GarageDoorState> emit) {
BackToGarageDoorGridViewEvent event, Emitter<GarageDoorState> emit) {
emit(GarageDoorLoadedState(status: deviceStatus)); emit(GarageDoorLoadedState(status: deviceStatus));
} }
void _handleUpdate( void _handleUpdate(GarageDoorUpdatedEvent event, Emitter<GarageDoorState> emit) {
GarageDoorUpdatedEvent event, Emitter<GarageDoorState> emit) {
emit(GarageDoorLoadedState(status: deviceStatus)); emit(GarageDoorLoadedState(status: deviceStatus));
} }
@ -282,11 +253,9 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
late bool status; late bool status;
await Future.delayed(const Duration(milliseconds: 500)); await Future.delayed(const Duration(milliseconds: 500));
if (isBatch) { if (isBatch) {
status = await DevicesManagementApi() status = await DevicesManagementApi().deviceBatchControl(deviceId, code, value);
.deviceBatchControl(deviceId, code, value);
} else { } else {
status = await DevicesManagementApi() status = await DevicesManagementApi().deviceControl(deviceId, Status(code: code, value: value));
.deviceControl(deviceId, Status(code: code, value: value));
} }
if (!status) { if (!status) {
@ -301,12 +270,10 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
} }
} }
Future<void> _onFactoryReset( Future<void> _onFactoryReset(GarageDoorFactoryResetEvent event, Emitter<GarageDoorState> emit) async {
GarageDoorFactoryResetEvent event, Emitter<GarageDoorState> emit) async {
emit(GarageDoorLoadingState()); emit(GarageDoorLoadingState());
try { try {
final response = await DevicesManagementApi() final response = await DevicesManagementApi().factoryReset(event.factoryReset, event.deviceId);
.factoryReset(event.factoryReset, event.deviceId);
if (!response) { if (!response) {
emit(const GarageDoorErrorState(message: 'Failed to reset device')); emit(const GarageDoorErrorState(message: 'Failed to reset device'));
} else { } else {
@ -317,47 +284,34 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
} }
} }
void _increaseDelay( void _increaseDelay(IncreaseGarageDoorDelayEvent event, Emitter<GarageDoorState> emit) async {
IncreaseGarageDoorDelayEvent event, Emitter<GarageDoorState> emit) async {
// if (deviceStatus.countdown1 != 0) { // if (deviceStatus.countdown1 != 0) {
try { try {
deviceStatus = deviceStatus.copyWith( deviceStatus = deviceStatus.copyWith(delay: deviceStatus.delay + Duration(minutes: 10));
delay: deviceStatus.delay + Duration(minutes: 10));
emit(GarageDoorLoadedState(status: deviceStatus)); emit(GarageDoorLoadedState(status: deviceStatus));
add(GarageDoorControlEvent( add(GarageDoorControlEvent(deviceId: event.deviceId, value: deviceStatus.delay.inSeconds, code: 'countdown_1'));
deviceId: event.deviceId,
value: deviceStatus.delay.inSeconds,
code: 'countdown_1'));
} catch (e) { } catch (e) {
emit(GarageDoorErrorState(message: e.toString())); emit(GarageDoorErrorState(message: e.toString()));
} }
// } // }
} }
void _decreaseDelay( void _decreaseDelay(DecreaseGarageDoorDelayEvent event, Emitter<GarageDoorState> emit) async {
DecreaseGarageDoorDelayEvent event, Emitter<GarageDoorState> emit) async {
// if (deviceStatus.countdown1 != 0) { // if (deviceStatus.countdown1 != 0) {
try { try {
if (deviceStatus.delay.inMinutes > 10) { if (deviceStatus.delay.inMinutes > 10) {
deviceStatus = deviceStatus.copyWith( deviceStatus = deviceStatus.copyWith(delay: deviceStatus.delay - Duration(minutes: 10));
delay: deviceStatus.delay - Duration(minutes: 10));
} }
emit(GarageDoorLoadedState(status: deviceStatus)); emit(GarageDoorLoadedState(status: deviceStatus));
add(GarageDoorControlEvent( add(GarageDoorControlEvent(deviceId: event.deviceId, value: deviceStatus.delay.inSeconds, code: 'countdown_1'));
deviceId: event.deviceId,
value: deviceStatus.delay.inSeconds,
code: 'countdown_1'));
} catch (e) { } catch (e) {
emit(GarageDoorErrorState(message: e.toString())); emit(GarageDoorErrorState(message: e.toString()));
} }
//} //}
} }
void _garageDoorControlEvent( void _garageDoorControlEvent(GarageDoorControlEvent event, Emitter<GarageDoorState> emit) async {
GarageDoorControlEvent event, Emitter<GarageDoorState> emit) async { final oldValue = event.code == 'countdown_1' ? deviceStatus.countdown1 : deviceStatus.switch1;
final oldValue = event.code == 'countdown_1'
? deviceStatus.countdown1
: deviceStatus.switch1;
_updateLocalValue(event.code, event.value); _updateLocalValue(event.code, event.value);
emit(GarageDoorLoadedState(status: deviceStatus)); emit(GarageDoorLoadedState(status: deviceStatus));
final success = await _runDeBouncer( final success = await _runDeBouncer(
@ -373,8 +327,7 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
} }
} }
void _revertValue( void _revertValue(String code, dynamic oldValue, Emitter<GarageDoorState> emit) {
String code, dynamic oldValue, Emitter<GarageDoorState> emit) {
switch (code) { switch (code) {
case 'switch_1': case 'switch_1':
if (oldValue is bool) { if (oldValue is bool) {
@ -383,8 +336,7 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
break; break;
case 'countdown_1': case 'countdown_1':
if (oldValue is int) { if (oldValue is int) {
deviceStatus = deviceStatus.copyWith( deviceStatus = deviceStatus.copyWith(countdown1: oldValue, delay: Duration(seconds: oldValue));
countdown1: oldValue, delay: Duration(seconds: oldValue));
} }
break; break;
// Add other cases if needed // Add other cases if needed
@ -406,8 +358,7 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
break; break;
case 'countdown_1': case 'countdown_1':
if (value is int) { if (value is int) {
deviceStatus = deviceStatus.copyWith( deviceStatus = deviceStatus.copyWith(countdown1: value, delay: Duration(seconds: value));
countdown1: value, delay: Duration(seconds: value));
} }
break; break;
case 'countdown_alarm': case 'countdown_alarm':
@ -420,6 +371,25 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
deviceStatus = deviceStatus.copyWith(trTimeCon: value); deviceStatus = deviceStatus.copyWith(trTimeCon: value);
} }
break; break;
case 'door_state_1':
if (value is String) {
deviceStatus = deviceStatus.copyWith(doorState1: value);
}
break;
case 'door_control_1':
if (value is String) {
deviceStatus = deviceStatus.copyWith(doorControl1: value);
}
break;
case 'voice_control_1':
if (value is bool) {
deviceStatus = deviceStatus.copyWith(voiceControl1: value);
}
break;
case 'door_contact_state':
if (value is bool) {
deviceStatus = deviceStatus.copyWith(doorContactState: value);
}
default: default:
break; break;
} }
@ -430,4 +400,24 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
_timer?.cancel(); _timer?.cancel();
return super.close(); return super.close();
} }
FutureOr<void> _onEditSchedule(EditGarageDoorScheduleEvent event, Emitter<GarageDoorState> emit) async {
try {
ScheduleEntry newSchedule = ScheduleEntry(
scheduleId: event.scheduleId,
category: event.category,
time: formatTimeOfDayToISO(event.time),
function: Status(code: 'switch_1', value: event.functionOn),
days: ScheduleModel.convertSelectedDaysToStrings(event.selectedDays),
);
bool success = await DevicesManagementApi().editScheduleRecord(deviceId, newSchedule);
if (success) {
add(FetchGarageDoorSchedulesEvent(deviceId: deviceId, category: 'switch_1'));
} else {
emit(GarageDoorLoadedState(status: deviceStatus));
}
} catch (e) {
emit(GarageDoorLoadedState(status: deviceStatus));
}
}
} }

View File

@ -25,8 +25,7 @@ class GarageDoorControlEvent extends GarageDoorEvent {
final dynamic value; final dynamic value;
final String code; final String code;
const GarageDoorControlEvent( const GarageDoorControlEvent({required this.deviceId, required this.value, required this.code});
{required this.deviceId, required this.value, required this.code});
@override @override
List<Object?> get props => [deviceId, value]; List<Object?> get props => [deviceId, value];
@ -46,6 +45,22 @@ class AddGarageDoorScheduleEvent extends GarageDoorEvent {
}); });
} }
class EditGarageDoorScheduleEvent extends GarageDoorEvent {
final String scheduleId;
final String category;
final TimeOfDay time;
final bool functionOn;
final List<bool> selectedDays;
const EditGarageDoorScheduleEvent({
required this.scheduleId,
required this.category,
required this.time,
required this.functionOn,
required this.selectedDays,
});
}
class UpdateGarageDoorScheduleEvent extends GarageDoorEvent { class UpdateGarageDoorScheduleEvent extends GarageDoorEvent {
final String deviceId; final String deviceId;
final String scheduleId; final String scheduleId;
@ -106,8 +121,7 @@ class FetchGarageDoorRecordsEvent extends GarageDoorEvent {
final String deviceId; final String deviceId;
final String code; final String code;
const FetchGarageDoorRecordsEvent( const FetchGarageDoorRecordsEvent({required this.deviceId, required this.code});
{required this.deviceId, required this.code});
@override @override
List<Object?> get props => [deviceId, code]; List<Object?> get props => [deviceId, code];

View File

@ -76,13 +76,10 @@ class GarageDoorDialogHelper {
padding: 8, padding: 8,
backgroundColor: ColorsManager.boxColor, backgroundColor: ColorsManager.boxColor,
borderRadius: 15, borderRadius: 15,
onPressed: isEdit == true onPressed: () async {
? null
: () async {
TimeOfDay? time = await showTimePicker( TimeOfDay? time = await showTimePicker(
context: context, context: context,
initialTime: initialTime: state.selectedTime ?? TimeOfDay.now(),
state.selectedTime ?? TimeOfDay.now(),
builder: (context, child) { builder: (context, child) {
return Theme( return Theme(
data: Theme.of(context).copyWith( data: Theme.of(context).copyWith(
@ -102,9 +99,7 @@ class GarageDoorDialogHelper {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
state.selectedTime == null state.selectedTime == null ? 'Time' : state.selectedTime!.format(context),
? 'Time'
: state.selectedTime!.format(context),
style: context.textTheme.bodySmall!.copyWith( style: context.textTheme.bodySmall!.copyWith(
color: ColorsManager.grayColor, color: ColorsManager.grayColor,
), ),
@ -119,8 +114,7 @@ class GarageDoorDialogHelper {
), ),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
_buildDayCheckboxes(context, state.selectedDays, _buildDayCheckboxes(context, state.selectedDays, isEdit: isEdit),
isEdit: isEdit),
const SizedBox(height: 16), const SizedBox(height: 16),
_buildFunctionSwitch(context, state.functionOn, isEdit), _buildFunctionSwitch(context, state.functionOn, isEdit),
], ],
@ -147,7 +141,13 @@ class GarageDoorDialogHelper {
onPressed: () { onPressed: () {
if (state.selectedTime != null) { if (state.selectedTime != null) {
if (state.isEditing && index != null) { if (state.isEditing && index != null) {
return; bloc.add(EditGarageDoorScheduleEvent(
scheduleId: schedule?.scheduleId ?? '',
category: 'switch_1',
time: state.selectedTime!,
selectedDays: state.selectedDays,
functionOn: state.functionOn,
));
} else { } else {
bloc.add(AddGarageDoorScheduleEvent( bloc.add(AddGarageDoorScheduleEvent(
category: 'switch_1', category: 'switch_1',
@ -199,9 +199,7 @@ class GarageDoorDialogHelper {
return daysBoolean; return daysBoolean;
} }
static Widget _buildDayCheckboxes( static Widget _buildDayCheckboxes(BuildContext context, List<bool> selectedDays, {bool? isEdit}) {
BuildContext context, List<bool> selectedDays,
{bool? isEdit}) {
final dayLabels = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; final dayLabels = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
return Row( return Row(
@ -210,12 +208,8 @@ class GarageDoorDialogHelper {
children: [ children: [
Checkbox( Checkbox(
value: selectedDays[index], value: selectedDays[index],
onChanged: isEdit == true onChanged: (bool? value) {
? null context.read<GarageDoorBloc>().add(UpdateSelectedDayEvent(index, value!));
: (bool? value) {
context
.read<GarageDoorBloc>()
.add(UpdateSelectedDayEvent(index, value!));
}, },
), ),
Text(dayLabels[index]), Text(dayLabels[index]),
@ -225,27 +219,19 @@ class GarageDoorDialogHelper {
); );
} }
static Widget _buildFunctionSwitch( static Widget _buildFunctionSwitch(BuildContext context, bool isOn, bool? isEdit) {
BuildContext context, bool isOn, bool? isEdit) {
return Row( return Row(
children: [ children: [
Text( Text(
'Function:', 'Function:',
style: context.textTheme.bodySmall! style: context.textTheme.bodySmall!.copyWith(color: ColorsManager.grayColor),
.copyWith(color: ColorsManager.grayColor),
), ),
const SizedBox(width: 10), const SizedBox(width: 10),
Radio<bool>( Radio<bool>(
value: true, value: true,
groupValue: isOn, groupValue: isOn,
onChanged: (bool? value) { onChanged: (bool? value) {
if (isEdit == true) { context.read<GarageDoorBloc>().add(const UpdateFunctionOnEvent(functionOn: true));
return;
} else {
context
.read<GarageDoorBloc>()
.add(const UpdateFunctionOnEvent(functionOn: true));
}
}, },
), ),
const Text('On'), const Text('On'),
@ -254,13 +240,7 @@ class GarageDoorDialogHelper {
value: false, value: false,
groupValue: isOn, groupValue: isOn,
onChanged: (bool? value) { onChanged: (bool? value) {
if (isEdit == true) { context.read<GarageDoorBloc>().add(const UpdateFunctionOnEvent(functionOn: false));
return;
} else {
context
.read<GarageDoorBloc>()
.add(const UpdateFunctionOnEvent(functionOn: false));
}
}, },
), ),
const Text('Off'), const Text('Off'),
@ -317,33 +297,36 @@ class GarageDoorDialogHelper {
alertBody: TimeOutAlarmDialogBody(bloc), alertBody: TimeOutAlarmDialogBody(bloc),
title: 'Time Out Alarm', title: 'Time Out Alarm',
onConfirm: () { onConfirm: () {
final updatedState = final updatedState = context.read<GarageDoorBloc>().state;
context.read<GarageDoorBloc>().state; if (updatedState is GarageDoorLoadedState) {
if (updatedState
is GarageDoorLoadedState) {
context.read<GarageDoorBloc>().add( context.read<GarageDoorBloc>().add(
GarageDoorControlEvent( GarageDoorControlEvent(
deviceId: deviceId: updatedState.status.uuid,
updatedState.status.uuid,
code: 'countdown_alarm', code: 'countdown_alarm',
value: updatedState value: updatedState.status.countdownAlarm,
.status.countdownAlarm,
), ),
); );
Navigator.pop(context); Navigator.pop(context);
// context.read<GarageDoorBloc>().add(
// GarageDoorInitialEvent(
// bloc.deviceId));
} }
}); });
}, },
child: ToggleWidget( child: ToggleWidget(
icon: "-1", icon: "-1",
value: state.status.countdownAlarm > 0, value: state.status.doorState1 == "close_time_alarm" ? false : true,
code: 'countdown_alarm', code: 'door_state_1',
deviceId: bloc.deviceId, deviceId: bloc.deviceId,
label: 'Alarm when door is open', label: 'Alarm when door is open',
onChange: (value) {}), onChange: (value) {
context.read<GarageDoorBloc>().add(
GarageDoorControlEvent(
deviceId: bloc.deviceId,
code: 'door_state_1',
value: state.status.doorState1 == "close_time_alarm"
? "unclosed_time"
: "close_time_alarm",
),
);
}),
), ),
), ),
const SizedBox( const SizedBox(
@ -365,23 +348,16 @@ class GarageDoorDialogHelper {
), ),
title: 'Opening and Closing Time', title: 'Opening and Closing Time',
onConfirm: () { onConfirm: () {
final updatedState = final updatedState = context.read<GarageDoorBloc>().state;
context.read<GarageDoorBloc>().state; if (updatedState is GarageDoorLoadedState) {
if (updatedState
is GarageDoorLoadedState) {
context.read<GarageDoorBloc>().add( context.read<GarageDoorBloc>().add(
GarageDoorControlEvent( GarageDoorControlEvent(
deviceId: deviceId: updatedState.status.uuid,
updatedState.status.uuid,
code: 'tr_timecon', code: 'tr_timecon',
value: updatedState value: updatedState.status.trTimeCon,
.status.trTimeCon,
), ),
); );
Navigator.pop(context); Navigator.pop(context);
// context.read<GarageDoorBloc>().add(
// GarageDoorInitialEvent(
// bloc.deviceId));
} }
}); });
}, },

View File

@ -65,7 +65,7 @@ class GarageDoorStatusModel {
voiceControl1 = status.value ?? false; voiceControl1 = status.value ?? false;
break; break;
case 'door_state_1': case 'door_state_1':
doorState1 = status.value ?? 'closed'; doorState1 = status.value ?? 'close_time_alarm';
break; break;
} }
} }

View File

@ -26,8 +26,7 @@ class ScheduleGarageTableWidget extends StatelessWidget {
Table( Table(
border: TableBorder.all( border: TableBorder.all(
color: ColorsManager.graysColor, color: ColorsManager.graysColor,
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20)),
topLeft: Radius.circular(20), topRight: Radius.circular(20)),
), ),
children: [ children: [
TableRow( TableRow(
@ -51,21 +50,17 @@ class ScheduleGarageTableWidget extends StatelessWidget {
BlocBuilder<GarageDoorBloc, GarageDoorState>( BlocBuilder<GarageDoorBloc, GarageDoorState>(
builder: (context, state) { builder: (context, state) {
if (state is ScheduleGarageLoadingState) { if (state is ScheduleGarageLoadingState) {
return const SizedBox( return const SizedBox(height: 200, child: Center(child: CircularProgressIndicator()));
height: 200,
child: Center(child: CircularProgressIndicator()));
} }
if (state is GarageDoorLoadedState && if (state is GarageDoorLoadedState && state.status.schedules?.isEmpty == true) {
state.status.schedules == null) {
return _buildEmptyState(context); return _buildEmptyState(context);
} else if (state is GarageDoorLoadedState) { } else if (state is GarageDoorLoadedState) {
return Container( return Container(
height: 200, height: 200,
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all(color: ColorsManager.graysColor), border: Border.all(color: ColorsManager.graysColor),
borderRadius: const BorderRadius.only( borderRadius:
bottomLeft: Radius.circular(20), const BorderRadius.only(bottomLeft: Radius.circular(20), bottomRight: Radius.circular(20)),
bottomRight: Radius.circular(20)),
), ),
child: _buildTableBody(state, context)); child: _buildTableBody(state, context));
} }
@ -83,8 +78,7 @@ class ScheduleGarageTableWidget extends StatelessWidget {
height: 200, height: 200,
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all(color: ColorsManager.graysColor), border: Border.all(color: ColorsManager.graysColor),
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(bottomLeft: Radius.circular(20), bottomRight: Radius.circular(20)),
bottomLeft: Radius.circular(20), bottomRight: Radius.circular(20)),
), ),
child: Center( child: Center(
child: Column( child: Column(
@ -118,8 +112,7 @@ class ScheduleGarageTableWidget extends StatelessWidget {
children: [ children: [
if (state.status.schedules != null) if (state.status.schedules != null)
for (int i = 0; i < state.status.schedules!.length; i++) for (int i = 0; i < state.status.schedules!.length; i++)
_buildScheduleRow( _buildScheduleRow(state.status.schedules![i], i, context, state),
state.status.schedules![i], i, context, state),
], ],
), ),
), ),
@ -141,8 +134,7 @@ class ScheduleGarageTableWidget extends StatelessWidget {
); );
} }
TableRow _buildScheduleRow(ScheduleModel schedule, int index, TableRow _buildScheduleRow(ScheduleModel schedule, int index, BuildContext context, GarageDoorLoadedState state) {
BuildContext context, GarageDoorLoadedState state) {
return TableRow( return TableRow(
children: [ children: [
Center( Center(
@ -160,8 +152,7 @@ class ScheduleGarageTableWidget extends StatelessWidget {
width: 24, width: 24,
height: 24, height: 24,
child: schedule.enable child: schedule.enable
? const Icon(Icons.radio_button_checked, ? const Icon(Icons.radio_button_checked, color: ColorsManager.blueColor)
color: ColorsManager.blueColor)
: const Icon( : const Icon(
Icons.radio_button_unchecked, Icons.radio_button_unchecked,
color: ColorsManager.grayColor, color: ColorsManager.grayColor,
@ -169,9 +160,7 @@ class ScheduleGarageTableWidget extends StatelessWidget {
), ),
), ),
), ),
Center( Center(child: Text(_getSelectedDays(ScheduleModel.parseSelectedDays(schedule.days)))),
child: Text(_getSelectedDays(
ScheduleModel.parseSelectedDays(schedule.days)))),
Center(child: Text(formatIsoStringToTime(schedule.time, context))), Center(child: Text(formatIsoStringToTime(schedule.time, context))),
Center(child: Text(schedule.function.value ? 'On' : 'Off')), Center(child: Text(schedule.function.value ? 'On' : 'Off')),
Center( Center(
@ -181,24 +170,18 @@ class ScheduleGarageTableWidget extends StatelessWidget {
TextButton( TextButton(
style: TextButton.styleFrom(padding: EdgeInsets.zero), style: TextButton.styleFrom(padding: EdgeInsets.zero),
onPressed: () { onPressed: () {
GarageDoorDialogHelper.showAddGarageDoorScheduleDialog( GarageDoorDialogHelper.showAddGarageDoorScheduleDialog(context,
context, schedule: schedule, index: index, isEdit: true);
schedule: schedule,
index: index,
isEdit: true);
}, },
child: Text( child: Text(
'Edit', 'Edit',
style: context.textTheme.bodySmall! style: context.textTheme.bodySmall!.copyWith(color: ColorsManager.blueColor),
.copyWith(color: ColorsManager.blueColor),
), ),
), ),
TextButton( TextButton(
style: TextButton.styleFrom(padding: EdgeInsets.zero), style: TextButton.styleFrom(padding: EdgeInsets.zero),
onPressed: () { onPressed: () {
context context.read<GarageDoorBloc>().add(DeleteGarageDoorScheduleEvent(
.read<GarageDoorBloc>()
.add(DeleteGarageDoorScheduleEvent(
index: index, index: index,
scheduleId: schedule.scheduleId, scheduleId: schedule.scheduleId,
deviceId: state.status.uuid, deviceId: state.status.uuid,
@ -206,8 +189,7 @@ class ScheduleGarageTableWidget extends StatelessWidget {
}, },
child: Text( child: Text(
'Delete', 'Delete',
style: context.textTheme.bodySmall! style: context.textTheme.bodySmall!.copyWith(color: ColorsManager.blueColor),
.copyWith(color: ColorsManager.blueColor),
), ),
), ),
], ],

View File

@ -16,12 +16,10 @@ class GateWayBloc extends Bloc<GateWayEvent, GateWayState> {
on<GateWayFactoryReset>(_onFactoryReset); on<GateWayFactoryReset>(_onFactoryReset);
} }
FutureOr<void> _getGatWayById( FutureOr<void> _getGatWayById(GatWayById event, Emitter<GateWayState> emit) async {
GatWayById event, Emitter<GateWayState> emit) async {
emit(GatewayLoadingState()); emit(GatewayLoadingState());
try { try {
List<DeviceModel> devicesList = List<DeviceModel> devicesList = await DevicesManagementApi.getDevicesByGatewayId(event.getWayId);
await DevicesManagementApi.getDevicesByGatewayId(event.getWayId);
emit(UpdateGatewayState(list: devicesList)); emit(UpdateGatewayState(list: devicesList));
} catch (e) { } catch (e) {
@ -30,8 +28,7 @@ class GateWayBloc extends Bloc<GateWayEvent, GateWayState> {
} }
} }
FutureOr<void> _onFactoryReset( FutureOr<void> _onFactoryReset(GateWayFactoryReset event, Emitter<GateWayState> emit) async {
GateWayFactoryReset event, Emitter<GateWayState> emit) async {
emit(GatewayLoadingState()); emit(GatewayLoadingState());
try { try {
final response = await DevicesManagementApi().factoryReset( final response = await DevicesManagementApi().factoryReset(

View File

@ -74,7 +74,7 @@ class _DeviceItem extends StatelessWidget {
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
color: ColorsManager.whiteColors, color: ColorsManager.whiteColors,
child: SvgPicture.asset( child: SvgPicture.asset(
device.icon, device.icon ?? 'assets/icons/gateway.svg',
width: 35, width: 35,
height: 35, height: 35,
fit: BoxFit.contain, fit: BoxFit.contain,

View File

@ -2,9 +2,18 @@ import 'package:flutter/material.dart';
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart'; import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
class NotificationDialog extends StatelessWidget { class NotificationDialog extends StatefulWidget {
const NotificationDialog({super.key}); const NotificationDialog({super.key});
@override
State<NotificationDialog> createState() => _NotificationDialogState();
}
class _NotificationDialogState extends State<NotificationDialog> {
bool isLowBatteryNotificationEnabled = true;
bool isClosingRemindersEnabled = true;
bool isDoorAlarmEnabled = true;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Dialog( return Dialog(
@ -14,7 +23,7 @@ class NotificationDialog extends StatelessWidget {
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
), ),
child: SizedBox( child: SizedBox(
width: 798, width: 660,
child: SingleChildScrollView( child: SingleChildScrollView(
child: Padding( child: Padding(
padding: const EdgeInsets.all(20.0), padding: const EdgeInsets.all(20.0),
@ -61,30 +70,54 @@ class NotificationDialog extends StatelessWidget {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
ToggleWidget( SizedBox(
value: true, width: 170,
height: 135,
child: ToggleWidget(
value: isLowBatteryNotificationEnabled,
code: 'notification', code: 'notification',
deviceId: '', deviceId: '',
label: 'Low Battery', label: 'Low Battery',
onChange: (v) {}, onChange: (v) {
setState(() {
isLowBatteryNotificationEnabled = v;
});
},
icon: '-1', icon: '-1',
), ),
ToggleWidget( ),
value: true, SizedBox(
width: 170,
height: 135,
child: ToggleWidget(
value: isClosingRemindersEnabled,
code: 'notification', code: 'notification',
deviceId: '', deviceId: '',
label: 'Closing\nReminders', label: 'Closing\nReminders',
onChange: (v) {}, onChange: (v) {
setState(() {
isClosingRemindersEnabled = v;
});
},
icon: '-1', icon: '-1',
), ),
ToggleWidget( ),
value: true, SizedBox(
width: 170,
height: 135,
child: ToggleWidget(
value: isDoorAlarmEnabled,
code: 'notification', code: 'notification',
deviceId: '', deviceId: '',
label: 'Door Alarm', label: 'Door Alarm',
onChange: (v) {}, onChange: (v) {
setState(() {
isDoorAlarmEnabled = v;
});
},
icon: '-1', icon: '-1',
), ),
),
], ],
), ),
], ],

View File

@ -10,14 +10,12 @@ import 'package:syncrow_web/services/devices_mang_api.dart';
part 'one_gang_glass_switch_event.dart'; part 'one_gang_glass_switch_event.dart';
part 'one_gang_glass_switch_state.dart'; part 'one_gang_glass_switch_state.dart';
class OneGangGlassSwitchBloc class OneGangGlassSwitchBloc extends Bloc<OneGangGlassSwitchEvent, OneGangGlassSwitchState> {
extends Bloc<OneGangGlassSwitchEvent, OneGangGlassSwitchState> {
OneGangGlassStatusModel deviceStatus; OneGangGlassStatusModel deviceStatus;
Timer? _timer; Timer? _timer;
OneGangGlassSwitchBloc({required String deviceId}) OneGangGlassSwitchBloc({required String deviceId})
: deviceStatus = OneGangGlassStatusModel( : deviceStatus = OneGangGlassStatusModel(uuid: deviceId, switch1: false, countDown: 0),
uuid: deviceId, switch1: false, countDown: 0),
super(OneGangGlassSwitchInitial()) { super(OneGangGlassSwitchInitial()) {
on<OneGangGlassSwitchFetchDeviceEvent>(_onFetchDeviceStatus); on<OneGangGlassSwitchFetchDeviceEvent>(_onFetchDeviceStatus);
on<OneGangGlassSwitchControl>(_onControl); on<OneGangGlassSwitchControl>(_onControl);
@ -26,22 +24,19 @@ class OneGangGlassSwitchBloc
on<OneGangGlassFactoryResetEvent>(_onFactoryReset); on<OneGangGlassFactoryResetEvent>(_onFactoryReset);
} }
Future<void> _onFetchDeviceStatus(OneGangGlassSwitchFetchDeviceEvent event, Future<void> _onFetchDeviceStatus(
Emitter<OneGangGlassSwitchState> emit) async { OneGangGlassSwitchFetchDeviceEvent event, Emitter<OneGangGlassSwitchState> emit) async {
emit(OneGangGlassSwitchLoading()); emit(OneGangGlassSwitchLoading());
try { try {
final status = final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
await DevicesManagementApi().getDeviceStatus(event.deviceId); deviceStatus = OneGangGlassStatusModel.fromJson(event.deviceId, status.status);
deviceStatus =
OneGangGlassStatusModel.fromJson(event.deviceId, status.status);
emit(OneGangGlassSwitchStatusLoaded(deviceStatus)); emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
} catch (e) { } catch (e) {
emit(OneGangGlassSwitchError(e.toString())); emit(OneGangGlassSwitchError(e.toString()));
} }
} }
Future<void> _onControl(OneGangGlassSwitchControl event, Future<void> _onControl(OneGangGlassSwitchControl event, Emitter<OneGangGlassSwitchState> emit) async {
Emitter<OneGangGlassSwitchState> emit) async {
final oldValue = _getValueByCode(event.code); final oldValue = _getValueByCode(event.code);
_updateLocalValue(event.code, event.value); _updateLocalValue(event.code, event.value);
@ -57,12 +52,10 @@ class OneGangGlassSwitchBloc
); );
} }
Future<void> _onFactoryReset(OneGangGlassFactoryResetEvent event, Future<void> _onFactoryReset(OneGangGlassFactoryResetEvent event, Emitter<OneGangGlassSwitchState> emit) async {
Emitter<OneGangGlassSwitchState> emit) async {
emit(OneGangGlassSwitchLoading()); emit(OneGangGlassSwitchLoading());
try { try {
final response = await DevicesManagementApi() final response = await DevicesManagementApi().factoryReset(event.factoryReset, event.deviceId);
.factoryReset(event.factoryReset, event.deviceId);
if (!response) { if (!response) {
emit(OneGangGlassSwitchError('Failed to reset device')); emit(OneGangGlassSwitchError('Failed to reset device'));
} else { } else {
@ -73,12 +66,11 @@ class OneGangGlassSwitchBloc
} }
} }
Future<void> _onBatchControl(OneGangGlassSwitchBatchControl event, Future<void> _onBatchControl(OneGangGlassSwitchBatchControl event, Emitter<OneGangGlassSwitchState> emit) async {
Emitter<OneGangGlassSwitchState> emit) async {
final oldValue = _getValueByCode(event.code); final oldValue = _getValueByCode(event.code);
_updateLocalValue(event.code, event.value); _updateLocalValue(event.code, event.value);
emit(OneGangGlassSwitchBatchStatusLoaded(deviceStatus)); emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
await _runDebounce( await _runDebounce(
deviceId: event.deviceIds, deviceId: event.deviceIds,
@ -91,15 +83,12 @@ class OneGangGlassSwitchBloc
} }
Future<void> _onFetchBatchStatus( Future<void> _onFetchBatchStatus(
OneGangGlassSwitchFetchBatchStatusEvent event, OneGangGlassSwitchFetchBatchStatusEvent event, Emitter<OneGangGlassSwitchState> emit) async {
Emitter<OneGangGlassSwitchState> emit) async {
emit(OneGangGlassSwitchLoading()); emit(OneGangGlassSwitchLoading());
try { try {
final status = final status = await DevicesManagementApi().getBatchStatus(event.deviceIds);
await DevicesManagementApi().getBatchStatus(event.deviceIds); deviceStatus = OneGangGlassStatusModel.fromJson(event.deviceIds.first, status.status);
deviceStatus = OneGangGlassStatusModel.fromJson( emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
event.deviceIds.first, status.status);
emit(OneGangGlassSwitchBatchStatusLoaded(deviceStatus));
} catch (e) { } catch (e) {
emit(OneGangGlassSwitchError(e.toString())); emit(OneGangGlassSwitchError(e.toString()));
} }
@ -128,11 +117,9 @@ class OneGangGlassSwitchBloc
try { try {
late bool response; late bool response;
if (isBatch) { if (isBatch) {
response = await DevicesManagementApi() response = await DevicesManagementApi().deviceBatchControl(deviceId, code, value);
.deviceBatchControl(deviceId, code, value);
} else { } else {
response = await DevicesManagementApi() response = await DevicesManagementApi().deviceControl(deviceId, Status(code: code, value: value));
.deviceControl(deviceId, Status(code: code, value: value));
} }
if (!response) { if (!response) {
@ -144,8 +131,7 @@ class OneGangGlassSwitchBloc
}); });
} }
void _revertValueAndEmit(String deviceId, String code, bool oldValue, void _revertValueAndEmit(String deviceId, String code, bool oldValue, Emitter<OneGangGlassSwitchState> emit) {
Emitter<OneGangGlassSwitchState> emit) {
_updateLocalValue(code, oldValue); _updateLocalValue(code, oldValue);
emit(OneGangGlassSwitchStatusLoaded(deviceStatus)); emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
} }

View File

@ -55,7 +55,7 @@ class OneGangGlassSwitchControlView extends StatelessWidget with HelperResponsiv
value: status.switch1, value: status.switch1,
code: 'switch_1', code: 'switch_1',
deviceId: deviceId, deviceId: deviceId,
label: 'Wall Lightً', label: "Wall Light",
onChange: (value) { onChange: (value) {
context.read<OneGangGlassSwitchBloc>().add( context.read<OneGangGlassSwitchBloc>().add(
OneGangGlassSwitchControl( OneGangGlassSwitchControl(

View File

@ -7,8 +7,7 @@ import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/extension/build_context_x.dart';
class FirmwareUpdateWidget extends StatefulWidget { class FirmwareUpdateWidget extends StatefulWidget {
const FirmwareUpdateWidget( const FirmwareUpdateWidget({super.key, required this.deviceId, required this.version});
{super.key, required this.deviceId, required this.version});
final String deviceId; final String deviceId;
final int version; final int version;
@ -33,6 +32,8 @@ class _FirmwareUpdateWidgetState extends State<FirmwareUpdateWidget> {
? Column( ? Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
children: [ children: [
Text( Text(
'Firmware Update', 'Firmware Update',
@ -47,7 +48,8 @@ class _FirmwareUpdateWidgetState extends State<FirmwareUpdateWidget> {
color: ColorsManager.grayColor, color: ColorsManager.grayColor,
), ),
), ),
const SizedBox(height: 16), ],
),
Row( Row(
children: [ children: [
Flexible( Flexible(

View File

@ -7,8 +7,7 @@ import 'package:syncrow_web/pages/device_managment/all_devices/helper/route_cont
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
class DeviceBatchControlDialog extends StatelessWidget class DeviceBatchControlDialog extends StatelessWidget with RouteControlsBasedCode {
with RouteControlsBasedCode {
final List<AllDevicesModel> devices; final List<AllDevicesModel> devices;
const DeviceBatchControlDialog({super.key, required this.devices}); const DeviceBatchControlDialog({super.key, required this.devices});
@ -110,11 +109,11 @@ String getBatchDialogName(AllDevicesModel device) {
case '1G': case '1G':
return "Smart Light Switch"; return "Smart Light Switch";
case '2G': case '2G':
return "2Gang Light"; return "Smart Light Switch";
case '3G': case '3G':
return "Living Room"; return "Smart Light Switch";
case 'GW': case 'GW':
return "GateWay"; return "Gateway";
case 'DL': case 'DL':
return "Door Lock"; return "Door Lock";
case 'WPS': case 'WPS':
@ -124,9 +123,21 @@ String getBatchDialogName(AllDevicesModel device) {
case 'CUR': case 'CUR':
return "Smart Curtains"; return "Smart Curtains";
case 'WH': case 'WH':
return "Smart Water Hater"; return "Smart Water Heater";
case 'AC': case 'AC':
return "Smart AC"; return "Smart AC";
case 'DS':
return "Door / Window Sensor";
case '1GT':
return "Touch Switch";
case '2GT':
return "Touch Switch";
case '3GT':
return "Touch Switch";
case 'GD':
return "Garage Door Opener";
case 'WL':
return "Water Leak Sensor";
default: default:
return device.categoryName ?? 'Device Control'; return device.categoryName ?? 'Device Control';
} }

View File

@ -31,7 +31,7 @@ class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode {
children: [ children: [
const SizedBox(), const SizedBox(),
Text( Text(
device.categoryName ?? 'Device Control', device.productName ?? 'Device Control',
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 22, fontSize: 22,

View File

@ -2,8 +2,9 @@ import 'package:flutter/material.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
class DeviceControlsContainer extends StatelessWidget { class DeviceControlsContainer extends StatelessWidget {
const DeviceControlsContainer({required this.child, super.key}); const DeviceControlsContainer({required this.child, this.padding, super.key});
final Widget child; final Widget child;
final double? padding;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -11,9 +12,16 @@ class DeviceControlsContainer extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
color: ColorsManager.greyColor.withOpacity(0.2), color: ColorsManager.greyColor.withOpacity(0.2),
border: Border.all(color: ColorsManager.boxDivider),
// boxShadow: <BoxShadow>[
// BoxShadow(
// color: ColorsManager.blackColor.withOpacity(0.05),
// blurRadius: 6.0,
// offset: const Offset(0, 5),
// spreadRadius: 0)
// ],
), ),
padding: const EdgeInsets.all(12), padding: EdgeInsets.all(padding ?? 12),
child: child, child: child,
); );
} }

View File

@ -3,6 +3,8 @@ import 'package:intl/intl.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_reports.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/device_reports.dart';
import 'package:syncrow_web/pages/device_managment/shared/table/table_cell_widget.dart'; import 'package:syncrow_web/pages/device_managment/shared/table/table_cell_widget.dart';
import 'package:syncrow_web/pages/device_managment/shared/table/table_header.dart'; import 'package:syncrow_web/pages/device_managment/shared/table/table_header.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart';
// ignore: must_be_immutable // ignore: must_be_immutable
class ReportsTable extends StatelessWidget { class ReportsTable extends StatelessWidget {
@ -31,7 +33,18 @@ class ReportsTable extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Stack( return report.data == null || report.data!.isEmpty
? Container(
padding: const EdgeInsets.all(20.0),
width: MediaQuery.sizeOf(context).width,
alignment: AlignmentDirectional.center,
height: 100,
child: Text(
'No reports found',
style: context.textTheme.bodyLarge!.copyWith(color: ColorsManager.grayColor),
),
)
: Stack(
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.all(20.0), padding: const EdgeInsets.all(20.0),
@ -66,12 +79,10 @@ class ReportsTable extends StatelessWidget {
if (hideValueShowDescription == true) { if (hideValueShowDescription == true) {
if (mainDoorSensor != null && mainDoorSensor == true) { if (mainDoorSensor != null && mainDoorSensor == true) {
value = data.value == 'true' ? 'Open' : 'Close'; value = data.value == 'true' ? 'Open' : 'Close';
} else if (garageDoorSensor != null && } else if (garageDoorSensor != null && garageDoorSensor == true) {
garageDoorSensor == true) {
value = data.value == 'true' ? 'Opened' : 'Closed'; value = data.value == 'true' ? 'Opened' : 'Closed';
} else if (waterLeak != null && waterLeak == true) { } else if (waterLeak != null && waterLeak == true) {
value = value = data.value == 'normal' ? 'Normal' : 'Leak Detected';
data.value == 'normal' ? 'Normal' : 'Leak Detected';
} else { } else {
value = '${data.value!} ${thirdColumnDescription ?? ''}'; value = '${data.value!} ${thirdColumnDescription ?? ''}';
} }
@ -89,7 +100,7 @@ class ReportsTable extends StatelessWidget {
), ),
], ],
); );
}), })
], ],
), ),
), ),

View File

@ -1,5 +1,6 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_web/pages/device_managment/shared/device_controls_container.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/extension/build_context_x.dart';
@ -30,13 +31,7 @@ class ToggleWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return DeviceControlsContainer(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: ColorsManager.greyColor.withOpacity(0.2),
border: Border.all(color: ColorsManager.boxDivider),
),
padding: const EdgeInsets.all(16),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,

View File

@ -57,7 +57,7 @@ class ThreeGangGlassSwitchBatchControlView extends StatelessWidget with HelperRe
value: status.switch1, value: status.switch1,
code: 'switch_1', code: 'switch_1',
deviceId: deviceIds.first, deviceId: deviceIds.first,
label: 'Glass Switch 1', label: "Wall Light",
onChange: (value) { onChange: (value) {
context.read<ThreeGangGlassSwitchBloc>().add( context.read<ThreeGangGlassSwitchBloc>().add(
ThreeGangGlassSwitchBatchControl( ThreeGangGlassSwitchBatchControl(
@ -72,7 +72,7 @@ class ThreeGangGlassSwitchBatchControlView extends StatelessWidget with HelperRe
value: status.switch2, value: status.switch2,
code: 'switch_2', code: 'switch_2',
deviceId: deviceIds.first, deviceId: deviceIds.first,
label: 'Glass Switch 2', label: "Ceiling Light",
onChange: (value) { onChange: (value) {
context.read<ThreeGangGlassSwitchBloc>().add( context.read<ThreeGangGlassSwitchBloc>().add(
ThreeGangGlassSwitchBatchControl( ThreeGangGlassSwitchBatchControl(
@ -87,7 +87,7 @@ class ThreeGangGlassSwitchBatchControlView extends StatelessWidget with HelperRe
value: status.switch3, value: status.switch3,
code: 'switch_3', code: 'switch_3',
deviceId: deviceIds.first, deviceId: deviceIds.first,
label: 'Glass Switch 3', label: "SpotLight",
onChange: (value) { onChange: (value) {
context.read<ThreeGangGlassSwitchBloc>().add( context.read<ThreeGangGlassSwitchBloc>().add(
ThreeGangGlassSwitchBatchControl( ThreeGangGlassSwitchBatchControl(

View File

@ -56,7 +56,7 @@ class ThreeGangGlassSwitchControlView extends StatelessWidget with HelperRespons
value: status.switch1, value: status.switch1,
code: 'switch_1', code: 'switch_1',
deviceId: deviceId, deviceId: deviceId,
label: 'Wall Light', label: "Wall Light",
onChange: (value) { onChange: (value) {
context.read<ThreeGangGlassSwitchBloc>().add( context.read<ThreeGangGlassSwitchBloc>().add(
ThreeGangGlassSwitchControl( ThreeGangGlassSwitchControl(
@ -71,7 +71,7 @@ class ThreeGangGlassSwitchControlView extends StatelessWidget with HelperRespons
value: status.switch2, value: status.switch2,
code: 'switch_2', code: 'switch_2',
deviceId: deviceId, deviceId: deviceId,
label: 'Ceiling Light', label: "Ceiling Light",
onChange: (value) { onChange: (value) {
context.read<ThreeGangGlassSwitchBloc>().add( context.read<ThreeGangGlassSwitchBloc>().add(
ThreeGangGlassSwitchControl( ThreeGangGlassSwitchControl(
@ -86,7 +86,7 @@ class ThreeGangGlassSwitchControlView extends StatelessWidget with HelperRespons
value: status.switch3, value: status.switch3,
code: 'switch_3', code: 'switch_3',
deviceId: deviceId, deviceId: deviceId,
label: 'SpotLight', label: "SpotLight",
onChange: (value) { onChange: (value) {
context.read<ThreeGangGlassSwitchBloc>().add( context.read<ThreeGangGlassSwitchBloc>().add(
ThreeGangGlassSwitchControl( ThreeGangGlassSwitchControl(

View File

@ -1,8 +1,8 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/event.dart'; import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/wall_event.dart';
import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/state.dart'; import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/wall_state.dart';
import 'package:syncrow_web/pages/device_managment/wall_sensor/model/wall_sensor_model.dart'; import 'package:syncrow_web/pages/device_managment/wall_sensor/model/wall_sensor_model.dart';
import 'package:syncrow_web/services/devices_mang_api.dart'; import 'package:syncrow_web/services/devices_mang_api.dart';
@ -38,12 +38,10 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
// Fetch batch status // Fetch batch status
FutureOr<void> _fetchWallSensorBatchControl( FutureOr<void> _fetchWallSensorBatchControl(
WallSensorFetchBatchStatusEvent event, WallSensorFetchBatchStatusEvent event, Emitter<WallSensorState> emit) async {
Emitter<WallSensorState> emit) async {
emit(WallSensorLoadingInitialState()); emit(WallSensorLoadingInitialState());
try { try {
var response = var response = await DevicesManagementApi().getBatchStatus(event.devicesIds);
await DevicesManagementApi().getBatchStatus(event.devicesIds);
deviceStatus = WallSensorModel.fromJson(response.status); deviceStatus = WallSensorModel.fromJson(response.status);
emit(WallSensorUpdateState(wallSensorModel: deviceStatus)); emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
} catch (e) { } catch (e) {
@ -70,8 +68,7 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
// } catch (_) {} // } catch (_) {}
// } // }
void _changeValue( void _changeValue(WallSensorChangeValueEvent event, Emitter<WallSensorState> emit) async {
WallSensorChangeValueEvent event, Emitter<WallSensorState> emit) async {
emit(WallSensorLoadingNewSate(wallSensorModel: deviceStatus)); emit(WallSensorLoadingNewSate(wallSensorModel: deviceStatus));
if (event.code == 'far_detection') { if (event.code == 'far_detection') {
deviceStatus.farDetection = event.value; deviceStatus.farDetection = event.value;
@ -128,8 +125,7 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
try { try {
late bool response; late bool response;
if (isBatch) { if (isBatch) {
response = await DevicesManagementApi() response = await DevicesManagementApi().deviceBatchControl(deviceId, code, value);
.deviceBatchControl(deviceId, code, value);
} else { } else {
response = await DevicesManagementApi() response = await DevicesManagementApi()
.deviceControl(deviceId, Status(code: code, value: value)); .deviceControl(deviceId, Status(code: code, value: value));
@ -148,10 +144,13 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
FutureOr<void> _getDeviceReports( FutureOr<void> _getDeviceReports(
GetDeviceReportsEvent event, Emitter<WallSensorState> emit) async { GetDeviceReportsEvent event, Emitter<WallSensorState> emit) async {
emit(DeviceReportsLoadingState()); emit(DeviceReportsLoadingState());
// final from = DateTime.now().subtract(const Duration(days: 30)).millisecondsSinceEpoch;
// final to = DateTime.now().millisecondsSinceEpoch;
try { try {
await DevicesManagementApi.getDeviceReports(deviceId, event.code) // await DevicesManagementApi.getDeviceReportsByDate(
.then((value) { // deviceId, event.code, from.toString(), to.toString())
await DevicesManagementApi.getDeviceReports(deviceId, event.code).then((value) {
emit(DeviceReportsState(deviceReport: value, code: event.code)); emit(DeviceReportsState(deviceReport: value, code: event.code));
}); });
} catch (e) { } catch (e) {
@ -160,13 +159,11 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
} }
} }
void _showDescription( void _showDescription(ShowDescriptionEvent event, Emitter<WallSensorState> emit) {
ShowDescriptionEvent event, Emitter<WallSensorState> emit) {
emit(WallSensorShowDescriptionState(description: event.description)); emit(WallSensorShowDescriptionState(description: event.description));
} }
void _backToGridView( void _backToGridView(BackToGridViewEvent event, Emitter<WallSensorState> emit) {
BackToGridViewEvent event, Emitter<WallSensorState> emit) {
emit(WallSensorUpdateState(wallSensorModel: deviceStatus)); emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
} }

View File

@ -4,14 +4,13 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_re
import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart'; import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart';
import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart'; import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart';
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_update_data.dart'; import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_update_data.dart';
import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/bloc.dart'; import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/wall_bloc.dart';
import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/event.dart'; import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/wall_event.dart';
import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/state.dart'; import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/wall_state.dart';
import 'package:syncrow_web/pages/device_managment/wall_sensor/model/wall_sensor_model.dart'; import 'package:syncrow_web/pages/device_managment/wall_sensor/model/wall_sensor_model.dart';
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
class WallSensorBatchControlView extends StatelessWidget class WallSensorBatchControlView extends StatelessWidget with HelperResponsiveLayout {
with HelperResponsiveLayout {
const WallSensorBatchControlView({super.key, required this.devicesIds}); const WallSensorBatchControlView({super.key, required this.devicesIds});
final List<String> devicesIds; final List<String> devicesIds;
@ -26,16 +25,13 @@ class WallSensorBatchControlView extends StatelessWidget
..add(WallSensorFetchBatchStatusEvent(devicesIds)), ..add(WallSensorFetchBatchStatusEvent(devicesIds)),
child: BlocBuilder<WallSensorBloc, WallSensorState>( child: BlocBuilder<WallSensorBloc, WallSensorState>(
builder: (context, state) { builder: (context, state) {
if (state is WallSensorLoadingInitialState || if (state is WallSensorLoadingInitialState || state is DeviceReportsLoadingState) {
state is DeviceReportsLoadingState) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} else if (state is WallSensorUpdateState) { } else if (state is WallSensorUpdateState) {
return _buildGridView(context, state.wallSensorModel, isExtraLarge, return _buildGridView(context, state.wallSensorModel, isExtraLarge, isLarge, isMedium);
isLarge, isMedium);
} else if (state is DeviceReportsFailedState) { } else if (state is DeviceReportsFailedState) {
final model = context.read<WallSensorBloc>().deviceStatus; final model = context.read<WallSensorBloc>().deviceStatus;
return _buildGridView( return _buildGridView(context, model, isExtraLarge, isLarge, isMedium);
context, model, isExtraLarge, isLarge, isMedium);
} }
return const Center(child: Text('Error fetching status')); return const Center(child: Text('Error fetching status'));
}, },
@ -43,8 +39,8 @@ class WallSensorBatchControlView extends StatelessWidget
); );
} }
Widget _buildGridView(BuildContext context, WallSensorModel model, Widget _buildGridView(
bool isExtraLarge, bool isLarge, bool isMedium) { BuildContext context, WallSensorModel model, bool isExtraLarge, bool isLarge, bool isMedium) {
return GridView( return GridView(
padding: const EdgeInsets.symmetric(horizontal: 50, vertical: 20), padding: const EdgeInsets.symmetric(horizontal: 50, vertical: 20),
shrinkWrap: true, shrinkWrap: true,
@ -97,8 +93,7 @@ class WallSensorBatchControlView extends StatelessWidget
maxValue: 10000, maxValue: 10000,
steps: 1, steps: 1,
description: 'sec', description: 'sec',
action: (int value) => action: (int value) => context.read<WallSensorBloc>().add(WallSensorBatchControlEvent(
context.read<WallSensorBloc>().add(WallSensorBatchControlEvent(
deviceIds: devicesIds, deviceIds: devicesIds,
code: 'no_one_time', code: 'no_one_time',
value: value, value: value,

View File

@ -3,9 +3,9 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
import 'package:syncrow_web/pages/device_managment/shared/table/description_view.dart'; import 'package:syncrow_web/pages/device_managment/shared/table/description_view.dart';
import 'package:syncrow_web/pages/device_managment/shared/table/report_table.dart'; import 'package:syncrow_web/pages/device_managment/shared/table/report_table.dart';
import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/bloc.dart'; import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/wall_bloc.dart';
import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/event.dart'; import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/wall_event.dart';
import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/state.dart'; import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/wall_state.dart';
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_display_data.dart'; import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_display_data.dart';
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_static_widget.dart'; import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_static_widget.dart';
import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_status.dart'; import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_status.dart';
@ -14,8 +14,7 @@ import 'package:syncrow_web/pages/device_managment/wall_sensor/model/wall_sensor
import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
class WallSensorControlsView extends StatelessWidget class WallSensorControlsView extends StatelessWidget with HelperResponsiveLayout {
with HelperResponsiveLayout {
const WallSensorControlsView({super.key, required this.device}); const WallSensorControlsView({super.key, required this.device});
final AllDevicesModel device; final AllDevicesModel device;
@ -26,23 +25,19 @@ class WallSensorControlsView extends StatelessWidget
final isLarge = isLargeScreenSize(context); final isLarge = isLargeScreenSize(context);
final isMedium = isMediumScreenSize(context); final isMedium = isMediumScreenSize(context);
return BlocProvider( return BlocProvider(
create: (context) => WallSensorBloc(deviceId: device.uuid!) create: (context) =>
..add(WallSensorFetchStatusEvent()), WallSensorBloc(deviceId: device.uuid!)..add(WallSensorFetchStatusEvent()),
child: BlocBuilder<WallSensorBloc, WallSensorState>( child: BlocBuilder<WallSensorBloc, WallSensorState>(
builder: (context, state) { builder: (context, state) {
if (state is WallSensorLoadingInitialState || if (state is WallSensorLoadingInitialState || state is DeviceReportsLoadingState) {
state is DeviceReportsLoadingState) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} else if (state is WallSensorUpdateState) { } else if (state is WallSensorUpdateState) {
return _buildGridView(context, state.wallSensorModel, isExtraLarge, return _buildGridView(context, state.wallSensorModel, isExtraLarge, isLarge, isMedium);
isLarge, isMedium);
} else if (state is DeviceReportsState) { } else if (state is DeviceReportsState) {
return ReportsTable( return ReportsTable(
report: state.deviceReport, report: state.deviceReport,
thirdColumnTitle: thirdColumnTitle: state.code == 'illuminance_value' ? "Value" : 'Status',
state.code == 'illuminance_value' ? "Value" : 'Status', thirdColumnDescription: state.code == 'illuminance_value' ? "Lux" : null,
thirdColumnDescription:
state.code == 'illuminance_value' ? "Lux" : null,
onRowTap: (index) {}, onRowTap: (index) {},
onClose: () { onClose: () {
context.read<WallSensorBloc>().add(BackToGridViewEvent()); context.read<WallSensorBloc>().add(BackToGridViewEvent());
@ -57,8 +52,7 @@ class WallSensorControlsView extends StatelessWidget
); );
} else if (state is DeviceReportsFailedState) { } else if (state is DeviceReportsFailedState) {
final model = context.read<WallSensorBloc>().deviceStatus; final model = context.read<WallSensorBloc>().deviceStatus;
return _buildGridView( return _buildGridView(context, model, isExtraLarge, isLarge, isMedium);
context, model, isExtraLarge, isLarge, isMedium);
} }
return const Center(child: Text('Error fetching status')); return const Center(child: Text('Error fetching status'));
}, },
@ -66,8 +60,8 @@ class WallSensorControlsView extends StatelessWidget
); );
} }
Widget _buildGridView(BuildContext context, WallSensorModel model, Widget _buildGridView(
bool isExtraLarge, bool isLarge, bool isMedium) { BuildContext context, WallSensorModel model, bool isExtraLarge, bool isLarge, bool isMedium) {
return GridView( return GridView(
padding: const EdgeInsets.symmetric(horizontal: 50), padding: const EdgeInsets.symmetric(horizontal: 50),
shrinkWrap: true, shrinkWrap: true,
@ -136,8 +130,7 @@ class WallSensorControlsView extends StatelessWidget
maxValue: 10000, maxValue: 10000,
steps: 1, steps: 1,
description: 'sec', description: 'sec',
action: (int value) => action: (int value) => context.read<WallSensorBloc>().add(WallSensorChangeValueEvent(
context.read<WallSensorBloc>().add(WallSensorChangeValueEvent(
code: 'no_one_time', code: 'no_one_time',
value: value, value: value,
))), ))),
@ -157,8 +150,9 @@ class WallSensorControlsView extends StatelessWidget
), ),
GestureDetector( GestureDetector(
onTap: () { onTap: () {
context.read<WallSensorBloc>().add(GetDeviceReportsEvent( context
code: 'illuminance_value', deviceUuid: device.uuid!)); .read<WallSensorBloc>()
.add(GetDeviceReportsEvent(code: 'illuminance_value', deviceUuid: device.uuid!));
}, },
child: const PresenceStaticWidget( child: const PresenceStaticWidget(
icon: Assets.illuminanceRecordIcon, icon: Assets.illuminanceRecordIcon,
@ -167,8 +161,9 @@ class WallSensorControlsView extends StatelessWidget
), ),
GestureDetector( GestureDetector(
onTap: () { onTap: () {
context.read<WallSensorBloc>().add(GetDeviceReportsEvent( context
code: 'presence_state', deviceUuid: device.uuid!)); .read<WallSensorBloc>()
.add(GetDeviceReportsEvent(code: 'presence_state', deviceUuid: device.uuid!));
}, },
child: const PresenceStaticWidget( child: const PresenceStaticWidget(
icon: Assets.presenceRecordIcon, icon: Assets.presenceRecordIcon,

View File

@ -1,6 +1,7 @@
// water_heater_bloc.dart // water_heater_bloc.dart
import 'dart:async'; import 'dart:async';
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -30,6 +31,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
on<GetSchedulesEvent>(_getSchedule); on<GetSchedulesEvent>(_getSchedule);
on<AddScheduleEvent>(_onAddSchedule); on<AddScheduleEvent>(_onAddSchedule);
on<EditWaterHeaterScheduleEvent>(_onEditSchedule);
on<DeleteScheduleEvent>(_onDeleteSchedule); on<DeleteScheduleEvent>(_onDeleteSchedule);
on<UpdateScheduleEntryEvent>(_onUpdateSchedule); on<UpdateScheduleEntryEvent>(_onUpdateSchedule);
} }
@ -76,8 +78,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
final currentState = state as WaterHeaterDeviceStatusLoaded; final currentState = state as WaterHeaterDeviceStatusLoaded;
final updatedDays = List<bool>.from(currentState.selectedDays); final updatedDays = List<bool>.from(currentState.selectedDays);
updatedDays[event.index] = event.value; updatedDays[event.index] = event.value;
emit(currentState.copyWith( emit(currentState.copyWith(selectedDays: updatedDays, selectedTime: currentState.selectedTime));
selectedDays: updatedDays, selectedTime: currentState.selectedTime));
} }
FutureOr<void> _updateFunctionOn( FutureOr<void> _updateFunctionOn(
@ -85,8 +86,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
Emitter<WaterHeaterState> emit, Emitter<WaterHeaterState> emit,
) { ) {
final currentState = state as WaterHeaterDeviceStatusLoaded; final currentState = state as WaterHeaterDeviceStatusLoaded;
emit(currentState.copyWith( emit(currentState.copyWith(functionOn: event.isOn, selectedTime: currentState.selectedTime));
functionOn: event.isOn, selectedTime: currentState.selectedTime));
} }
FutureOr<void> _updateScheduleEvent( FutureOr<void> _updateScheduleEvent(
@ -101,8 +101,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
)); ));
} }
if (event.scheduleMode == ScheduleModes.countdown) { if (event.scheduleMode == ScheduleModes.countdown) {
final countdownRemaining = final countdownRemaining = Duration(hours: event.hours, minutes: event.minutes);
Duration(hours: event.hours, minutes: event.minutes);
emit(currentState.copyWith( emit(currentState.copyWith(
scheduleMode: ScheduleModes.countdown, scheduleMode: ScheduleModes.countdown,
@ -112,13 +111,11 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
countdownRemaining: countdownRemaining, countdownRemaining: countdownRemaining,
)); ));
if (!currentState.isCountdownActive! && if (!currentState.isCountdownActive! && countdownRemaining > Duration.zero) {
countdownRemaining > Duration.zero) {
_startCountdownTimer(emit, countdownRemaining); _startCountdownTimer(emit, countdownRemaining);
} }
} else if (event.scheduleMode == ScheduleModes.inching) { } else if (event.scheduleMode == ScheduleModes.inching) {
final inchingDuration = final inchingDuration = Duration(hours: event.hours, minutes: event.minutes);
Duration(hours: event.hours, minutes: event.minutes);
emit(currentState.copyWith( emit(currentState.copyWith(
scheduleMode: ScheduleModes.inching, scheduleMode: ScheduleModes.inching,
@ -220,8 +217,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
try { try {
final status = await DevicesManagementApi().deviceControl( final status = await DevicesManagementApi().deviceControl(
event.deviceId, event.deviceId,
Status( Status(code: isCountDown ? 'countdown_1' : 'switch_inching', value: 0),
code: isCountDown ? 'countdown_1' : 'switch_inching', value: 0),
); );
if (!status) { if (!status) {
emit(const WaterHeaterFailedState(error: 'Failed to stop schedule.')); emit(const WaterHeaterFailedState(error: 'Failed to stop schedule.'));
@ -239,10 +235,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
emit(WaterHeaterLoadingState()); emit(WaterHeaterLoadingState());
try { try {
final status = final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
await DevicesManagementApi().getDeviceStatus(event.deviceId); deviceStatus = WaterHeaterStatusModel.fromJson(event.deviceId, status.status);
deviceStatus =
WaterHeaterStatusModel.fromJson(event.deviceId, status.status);
if (deviceStatus.scheduleMode == ScheduleModes.countdown) { if (deviceStatus.scheduleMode == ScheduleModes.countdown) {
final countdownRemaining = Duration( final countdownRemaining = Duration(
@ -340,10 +334,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
if (state is WaterHeaterDeviceStatusLoaded) { if (state is WaterHeaterDeviceStatusLoaded) {
final currentState = state as WaterHeaterDeviceStatusLoaded; final currentState = state as WaterHeaterDeviceStatusLoaded;
if (currentState.countdownRemaining != null && if (currentState.countdownRemaining != null && currentState.countdownRemaining! > Duration.zero) {
currentState.countdownRemaining! > Duration.zero) { final newRemaining = currentState.countdownRemaining! - const Duration(minutes: 1);
final newRemaining =
currentState.countdownRemaining! - const Duration(minutes: 1);
if (newRemaining <= Duration.zero) { if (newRemaining <= Duration.zero) {
_countdownTimer?.cancel(); _countdownTimer?.cancel();
@ -438,8 +430,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
} }
} }
void _revertValue(String code, dynamic oldValue, void _revertValue(String code, dynamic oldValue, void Function(WaterHeaterState state) emit) {
void Function(WaterHeaterState state) emit) {
_updateLocalValue(code, oldValue); _updateLocalValue(code, oldValue);
if (state is WaterHeaterDeviceStatusLoaded) { if (state is WaterHeaterDeviceStatusLoaded) {
final currentState = state as WaterHeaterDeviceStatusLoaded; final currentState = state as WaterHeaterDeviceStatusLoaded;
@ -486,13 +477,12 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
return super.close(); return super.close();
} }
FutureOr<void> _getSchedule( FutureOr<void> _getSchedule(GetSchedulesEvent event, Emitter<WaterHeaterState> emit) async {
GetSchedulesEvent event, Emitter<WaterHeaterState> emit) async {
emit(ScheduleLoadingState()); emit(ScheduleLoadingState());
try { try {
List<ScheduleModel> schedules = await DevicesManagementApi() List<ScheduleModel> schedules =
.getDeviceSchedules(deviceStatus.uuid, event.category); await DevicesManagementApi().getDeviceSchedules(deviceStatus.uuid, event.category);
emit(WaterHeaterDeviceStatusLoaded( emit(WaterHeaterDeviceStatusLoaded(
deviceStatus, deviceStatus,
@ -524,8 +514,35 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
// emit(ScheduleLoadingState()); // emit(ScheduleLoadingState());
bool success = await DevicesManagementApi() bool success = await DevicesManagementApi().addScheduleRecord(newSchedule, currentState.status.uuid);
.addScheduleRecord(newSchedule, currentState.status.uuid);
if (success) {
add(GetSchedulesEvent(category: 'switch_1', uuid: deviceStatus.uuid));
} else {
emit(currentState);
//emit(const WaterHeaterFailedState(error: 'Failed to add schedule.'));
}
}
}
FutureOr<void> _onEditSchedule(EditWaterHeaterScheduleEvent event, Emitter<WaterHeaterState> emit) async {
if (state is WaterHeaterDeviceStatusLoaded) {
final currentState = state as WaterHeaterDeviceStatusLoaded;
ScheduleEntry newSchedule = ScheduleEntry(
scheduleId: event.scheduleId,
category: event.category,
time: formatTimeOfDayToISO(event.time),
function: Status(code: 'switch_1', value: event.functionOn),
days: ScheduleModel.convertSelectedDaysToStrings(event.selectedDays),
);
// emit(ScheduleLoadingState());
bool success = await DevicesManagementApi().editScheduleRecord(
currentState.status.uuid,
newSchedule,
);
if (success) { if (success) {
add(GetSchedulesEvent(category: 'switch_1', uuid: deviceStatus.uuid)); add(GetSchedulesEvent(category: 'switch_1', uuid: deviceStatus.uuid));
@ -577,13 +594,11 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
// emit(ScheduleLoadingState()); // emit(ScheduleLoadingState());
bool success = await DevicesManagementApi() bool success = await DevicesManagementApi().deleteScheduleRecord(currentState.status.uuid, event.scheduleId);
.deleteScheduleRecord(currentState.status.uuid, event.scheduleId);
if (success) { if (success) {
final updatedSchedules = currentState.schedules final updatedSchedules =
.where((schedule) => schedule.scheduleId != event.scheduleId) currentState.schedules.where((schedule) => schedule.scheduleId != event.scheduleId).toList();
.toList();
emit(currentState.copyWith(schedules: updatedSchedules)); emit(currentState.copyWith(schedules: updatedSchedules));
} else { } else {
@ -593,15 +608,12 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
} }
} }
FutureOr<void> _batchFetchWaterHeater(FetchWaterHeaterBatchStatusEvent event, FutureOr<void> _batchFetchWaterHeater(FetchWaterHeaterBatchStatusEvent event, Emitter<WaterHeaterState> emit) async {
Emitter<WaterHeaterState> emit) async {
emit(WaterHeaterLoadingState()); emit(WaterHeaterLoadingState());
try { try {
final status = final status = await DevicesManagementApi().getBatchStatus(event.devicesUuid);
await DevicesManagementApi().getBatchStatus(event.devicesUuid); deviceStatus = WaterHeaterStatusModel.fromJson(event.devicesUuid.first, status.status);
deviceStatus = WaterHeaterStatusModel.fromJson(
event.devicesUuid.first, status.status);
emit(WaterHeaterDeviceStatusLoaded(deviceStatus)); emit(WaterHeaterDeviceStatusLoaded(deviceStatus));
} catch (e) { } catch (e) {
@ -609,8 +621,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
} }
} }
FutureOr<void> _batchControlWaterHeater(ControlWaterHeaterBatchEvent event, FutureOr<void> _batchControlWaterHeater(ControlWaterHeaterBatchEvent event, Emitter<WaterHeaterState> emit) async {
Emitter<WaterHeaterState> emit) async {
if (state is WaterHeaterDeviceStatusLoaded) { if (state is WaterHeaterDeviceStatusLoaded) {
final currentState = state as WaterHeaterDeviceStatusLoaded; final currentState = state as WaterHeaterDeviceStatusLoaded;

View File

@ -71,6 +71,22 @@ final class AddScheduleEvent extends WaterHeaterEvent {
List<Object?> get props => [selectedDays, time, functionOn, category]; List<Object?> get props => [selectedDays, time, functionOn, category];
} }
class EditWaterHeaterScheduleEvent extends WaterHeaterEvent {
final String scheduleId;
final String category;
final TimeOfDay time;
final bool functionOn;
final List<bool> selectedDays;
const EditWaterHeaterScheduleEvent({
required this.scheduleId,
required this.category,
required this.time,
required this.functionOn,
required this.selectedDays,
});
}
final class DeleteScheduleEvent extends WaterHeaterEvent { final class DeleteScheduleEvent extends WaterHeaterEvent {
final int index; final int index;
final String scheduleId; final String scheduleId;

View File

@ -1,14 +1,13 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
import 'package:syncrow_web/pages/device_managment/water_heater/bloc/water_heater_bloc.dart'; import 'package:syncrow_web/pages/device_managment/water_heater/bloc/water_heater_bloc.dart';
import 'package:syncrow_web/pages/device_managment/water_heater/models/schedule_model.dart'; import 'package:syncrow_web/pages/device_managment/water_heater/models/schedule_model.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/extension/build_context_x.dart';
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
class ScheduleDialogHelper { class ScheduleDialogHelper {
static void showAddScheduleDialog(BuildContext context, static void showAddScheduleDialog(BuildContext context, {ScheduleModel? schedule, int? index, bool? isEdit}) {
{ScheduleModel? schedule, int? index, bool? isEdit}) {
final bloc = context.read<WaterHeaterBloc>(); final bloc = context.read<WaterHeaterBloc>();
if (schedule == null) { if (schedule == null) {
@ -70,13 +69,10 @@ class ScheduleDialogHelper {
padding: 8, padding: 8,
backgroundColor: ColorsManager.boxColor, backgroundColor: ColorsManager.boxColor,
borderRadius: 15, borderRadius: 15,
onPressed: isEdit == true onPressed: () async {
? null
: () async {
TimeOfDay? time = await showTimePicker( TimeOfDay? time = await showTimePicker(
context: context, context: context,
initialTime: initialTime: state.selectedTime ?? TimeOfDay.now(),
state.selectedTime ?? TimeOfDay.now(),
builder: (context, child) { builder: (context, child) {
return Theme( return Theme(
data: Theme.of(context).copyWith( data: Theme.of(context).copyWith(
@ -96,9 +92,7 @@ class ScheduleDialogHelper {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
state.selectedTime == null state.selectedTime == null ? 'Time' : state.selectedTime!.format(context),
? 'Time'
: state.selectedTime!.format(context),
style: context.textTheme.bodySmall!.copyWith( style: context.textTheme.bodySmall!.copyWith(
color: ColorsManager.grayColor, color: ColorsManager.grayColor,
), ),
@ -113,8 +107,7 @@ class ScheduleDialogHelper {
), ),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
_buildDayCheckboxes(context, state.selectedDays, _buildDayCheckboxes(context, state.selectedDays, isEdit: isEdit),
isEdit: isEdit),
const SizedBox(height: 16), const SizedBox(height: 16),
_buildFunctionSwitch(context, state.functionOn, isEdit), _buildFunctionSwitch(context, state.functionOn, isEdit),
], ],
@ -141,7 +134,13 @@ class ScheduleDialogHelper {
onPressed: () { onPressed: () {
if (state.selectedTime != null) { if (state.selectedTime != null) {
if (state.isEditing && index != null) { if (state.isEditing && index != null) {
return; bloc.add(EditWaterHeaterScheduleEvent(
scheduleId: schedule?.scheduleId ?? '',
category: 'switch_1',
time: state.selectedTime!,
selectedDays: state.selectedDays,
functionOn: state.functionOn,
));
} else { } else {
bloc.add(AddScheduleEvent( bloc.add(AddScheduleEvent(
category: 'switch_1', category: 'switch_1',
@ -193,9 +192,7 @@ class ScheduleDialogHelper {
return daysBoolean; return daysBoolean;
} }
static Widget _buildDayCheckboxes( static Widget _buildDayCheckboxes(BuildContext context, List<bool> selectedDays, {bool? isEdit}) {
BuildContext context, List<bool> selectedDays,
{bool? isEdit}) {
final dayLabels = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; final dayLabels = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
return Row( return Row(
@ -204,12 +201,8 @@ class ScheduleDialogHelper {
children: [ children: [
Checkbox( Checkbox(
value: selectedDays[index], value: selectedDays[index],
onChanged: isEdit == true onChanged: (bool? value) {
? null context.read<WaterHeaterBloc>().add(UpdateSelectedDayEvent(index, value!));
: (bool? value) {
context
.read<WaterHeaterBloc>()
.add(UpdateSelectedDayEvent(index, value!));
}, },
), ),
Text(dayLabels[index]), Text(dayLabels[index]),
@ -219,27 +212,19 @@ class ScheduleDialogHelper {
); );
} }
static Widget _buildFunctionSwitch( static Widget _buildFunctionSwitch(BuildContext context, bool isOn, bool? isEdit) {
BuildContext context, bool isOn, bool? isEdit) {
return Row( return Row(
children: [ children: [
Text( Text(
'Function:', 'Function:',
style: context.textTheme.bodySmall! style: context.textTheme.bodySmall!.copyWith(color: ColorsManager.grayColor),
.copyWith(color: ColorsManager.grayColor),
), ),
const SizedBox(width: 10), const SizedBox(width: 10),
Radio<bool>( Radio<bool>(
value: true, value: true,
groupValue: isOn, groupValue: isOn,
onChanged: (bool? value) { onChanged: (bool? value) {
if (isEdit == true) { context.read<WaterHeaterBloc>().add(const UpdateFunctionOnEvent(true));
return;
} else {
context
.read<WaterHeaterBloc>()
.add(const UpdateFunctionOnEvent(true));
}
}, },
), ),
const Text('On'), const Text('On'),
@ -248,13 +233,7 @@ class ScheduleDialogHelper {
value: false, value: false,
groupValue: isOn, groupValue: isOn,
onChanged: (bool? value) { onChanged: (bool? value) {
if (isEdit == true) { context.read<WaterHeaterBloc>().add(const UpdateFunctionOnEvent(false));
return;
} else {
context
.read<WaterHeaterBloc>()
.add(const UpdateFunctionOnEvent(false));
}
}, },
), ),
const Text('Off'), const Text('Off'),

View File

@ -1,7 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
class ScheduleEntry { class ScheduleEntry {
@ -9,12 +8,14 @@ class ScheduleEntry {
final String time; final String time;
final Status function; final Status function;
final List<String> days; final List<String> days;
final String? scheduleId;
ScheduleEntry({ ScheduleEntry({
required this.category, required this.category,
required this.time, required this.time,
required this.function, required this.function,
required this.days, required this.days,
this.scheduleId,
}); });
@override @override
@ -38,6 +39,7 @@ class ScheduleEntry {
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
return { return {
'scheduleId': scheduleId,
'category': category, 'category': category,
'time': time, 'time': time,
'function': function.toMap(), 'function': function.toMap(),
@ -56,8 +58,7 @@ class ScheduleEntry {
String toJson() => json.encode(toMap()); String toJson() => json.encode(toMap());
factory ScheduleEntry.fromJson(String source) => factory ScheduleEntry.fromJson(String source) => ScheduleEntry.fromMap(json.decode(source));
ScheduleEntry.fromMap(json.decode(source));
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
@ -72,9 +73,6 @@ class ScheduleEntry {
@override @override
int get hashCode { int get hashCode {
return category.hashCode ^ return category.hashCode ^ time.hashCode ^ function.hashCode ^ days.hashCode;
time.hashCode ^
function.hashCode ^
days.hashCode;
} }
} }

View File

@ -2,9 +2,18 @@ import 'package:flutter/material.dart';
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart'; import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
class WaterLeakNotificationDialog extends StatelessWidget { class WaterLeakNotificationDialog extends StatefulWidget {
const WaterLeakNotificationDialog({super.key}); const WaterLeakNotificationDialog({super.key});
@override
State<WaterLeakNotificationDialog> createState() => _NotificationDialogState();
}
class _NotificationDialogState extends State<WaterLeakNotificationDialog> {
bool isLowBatteryNotificationEnabled = true;
bool isClosingRemindersEnabled = true;
bool isWaterLeakage = true;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Dialog( return Dialog(
@ -14,7 +23,7 @@ class WaterLeakNotificationDialog extends StatelessWidget {
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
), ),
child: SizedBox( child: SizedBox(
width: 400, width: 560,
child: SingleChildScrollView( child: SingleChildScrollView(
child: Padding( child: Padding(
padding: const EdgeInsets.all(20.0), padding: const EdgeInsets.all(20.0),
@ -61,22 +70,38 @@ class WaterLeakNotificationDialog extends StatelessWidget {
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
ToggleWidget( SizedBox(
value: true, width: 170,
height: 135,
child: ToggleWidget(
value: isLowBatteryNotificationEnabled,
code: 'notification', code: 'notification',
deviceId: '', deviceId: '',
label: 'Low Battery', label: 'Low Battery',
onChange: (v) {}, onChange: (v) {
setState(() {
isLowBatteryNotificationEnabled = v;
});
},
icon: '-1', icon: '-1',
), ),
ToggleWidget( ),
value: true, SizedBox(
width: 170,
height: 135,
child: ToggleWidget(
value: isWaterLeakage,
code: 'notification', code: 'notification',
deviceId: '', deviceId: '',
label: 'Water Leakage', label: 'Water Leakage',
onChange: (v) {}, onChange: (v) {
setState(() {
isWaterLeakage = v;
});
},
icon: '-1', icon: '-1',
), ),
),
], ],
), ),
], ],

View File

@ -76,7 +76,8 @@ class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordStat
Future<void> selectTimeVisitorPassword( Future<void> selectTimeVisitorPassword(
SelectTimeVisitorPassword event, SelectTimeVisitorPassword event,
Emitter<VisitorPasswordState> emit,) async { Emitter<VisitorPasswordState> emit,
) async {
final DateTime? picked = await showDatePicker( final DateTime? picked = await showDatePicker(
context: event.context, context: event.context,
initialDate: DateTime.now(), initialDate: DateTime.now(),
@ -359,7 +360,6 @@ class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordStat
context: event.context, context: event.context,
initialTime: TimeOfDay.now(), initialTime: TimeOfDay.now(),
); );
print('timePicked=$timePicked');
if (timePicked != null) { if (timePicked != null) {
final selectedDateTime = DateTime( final selectedDateTime = DateTime(

View File

@ -1,6 +1,6 @@
import 'package:syncrow_web/utils/constants/app_enum.dart';
import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/enum/device_types.dart'; import 'package:syncrow_web/utils/enum/device_types.dart';
import 'package:syncrow_web/utils/constants/app_enum.dart';
class DeviceModel { class DeviceModel {
dynamic productUuid; dynamic productUuid;
@ -51,7 +51,6 @@ class DeviceModel {
factory DeviceModel.fromJson(Map<String, dynamic> json) { factory DeviceModel.fromJson(Map<String, dynamic> json) {
String tempIcon = ''; String tempIcon = '';
DeviceType type = devicesTypesMap[json['productType']] ?? DeviceType.Other; DeviceType type = devicesTypesMap[json['productType']] ?? DeviceType.Other;
if (type == DeviceType.LightBulb) { if (type == DeviceType.LightBulb) {
tempIcon = Assets.lightBulb; tempIcon = Assets.lightBulb;
} else if (type == DeviceType.CeilingSensor || type == DeviceType.WallSensor) { } else if (type == DeviceType.CeilingSensor || type == DeviceType.WallSensor) {
@ -66,9 +65,22 @@ class DeviceModel {
tempIcon = Assets.gangSwitch; tempIcon = Assets.gangSwitch;
} else if (type == DeviceType.Gateway) { } else if (type == DeviceType.Gateway) {
tempIcon = Assets.gateway; tempIcon = Assets.gateway;
} else if (type == DeviceType.OneGang) {
tempIcon = Assets.oneGang;
} else if (type == DeviceType.TwoGang) {
tempIcon = Assets.twoGang;
} else if (type == DeviceType.WH) {
tempIcon = Assets.waterHeater;
} else if (type == DeviceType.DoorSensor) {
tempIcon = Assets.openCloseDoor;
} else if (type == DeviceType.GarageDoor) {
tempIcon = Assets.openedDoor;
} else if (type == DeviceType.WaterLeak) {
tempIcon = Assets.waterLeakNormal;
} else { } else {
tempIcon = Assets.logo; tempIcon = Assets.blackLogo;
} }
return DeviceModel( return DeviceModel(
productUuid: json['productUuid'], productUuid: json['productUuid'],
productType: json['productType'], productType: json['productType'],

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_web/pages/common/custom_table.dart'; import 'package:syncrow_web/pages/common/access_device_table.dart';
import 'package:syncrow_web/pages/common/text_field/custom_web_textfield.dart'; import 'package:syncrow_web/pages/common/text_field/custom_web_textfield.dart';
import 'package:syncrow_web/pages/common/buttons/default_button.dart'; import 'package:syncrow_web/pages/common/buttons/default_button.dart';
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart'; import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart';
@ -49,7 +49,7 @@ class AddDeviceDialog extends StatelessWidget {
children: <Widget>[ children: <Widget>[
Container( Container(
width: size.width, width: size.width,
padding: EdgeInsets.all(15), padding: const EdgeInsets.all(15),
decoration: containerDecoration.copyWith( decoration: containerDecoration.copyWith(
color: ColorsManager.worningColor, color: ColorsManager.worningColor,
border: Border.all(color: Color(0xffFFD22F)), border: Border.all(color: Color(0xffFFD22F)),
@ -163,7 +163,7 @@ class AddDeviceDialog extends StatelessWidget {
Expanded( Expanded(
flex: 3, flex: 3,
child: state is TableLoaded child: state is TableLoaded
? DynamicTable( ? AccessDeviceTable(
uuidIndex: 1, uuidIndex: 1,
withSelectAll: true, withSelectAll: true,
initialSelectedIds: selectedDeviceIds, initialSelectedIds: selectedDeviceIds,

View File

@ -12,7 +12,6 @@ class AccessMangApi {
path: ApiEndpoints.visitorPassword, path: ApiEndpoints.visitorPassword,
showServerMessage: true, showServerMessage: true,
expectedResponseModel: (json) { expectedResponseModel: (json) {
print(json);
List<dynamic> jsonData = json; List<dynamic> jsonData = json;
List<PasswordModel> passwordList = jsonData.map((jsonItem) { List<PasswordModel> passwordList = jsonData.map((jsonItem) {
return PasswordModel.fromJson(jsonItem); return PasswordModel.fromJson(jsonItem);

View File

@ -68,8 +68,7 @@ class DevicesManagementApi {
} }
} }
Future<bool> deviceBatchControl( Future<bool> deviceBatchControl(List<String> uuids, String code, dynamic value) async {
List<String> uuids, String code, dynamic value) async {
try { try {
final body = { final body = {
'devicesUuid': uuids, 'devicesUuid': uuids,
@ -93,8 +92,7 @@ class DevicesManagementApi {
} }
} }
static Future<List<DeviceModel>> getDevicesByGatewayId( static Future<List<DeviceModel>> getDevicesByGatewayId(String gatewayId) async {
String gatewayId) async {
final response = await HTTPService().get( final response = await HTTPService().get(
path: ApiEndpoints.gatewayApi.replaceAll('{gatewayUuid}', gatewayId), path: ApiEndpoints.gatewayApi.replaceAll('{gatewayUuid}', gatewayId),
showServerMessage: false, showServerMessage: false,
@ -128,9 +126,7 @@ class DevicesManagementApi {
String code, String code,
) async { ) async {
final response = await HTTPService().get( final response = await HTTPService().get(
path: ApiEndpoints.getDeviceLogs path: ApiEndpoints.getDeviceLogs.replaceAll('{uuid}', uuid).replaceAll('{code}', code),
.replaceAll('{uuid}', uuid)
.replaceAll('{code}', code),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return DeviceReport.fromJson(json); return DeviceReport.fromJson(json);
@ -139,8 +135,7 @@ class DevicesManagementApi {
return response; return response;
} }
static Future<DeviceReport> getDeviceReportsByDate(String uuid, String code, static Future<DeviceReport> getDeviceReportsByDate(String uuid, String code, [String? from, String? to]) async {
[String? from, String? to]) async {
final response = await HTTPService().get( final response = await HTTPService().get(
path: ApiEndpoints.getDeviceLogsByDate path: ApiEndpoints.getDeviceLogsByDate
.replaceAll('{uuid}', uuid) .replaceAll('{uuid}', uuid)
@ -179,8 +174,7 @@ class DevicesManagementApi {
} }
} }
Future<bool> addScheduleRecord( Future<bool> addScheduleRecord(ScheduleEntry sendSchedule, String uuid) async {
ScheduleEntry sendSchedule, String uuid) async {
try { try {
final response = await HTTPService().post( final response = await HTTPService().post(
path: ApiEndpoints.scheduleByDeviceId.replaceAll('{deviceUuid}', uuid), path: ApiEndpoints.scheduleByDeviceId.replaceAll('{deviceUuid}', uuid),
@ -197,13 +191,10 @@ class DevicesManagementApi {
} }
} }
Future<List<ScheduleModel>> getDeviceSchedules( Future<List<ScheduleModel>> getDeviceSchedules(String uuid, String category) async {
String uuid, String category) async {
try { try {
final response = await HTTPService().get( final response = await HTTPService().get(
path: ApiEndpoints.getScheduleByDeviceId path: ApiEndpoints.getScheduleByDeviceId.replaceAll('{deviceUuid}', uuid).replaceAll('{category}', category),
.replaceAll('{deviceUuid}', uuid)
.replaceAll('{category}', category),
showServerMessage: true, showServerMessage: true,
expectedResponseModel: (json) { expectedResponseModel: (json) {
List<ScheduleModel> schedules = []; List<ScheduleModel> schedules = [];
@ -220,10 +211,7 @@ class DevicesManagementApi {
} }
} }
Future<bool> updateScheduleRecord( Future<bool> updateScheduleRecord({required bool enable, required String uuid, required String scheduleId}) async {
{required bool enable,
required String uuid,
required String scheduleId}) async {
try { try {
final response = await HTTPService().put( final response = await HTTPService().put(
path: ApiEndpoints.updateScheduleByDeviceId path: ApiEndpoints.updateScheduleByDeviceId
@ -244,6 +232,22 @@ class DevicesManagementApi {
} }
} }
Future<bool> editScheduleRecord(String uuid, ScheduleEntry newSchedule) async {
try {
final response = await HTTPService().put(
path: ApiEndpoints.scheduleByDeviceId.replaceAll('{deviceUuid}', uuid),
body: newSchedule.toMap(),
expectedResponseModel: (json) {
return json['success'] ?? false;
},
);
return response;
} catch (e) {
debugPrint('Error fetching $e');
return false;
}
}
Future<bool> deleteScheduleRecord(String uuid, String scheduleId) async { Future<bool> deleteScheduleRecord(String uuid, String scheduleId) async {
try { try {
final response = await HTTPService().delete( final response = await HTTPService().delete(

View File

@ -5,8 +5,7 @@ abstract class ColorsManager {
static const Color switchOffColor = Color(0x7F8D99AE); static const Color switchOffColor = Color(0x7F8D99AE);
static const Color primaryColor = Color(0xFF0030CB); //023DFE static const Color primaryColor = Color(0xFF0030CB); //023DFE
static const Color secondaryTextColor = Color(0xFF848484); static const Color secondaryTextColor = Color(0xFF848484);
static Color primaryColorWithOpacity = static Color primaryColorWithOpacity = const Color(0xFF023DFE).withOpacity(0.6);
const Color(0xFF023DFE).withOpacity(0.6);
static const Color whiteColors = Colors.white; static const Color whiteColors = Colors.white;
static const Color secondaryColor = Color(0xFF023DFE); static const Color secondaryColor = Color(0xFF023DFE);
static const Color onSecondaryColor = Color(0xFF023DFE); static const Color onSecondaryColor = Color(0xFF023DFE);

View File

@ -13,12 +13,10 @@ class Assets {
static const String rightLine = "assets/images/right_line.png"; static const String rightLine = "assets/images/right_line.png";
static const String google = "assets/images/google.svg"; static const String google = "assets/images/google.svg";
static const String facebook = "assets/images/facebook.svg"; static const String facebook = "assets/images/facebook.svg";
static const String invisiblePassword = static const String invisiblePassword = "assets/images/Password_invisible.svg";
"assets/images/Password_invisible.svg";
static const String visiblePassword = "assets/images/password_visible.svg"; static const String visiblePassword = "assets/images/password_visible.svg";
static const String accessIcon = "assets/images/access_icon.svg"; static const String accessIcon = "assets/images/access_icon.svg";
static const String spaseManagementIcon = static const String spaseManagementIcon = "assets/images/spase_management_icon.svg";
"assets/images/spase_management_icon.svg";
static const String devicesIcon = "assets/images/devices_icon.svg"; static const String devicesIcon = "assets/images/devices_icon.svg";
static const String moveinIcon = "assets/images/movein_icon.svg"; static const String moveinIcon = "assets/images/movein_icon.svg";
static const String constructionIcon = "assets/images/construction_icon.svg"; static const String constructionIcon = "assets/images/construction_icon.svg";
@ -31,15 +29,13 @@ class Assets {
static const String emptyTable = "assets/images/empty_table.svg"; static const String emptyTable = "assets/images/empty_table.svg";
// General assets // General assets
static const String motionlessDetection = static const String motionlessDetection = "assets/icons/motionless_detection.svg";
"assets/icons/motionless_detection.svg";
static const String acHeating = "assets/icons/ac_heating.svg"; static const String acHeating = "assets/icons/ac_heating.svg";
static const String acPowerOff = "assets/icons/ac_power_off.svg"; static const String acPowerOff = "assets/icons/ac_power_off.svg";
static const String acFanMiddle = "assets/icons/ac_fan_middle.svg"; static const String acFanMiddle = "assets/icons/ac_fan_middle.svg";
static const String switchAlarmSound = "assets/icons/switch_alarm_sound.svg"; static const String switchAlarmSound = "assets/icons/switch_alarm_sound.svg";
static const String resetOff = "assets/icons/reset_off.svg"; static const String resetOff = "assets/icons/reset_off.svg";
static const String sensitivityOperationIcon = static const String sensitivityOperationIcon = "assets/icons/sesitivity_operation_icon.svg";
"assets/icons/sesitivity_operation_icon.svg";
static const String motionDetection = "assets/icons/motion_detection.svg"; static const String motionDetection = "assets/icons/motion_detection.svg";
static const String freezing = "assets/icons/freezing.svg"; static const String freezing = "assets/icons/freezing.svg";
static const String indicator = "assets/icons/indicator.svg"; static const String indicator = "assets/icons/indicator.svg";
@ -60,56 +56,35 @@ class Assets {
static const String celsiusDegrees = "assets/icons/celsius_degrees.svg"; static const String celsiusDegrees = "assets/icons/celsius_degrees.svg";
static const String masterState = "assets/icons/master_state.svg"; static const String masterState = "assets/icons/master_state.svg";
static const String acPower = "assets/icons/ac_power.svg"; static const String acPower = "assets/icons/ac_power.svg";
static const String farDetectionFunction = static const String farDetectionFunction = "assets/icons/far_detection_function.svg";
"assets/icons/far_detection_function.svg";
static const String nobodyTime = "assets/icons/nobody_time.svg"; static const String nobodyTime = "assets/icons/nobody_time.svg";
// Automation functions // Automation functions
static const String tempPasswordUnlock = static const String tempPasswordUnlock = "assets/icons/automation_functions/temp_password_unlock.svg";
"assets/icons/automation_functions/temp_password_unlock.svg"; static const String doorlockNormalOpen = "assets/icons/automation_functions/doorlock_normal_open.svg";
static const String doorlockNormalOpen = static const String doorbell = "assets/icons/automation_functions/doorbell.svg";
"assets/icons/automation_functions/doorlock_normal_open.svg"; static const String remoteUnlockViaApp = "assets/icons/automation_functions/remote_unlock_via_app.svg";
static const String doorbell = static const String doubleLock = "assets/icons/automation_functions/double_lock.svg";
"assets/icons/automation_functions/doorbell.svg"; static const String selfTestResult = "assets/icons/automation_functions/self_test_result.svg";
static const String remoteUnlockViaApp = static const String lockAlarm = "assets/icons/automation_functions/lock_alarm.svg";
"assets/icons/automation_functions/remote_unlock_via_app.svg"; static const String presenceState = "assets/icons/automation_functions/presence_state.svg";
static const String doubleLock = static const String currentTemp = "assets/icons/automation_functions/current_temp.svg";
"assets/icons/automation_functions/double_lock.svg"; static const String presence = "assets/icons/automation_functions/presence.svg";
static const String selfTestResult = static const String residualElectricity = "assets/icons/automation_functions/residual_electricity.svg";
"assets/icons/automation_functions/self_test_result.svg"; static const String hijackAlarm = "assets/icons/automation_functions/hijack_alarm.svg";
static const String lockAlarm = static const String passwordUnlock = "assets/icons/automation_functions/password_unlock.svg";
"assets/icons/automation_functions/lock_alarm.svg"; static const String remoteUnlockRequest = "assets/icons/automation_functions/remote_unlock_req.svg";
static const String presenceState = static const String cardUnlock = "assets/icons/automation_functions/card_unlock.svg";
"assets/icons/automation_functions/presence_state.svg";
static const String currentTemp =
"assets/icons/automation_functions/current_temp.svg";
static const String presence =
"assets/icons/automation_functions/presence.svg";
static const String residualElectricity =
"assets/icons/automation_functions/residual_electricity.svg";
static const String hijackAlarm =
"assets/icons/automation_functions/hijack_alarm.svg";
static const String passwordUnlock =
"assets/icons/automation_functions/password_unlock.svg";
static const String remoteUnlockRequest =
"assets/icons/automation_functions/remote_unlock_req.svg";
static const String cardUnlock =
"assets/icons/automation_functions/card_unlock.svg";
static const String motion = "assets/icons/automation_functions/motion.svg"; static const String motion = "assets/icons/automation_functions/motion.svg";
static const String fingerprintUnlock = static const String fingerprintUnlock = "assets/icons/automation_functions/fingerprint_unlock.svg";
"assets/icons/automation_functions/fingerprint_unlock.svg";
// Presence Sensor Assets // Presence Sensor Assets
static const String sensorMotionIcon = "assets/icons/sensor_motion_ic.svg"; static const String sensorMotionIcon = "assets/icons/sensor_motion_ic.svg";
static const String sensorPresenceIcon = static const String sensorPresenceIcon = "assets/icons/sensor_presence_ic.svg";
"assets/icons/sensor_presence_ic.svg";
static const String sensorVacantIcon = "assets/icons/sensor_vacant_ic.svg"; static const String sensorVacantIcon = "assets/icons/sensor_vacant_ic.svg";
static const String illuminanceRecordIcon = static const String illuminanceRecordIcon = "assets/icons/illuminance_record_ic.svg";
"assets/icons/illuminance_record_ic.svg"; static const String presenceRecordIcon = "assets/icons/presence_record_ic.svg";
static const String presenceRecordIcon = static const String helpDescriptionIcon = "assets/icons/help_description_ic.svg";
"assets/icons/presence_record_ic.svg";
static const String helpDescriptionIcon =
"assets/icons/help_description_ic.svg";
static const String lightPulp = "assets/icons/light_pulb.svg"; static const String lightPulp = "assets/icons/light_pulb.svg";
static const String acDevice = "assets/icons/ac_device.svg"; static const String acDevice = "assets/icons/ac_device.svg";
@ -183,9 +158,14 @@ class Assets {
//assets/icons/water_leak_normal.svg //assets/icons/water_leak_normal.svg
static const String waterLeakNormal = 'assets/icons/water_leak_normal.svg'; static const String waterLeakNormal = 'assets/icons/water_leak_normal.svg';
//assets/icons/water_leak_detected.svg //assets/icons/water_leak_detected.svg
static const String waterLeakDetected = static const String waterLeakDetected = 'assets/icons/water_leak_detected.svg';
'assets/icons/water_leak_detected.svg';
//assets/icons/automation_records.svg //assets/icons/automation_records.svg
static const String automationRecords = 'assets/icons/automation_records.svg'; static const String automationRecords = 'assets/icons/automation_records.svg';
//assets/icons/1gang.svg
static const String oneGang = 'assets/icons/1gang.svg';
//assets/icons/2gang.svg
static const String twoGang = 'assets/icons/2gang.svg';
} }

View File

@ -4,12 +4,37 @@ enum DeviceType {
DoorLock, DoorLock,
Curtain, Curtain,
Blind, Blind,
OneGang,
TwoGang,
ThreeGang, ThreeGang,
Gateway, Gateway,
CeilingSensor, CeilingSensor,
WallSensor, WallSensor,
WH,
DoorSensor,
GarageDoor,
WaterLeak,
Other, Other,
} }
/*
3G:
1G:
2G:
GW:
DL:
WPS:
CPS:
AC:
CUR:
WH:
DS:
1GT:
2GT:
3GT:
GD:
WL:
*/
Map<String, DeviceType> devicesTypesMap = { Map<String, DeviceType> devicesTypesMap = {
"AC": DeviceType.AC, "AC": DeviceType.AC,
@ -18,4 +43,14 @@ Map<String, DeviceType> devicesTypesMap = {
"DL": DeviceType.DoorLock, "DL": DeviceType.DoorLock,
"WPS": DeviceType.WallSensor, "WPS": DeviceType.WallSensor,
"3G": DeviceType.ThreeGang, "3G": DeviceType.ThreeGang,
"2G": DeviceType.TwoGang,
"1G": DeviceType.OneGang,
"CUR": DeviceType.Curtain,
"WH": DeviceType.WH,
'DS': DeviceType.DoorSensor,
"1GT": DeviceType.OneGang,
"2GT": DeviceType.TwoGang,
"3GT": DeviceType.ThreeGang,
'GD': DeviceType.GarageDoor,
'WL': DeviceType.WaterLeak
}; };