diff --git a/assets/icons/account_setting.svg b/assets/icons/account_setting.svg
new file mode 100644
index 00000000..0b27b849
--- /dev/null
+++ b/assets/icons/account_setting.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/frequency_icon.svg b/assets/icons/frequency_icon.svg
new file mode 100644
index 00000000..d093af37
--- /dev/null
+++ b/assets/icons/frequency_icon.svg
@@ -0,0 +1,25 @@
+
diff --git a/assets/icons/logo-grey.svg b/assets/icons/logo-grey.svg
new file mode 100644
index 00000000..4f835d2d
--- /dev/null
+++ b/assets/icons/logo-grey.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/icons/power_active_icon.svg b/assets/icons/power_active_icon.svg
new file mode 100644
index 00000000..28b1412a
--- /dev/null
+++ b/assets/icons/power_active_icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/settings.svg b/assets/icons/settings.svg
new file mode 100644
index 00000000..c626454d
--- /dev/null
+++ b/assets/icons/settings.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/icons/sign_out.svg b/assets/icons/sign_out.svg
new file mode 100644
index 00000000..5980d13e
--- /dev/null
+++ b/assets/icons/sign_out.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/speedo_meter.svg b/assets/icons/speedo_meter.svg
new file mode 100644
index 00000000..be3b5c4b
--- /dev/null
+++ b/assets/icons/speedo_meter.svg
@@ -0,0 +1,16 @@
+
diff --git a/assets/icons/volt-meter.svg b/assets/icons/volt-meter.svg
new file mode 100644
index 00000000..6691a7dd
--- /dev/null
+++ b/assets/icons/volt-meter.svg
@@ -0,0 +1,26 @@
+
diff --git a/assets/icons/volt_meter_icon.svg b/assets/icons/volt_meter_icon.svg
new file mode 100644
index 00000000..97b9037d
--- /dev/null
+++ b/assets/icons/volt_meter_icon.svg
@@ -0,0 +1,26 @@
+
diff --git a/assets/icons/voltage_icon.svg b/assets/icons/voltage_icon.svg
new file mode 100644
index 00000000..29b06678
--- /dev/null
+++ b/assets/icons/voltage_icon.svg
@@ -0,0 +1,41 @@
+
diff --git a/lib/pages/access_management/bloc/access_bloc.dart b/lib/pages/access_management/bloc/access_bloc.dart
index 55b525b4..3e74dbff 100644
--- a/lib/pages/access_management/bloc/access_bloc.dart
+++ b/lib/pages/access_management/bloc/access_bloc.dart
@@ -5,6 +5,7 @@ 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/common/hour_picker_dialog.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/snack_bar.dart';
@@ -26,7 +27,8 @@ class AccessBloc extends Bloc {
List filteredData = [];
List data = [];
- Future _onFetchTableData(FetchTableData event, Emitter emit) async {
+ Future _onFetchTableData(
+ FetchTableData event, Emitter emit) async {
try {
emit(AccessLoaded());
data = await AccessMangApi().fetchVisitorPassword();
@@ -39,19 +41,28 @@ class AccessBloc extends Bloc {
}
void updateTabsCount() {
- int toBeEffectiveCount =
- data.where((item) => item.passwordStatus.value == 'To be effective').length;
- int effectiveCount = data.where((item) => item.passwordStatus.value == 'Effective').length;
- int expiredCount = data.where((item) => item.passwordStatus.value == 'Expired').length;
+ int toBeEffectiveCount = data
+ .where((item) => item.passwordStatus.value == 'To be effective')
+ .length;
+ int effectiveCount =
+ data.where((item) => item.passwordStatus.value == 'Effective').length;
+ int expiredCount =
+ data.where((item) => item.passwordStatus.value == 'Expired').length;
tabs[1] = 'To Be Effective ($toBeEffectiveCount)';
tabs[2] = 'Effective ($effectiveCount)';
tabs[3] = 'Expired ($expiredCount)';
}
int selectedIndex = 0;
- final List tabs = ['All', 'To Be Effective (0)', 'Effective (0)', 'Expired'];
+ final List tabs = [
+ 'All',
+ 'To Be Effective (0)',
+ 'Effective (0)',
+ 'Expired'
+ ];
- Future selectFilterTap(TabChangedEvent event, Emitter emit) async {
+ Future selectFilterTap(
+ TabChangedEvent event, Emitter emit) async {
try {
emit(AccessLoaded());
selectedIndex = event.selectedIndex;
@@ -73,6 +84,23 @@ class AccessBloc extends Bloc {
initialDate: DateTime.now(),
firstDate: DateTime.now().add(const Duration(days: -5095)),
lastDate: DateTime.now().add(const Duration(days: 2095)),
+ builder: (BuildContext context, Widget? child) {
+ return Theme(
+ data: ThemeData.light().copyWith(
+ colorScheme: ColorScheme.light(
+ primary: ColorsManager.blackColor,
+ onPrimary: Colors.white,
+ onSurface: ColorsManager.grayColor,
+ ),
+ textButtonTheme: TextButtonThemeData(
+ style: TextButton.styleFrom(
+ foregroundColor: Colors.blue,
+ ),
+ ),
+ ),
+ child: child!,
+ );
+ },
);
if (picked != null) {
final TimeOfDay? timePicked = await showHourPicker(
@@ -88,16 +116,20 @@ class AccessBloc extends Bloc {
timePicked.hour,
timePicked.minute,
);
- final int selectedTimestamp = selectedDateTime.millisecondsSinceEpoch ~/ 1000;
+ final int selectedTimestamp =
+ selectedDateTime.millisecondsSinceEpoch ~/ 1000;
if (event.isStart) {
- if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) {
- CustomSnackBar.displaySnackBar('Effective Time cannot be later than Expiration Time.');
+ if (expirationTimeTimeStamp != null &&
+ selectedTimestamp > expirationTimeTimeStamp!) {
+ CustomSnackBar.displaySnackBar(
+ 'Effective Time cannot be later than Expiration Time.');
} else {
startTime = selectedDateTime.toString().split('.').first;
effectiveTimeTimeStamp = selectedTimestamp;
}
} else {
- if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) {
+ if (effectiveTimeTimeStamp != null &&
+ selectedTimestamp < effectiveTimeTimeStamp!) {
CustomSnackBar.displaySnackBar(
'Expiration Time cannot be earlier than Effective Time.');
} else {
@@ -110,7 +142,8 @@ class AccessBloc extends Bloc {
emit(ChangeTimeState());
}
- Future _filterData(FilterDataEvent event, Emitter emit) async {
+ Future _filterData(
+ FilterDataEvent event, Emitter emit) async {
emit(AccessLoaded());
try {
// Convert search text to lower case for case-insensitive search
@@ -119,29 +152,40 @@ class AccessBloc extends Bloc {
filteredData = data.where((item) {
bool matchesCriteria = true;
// Convert timestamp to DateTime and extract date component
- DateTime effectiveDate =
- DateTime.fromMillisecondsSinceEpoch(int.parse(item.effectiveTime.toString()) * 1000)
- .toUtc()
- .toLocal();
- DateTime invalidDate =
- DateTime.fromMillisecondsSinceEpoch(int.parse(item.invalidTime.toString()) * 1000)
- .toUtc()
- .toLocal();
- DateTime effectiveDateAndTime = DateTime(effectiveDate.year, effectiveDate.month,
- effectiveDate.day, effectiveDate.hour, effectiveDate.minute);
- DateTime invalidDateAndTime = DateTime(invalidDate.year, invalidDate.month, invalidDate.day,
- invalidDate.hour, invalidDate.minute);
+ DateTime effectiveDate = DateTime.fromMillisecondsSinceEpoch(
+ int.parse(item.effectiveTime.toString()) * 1000)
+ .toUtc()
+ .toLocal();
+ DateTime invalidDate = DateTime.fromMillisecondsSinceEpoch(
+ int.parse(item.invalidTime.toString()) * 1000)
+ .toUtc()
+ .toLocal();
+ DateTime effectiveDateAndTime = DateTime(
+ effectiveDate.year,
+ effectiveDate.month,
+ 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
if (searchText.isNotEmpty) {
- final bool matchesName = item.passwordName.toString().toLowerCase().contains(searchText);
+ final bool matchesName =
+ item.passwordName.toString().toLowerCase().contains(searchText);
if (!matchesName) {
matchesCriteria = false;
}
}
if (searchEmailText.isNotEmpty) {
- final bool matchesName =
- item.authorizerEmail.toString().toLowerCase().contains(searchEmailText);
+ final bool matchesName = item.authorizerEmail
+ .toString()
+ .toLowerCase()
+ .contains(searchEmailText);
if (!matchesName) {
matchesCriteria = false;
}
@@ -149,9 +193,11 @@ class AccessBloc extends Bloc {
// Filter by start date only
if (event.startTime != null && event.endTime == null) {
DateTime startDateTime =
- DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal();
- startDateTime = DateTime(startDateTime.year, startDateTime.month, startDateTime.day,
- startDateTime.hour, startDateTime.minute);
+ DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000)
+ .toUtc()
+ .toLocal();
+ startDateTime = DateTime(startDateTime.year, startDateTime.month,
+ startDateTime.day, startDateTime.hour, startDateTime.minute);
if (effectiveDateAndTime.isBefore(startDateTime)) {
matchesCriteria = false;
}
@@ -159,9 +205,11 @@ class AccessBloc extends Bloc {
// Filter by end date only
if (event.endTime != null && event.startTime == null) {
DateTime startDateTime =
- DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000).toUtc().toLocal();
- startDateTime = DateTime(startDateTime.year, startDateTime.month, startDateTime.day,
- startDateTime.hour, startDateTime.minute);
+ DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000)
+ .toUtc()
+ .toLocal();
+ startDateTime = DateTime(startDateTime.year, startDateTime.month,
+ startDateTime.day, startDateTime.hour, startDateTime.minute);
if (invalidDateAndTime.isAfter(startDateTime)) {
matchesCriteria = false;
}
@@ -170,13 +218,17 @@ class AccessBloc extends Bloc {
// Filter by both start date and end date
if (event.startTime != null && event.endTime != null) {
DateTime startDateTime =
- DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal();
+ DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000)
+ .toUtc()
+ .toLocal();
DateTime endDateTime =
- DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000).toUtc().toLocal();
- startDateTime = DateTime(startDateTime.year, startDateTime.month, startDateTime.day,
- startDateTime.hour, startDateTime.minute);
- endDateTime = DateTime(endDateTime.year, endDateTime.month, endDateTime.day,
- endDateTime.hour, endDateTime.minute);
+ DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000)
+ .toUtc()
+ .toLocal();
+ startDateTime = DateTime(startDateTime.year, startDateTime.month,
+ startDateTime.day, startDateTime.hour, startDateTime.minute);
+ endDateTime = DateTime(endDateTime.year, endDateTime.month,
+ endDateTime.day, endDateTime.hour, endDateTime.minute);
if (effectiveDateAndTime.isBefore(startDateTime) ||
invalidDateAndTime.isAfter(endDateTime)) {
matchesCriteria = false;
@@ -184,11 +236,14 @@ class AccessBloc extends Bloc {
}
// Filter by selected tab index
- if (event.selectedTabIndex == 1 && item.passwordStatus.value != 'To be effective') {
+ if (event.selectedTabIndex == 1 &&
+ item.passwordStatus.value != 'To be effective') {
matchesCriteria = false;
- } else if (event.selectedTabIndex == 2 && item.passwordStatus.value != 'Effective') {
+ } else if (event.selectedTabIndex == 2 &&
+ item.passwordStatus.value != 'Effective') {
matchesCriteria = false;
- } else if (event.selectedTabIndex == 3 && item.passwordStatus.value != 'Expired') {
+ } else if (event.selectedTabIndex == 3 &&
+ item.passwordStatus.value != 'Expired') {
matchesCriteria = false;
}
@@ -214,12 +269,14 @@ class AccessBloc extends Bloc {
}
String timestampToDate(dynamic timestamp) {
- DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(int.parse(timestamp) * 1000);
+ DateTime dateTime =
+ DateTime.fromMillisecondsSinceEpoch(int.parse(timestamp) * 1000);
return "${dateTime.year}/${dateTime.month.toString().padLeft(2, '0')}/${dateTime.day.toString().padLeft(2, '0')} "
" ${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}";
}
- Future onTabChanged(TabChangedEvent event, Emitter emit) async {
+ Future onTabChanged(
+ TabChangedEvent event, Emitter emit) async {
try {
emit(AccessLoaded());
selectedIndex = event.selectedIndex;
@@ -228,14 +285,19 @@ class AccessBloc extends Bloc {
filteredData = data;
break;
case 1: // To Be Effective
- filteredData =
- data.where((item) => item.passwordStatus.value == "To Be Effective").toList();
+ filteredData = data
+ .where((item) => item.passwordStatus.value == "To Be Effective")
+ .toList();
break;
case 2: // Effective
- filteredData = data.where((item) => item.passwordStatus.value == "Effective").toList();
+ filteredData = data
+ .where((item) => item.passwordStatus.value == "Effective")
+ .toList();
break;
case 3: // Expired
- filteredData = data.where((item) => item.passwordStatus.value == "Expired").toList();
+ filteredData = data
+ .where((item) => item.passwordStatus.value == "Expired")
+ .toList();
break;
default:
filteredData = data;
diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart
index 8a6fa022..bed27eea 100644
--- a/lib/pages/access_management/view/access_management.dart
+++ b/lib/pages/access_management/view/access_management.dart
@@ -15,8 +15,8 @@ import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/app_enum.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart';
-import 'package:syncrow_web/utils/style.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/web_layout/web_scaffold.dart';
class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
@@ -27,7 +27,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
final isLargeScreen = isLargeScreenSize(context);
final isSmallScreen = isSmallScreenSize(context);
final isHalfMediumScreen = isHafMediumScreenSize(context);
- final padding = isLargeScreen ? const EdgeInsets.all(30) : const EdgeInsets.all(15);
+ final padding =
+ isLargeScreen ? const EdgeInsets.all(30) : const EdgeInsets.all(15);
return WebScaffold(
enableMenuSidebar: false,
@@ -37,23 +38,10 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
style: Theme.of(context).textTheme.headlineLarge,
),
),
- centerBody: Wrap(
- children: [
- Padding(
- padding: EdgeInsets.only(left: MediaQuery.of(context).size.width * 0.09),
- child: Align(
- alignment: Alignment.bottomLeft,
- child: Text(
- 'Physical Access',
- style: Theme.of(context).textTheme.headlineMedium!.copyWith(color: Colors.white),
- ),
- ),
- ),
- ],
- ),
rightBody: const NavigateHomeGridView(),
scaffoldBody: BlocProvider(
- create: (BuildContext context) => AccessBloc()..add(FetchTableData()),
+ create: (BuildContext context) =>
+ AccessBloc()..add(FetchTableData()),
child: BlocConsumer(
listener: (context, state) {},
builder: (context, state) {
@@ -107,11 +95,14 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
return [
item.passwordName,
item.passwordType.value,
- accessBloc.timestampToDate(item.effectiveTime),
- accessBloc.timestampToDate(item.invalidTime),
+ accessBloc
+ .timestampToDate(item.effectiveTime),
+ accessBloc
+ .timestampToDate(item.invalidTime),
item.deviceName.toString(),
item.authorizerEmail.toString(),
- accessBloc.timestampToDate(item.invalidTime),
+ accessBloc
+ .timestampToDate(item.invalidTime),
item.passwordStatus.value,
];
}).toList(),
@@ -122,7 +113,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
})));
}
- Wrap _buildVisitorAdminPasswords(BuildContext context, AccessBloc accessBloc) {
+ Wrap _buildVisitorAdminPasswords(
+ BuildContext context, AccessBloc accessBloc) {
return Wrap(
spacing: 10,
runSpacing: 10,
@@ -147,8 +139,9 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
},
borderRadius: 8,
child: Text(
- '+ Create Visitor Password ',
- style: context.textTheme.titleSmall!.copyWith(color: Colors.white, fontSize: 12),
+ 'Create Visitor Password ',
+ style: context.textTheme.titleSmall!
+ .copyWith(color: Colors.white, fontSize: 12),
)),
),
Container(
@@ -160,7 +153,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
backgroundColor: ColorsManager.whiteColors,
child: Text(
'Admin Password',
- style: context.textTheme.titleSmall!.copyWith(color: Colors.black, fontSize: 12),
+ style: context.textTheme.titleSmall!
+ .copyWith(color: Colors.black, fontSize: 12),
)),
),
],
@@ -183,6 +177,16 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
isRequired: false,
textFieldName: 'Name',
description: '',
+ onSubmitted: (value) {
+ accessBloc.add(FilterDataEvent(
+ emailAuthorizer:
+ accessBloc.emailAuthorizer.text.toLowerCase(),
+ selectedTabIndex:
+ BlocProvider.of(context).selectedIndex,
+ passwordName: accessBloc.passwordName.text.toLowerCase(),
+ startTime: accessBloc.effectiveTimeTimeStamp,
+ endTime: accessBloc.expirationTimeTimeStamp));
+ },
),
),
const SizedBox(width: 15),
@@ -194,6 +198,16 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
isRequired: false,
textFieldName: 'Authorizer',
description: '',
+ onSubmitted: (value) {
+ accessBloc.add(FilterDataEvent(
+ emailAuthorizer:
+ accessBloc.emailAuthorizer.text.toLowerCase(),
+ selectedTabIndex:
+ BlocProvider.of(context).selectedIndex,
+ passwordName: accessBloc.passwordName.text.toLowerCase(),
+ startTime: accessBloc.effectiveTimeTimeStamp,
+ endTime: accessBloc.expirationTimeTimeStamp));
+ },
),
),
const SizedBox(width: 15),
@@ -218,7 +232,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
onSearch: () {
accessBloc.add(FilterDataEvent(
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
- selectedTabIndex: BlocProvider.of(context).selectedIndex,
+ selectedTabIndex:
+ BlocProvider.of(context).selectedIndex,
passwordName: accessBloc.passwordName.text.toLowerCase(),
startTime: accessBloc.effectiveTimeTimeStamp,
endTime: accessBloc.expirationTimeTimeStamp));
@@ -239,12 +254,21 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
SizedBox(
width: 300,
child: CustomWebTextField(
- controller: accessBloc.passwordName,
- isRequired: true,
- height: 40,
- textFieldName: 'Name',
- description: '',
- ),
+ controller: accessBloc.passwordName,
+ isRequired: true,
+ height: 40,
+ textFieldName: 'Name',
+ description: '',
+ onSubmitted: (value) {
+ accessBloc.add(FilterDataEvent(
+ emailAuthorizer:
+ accessBloc.emailAuthorizer.text.toLowerCase(),
+ selectedTabIndex:
+ BlocProvider.of(context).selectedIndex,
+ passwordName: accessBloc.passwordName.text.toLowerCase(),
+ startTime: accessBloc.effectiveTimeTimeStamp,
+ endTime: accessBloc.expirationTimeTimeStamp));
+ }),
),
DateTimeWebWidget(
icon: Assets.calendarIcon,
@@ -264,7 +288,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
onSearch: () {
accessBloc.add(FilterDataEvent(
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
- selectedTabIndex: BlocProvider.of(context).selectedIndex,
+ selectedTabIndex:
+ BlocProvider.of(context).selectedIndex,
passwordName: accessBloc.passwordName.text.toLowerCase(),
startTime: accessBloc.effectiveTimeTimeStamp,
endTime: accessBloc.expirationTimeTimeStamp));
diff --git a/lib/pages/auth/bloc/auth_bloc.dart b/lib/pages/auth/bloc/auth_bloc.dart
index 5b269141..60cc2f86 100644
--- a/lib/pages/auth/bloc/auth_bloc.dart
+++ b/lib/pages/auth/bloc/auth_bloc.dart
@@ -31,7 +31,8 @@ class AuthBloc extends Bloc {
////////////////////////////// forget password //////////////////////////////////
final TextEditingController forgetEmailController = TextEditingController();
- final TextEditingController forgetPasswordController = TextEditingController();
+ final TextEditingController forgetPasswordController =
+ TextEditingController();
final TextEditingController forgetOtp = TextEditingController();
final forgetFormKey = GlobalKey();
final forgetEmailKey = GlobalKey();
@@ -48,7 +49,8 @@ class AuthBloc extends Bloc {
return;
}
_remainingTime = 1;
- add(UpdateTimerEvent(remainingTime: _remainingTime, isButtonEnabled: false));
+ add(UpdateTimerEvent(
+ remainingTime: _remainingTime, isButtonEnabled: false));
try {
forgetEmailValidate = '';
_remainingTime = (await AuthenticationAPI.sendOtp(
@@ -84,7 +86,8 @@ class AuthBloc extends Bloc {
_timer?.cancel();
add(const UpdateTimerEvent(remainingTime: 0, isButtonEnabled: true));
} else {
- add(UpdateTimerEvent(remainingTime: _remainingTime, isButtonEnabled: false));
+ add(UpdateTimerEvent(
+ remainingTime: _remainingTime, isButtonEnabled: false));
}
});
}
@@ -94,21 +97,25 @@ class AuthBloc extends Bloc {
emit(const TimerState(isButtonEnabled: true, remainingTime: 0));
}
- Future changePassword(ChangePasswordEvent event, Emitter emit) async {
+ Future changePassword(
+ ChangePasswordEvent event, Emitter emit) async {
emit(LoadingForgetState());
try {
var response = await AuthenticationAPI.verifyOtp(
email: forgetEmailController.text, otpCode: forgetOtp.text);
if (response == true) {
await AuthenticationAPI.forgetPassword(
- password: forgetPasswordController.text, email: forgetEmailController.text);
+ otpCode: forgetOtp.text,
+ password: forgetPasswordController.text,
+ email: forgetEmailController.text);
_timer?.cancel();
emit(const TimerState(isButtonEnabled: true, remainingTime: 0));
emit(SuccessForgetState());
}
} on DioException catch (e) {
final errorData = e.response!.data;
- String errorMessage = errorData['error']['message'] ?? 'something went wrong';
+ String errorMessage =
+ errorData['error']['message'] ?? 'something went wrong';
validate = errorMessage;
emit(AuthInitialState());
}
@@ -122,7 +129,9 @@ class AuthBloc extends Bloc {
}
void _onUpdateTimer(UpdateTimerEvent event, Emitter emit) {
- emit(TimerState(isButtonEnabled: event.isButtonEnabled, remainingTime: event.remainingTime));
+ emit(TimerState(
+ isButtonEnabled: event.isButtonEnabled,
+ remainingTime: event.remainingTime));
}
///////////////////////////////////// login /////////////////////////////////////
@@ -154,7 +163,9 @@ class AuthBloc extends Bloc {
token = await AuthenticationAPI.loginWithEmail(
model: LoginWithEmailModel(
- email: event.username, password: event.password, regionUuid: event.regionUuid),
+ email: event.username,
+ password: event.password,
+ regionUuid: event.regionUuid),
);
} catch (failure) {
validate = 'Invalid Credentials!';
@@ -164,7 +175,8 @@ class AuthBloc extends Bloc {
if (token.accessTokenIsNotEmpty) {
FlutterSecureStorage storage = const FlutterSecureStorage();
- await storage.write(key: Token.loginAccessTokenKey, value: token.accessToken);
+ await storage.write(
+ key: Token.loginAccessTokenKey, value: token.accessToken);
const FlutterSecureStorage().write(
key: UserModel.userUuidKey,
value: Token.decodeToken(token.accessToken)['uuid'].toString());
@@ -322,12 +334,14 @@ class AuthBloc extends Bloc {
static Future getTokenAndValidate() async {
try {
const storage = FlutterSecureStorage();
- final firstLaunch =
- await SharedPreferencesHelper.readBoolFromSP(StringsManager.firstLaunch) ?? true;
+ final firstLaunch = await SharedPreferencesHelper.readBoolFromSP(
+ StringsManager.firstLaunch) ??
+ true;
if (firstLaunch) {
storage.deleteAll();
}
- await SharedPreferencesHelper.saveBoolToSP(StringsManager.firstLaunch, false);
+ await SharedPreferencesHelper.saveBoolToSP(
+ StringsManager.firstLaunch, false);
final value = await storage.read(key: Token.loginAccessTokenKey) ?? '';
if (value.isEmpty) {
return 'Token not found';
@@ -380,7 +394,9 @@ class AuthBloc extends Bloc {
final String formattedTime = [
if (days > 0) '${days}d', // Append 'd' for days
if (days > 0 || hours > 0)
- hours.toString().padLeft(2, '0'), // Show hours if there are days or hours
+ hours
+ .toString()
+ .padLeft(2, '0'), // Show hours if there are days or hours
minutes.toString().padLeft(2, '0'),
seconds.toString().padLeft(2, '0'),
].join(':');
diff --git a/lib/pages/common/curtain_toggle.dart b/lib/pages/common/curtain_toggle.dart
index 305ede03..7b1551c5 100644
--- a/lib/pages/common/curtain_toggle.dart
+++ b/lib/pages/common/curtain_toggle.dart
@@ -26,9 +26,12 @@ class CurtainToggle extends StatelessWidget {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
+ const SizedBox(
+ height: 10,
+ ),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- crossAxisAlignment: CrossAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.start,
children: [
ClipOval(
child: Container(
@@ -41,6 +44,9 @@ class CurtainToggle extends StatelessWidget {
),
),
),
+ const SizedBox(
+ width: 20,
+ ),
SizedBox(
height: 20,
width: 35,
diff --git a/lib/pages/common/custom_table.dart b/lib/pages/common/custom_table.dart
index 5b6692ae..22baba36 100644
--- a/lib/pages/common/custom_table.dart
+++ b/lib/pages/common/custom_table.dart
@@ -4,6 +4,7 @@ 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/constants/assets.dart';
+import 'package:syncrow_web/utils/extension/build_context_x.dart';
class DynamicTable extends StatefulWidget {
final List headers;
@@ -45,6 +46,8 @@ class DynamicTable extends StatefulWidget {
class _DynamicTableState extends State {
late List _selectedRows;
bool _selectAll = false;
+ final ScrollController _verticalScrollController = ScrollController();
+ final ScrollController _horizontalScrollController = ScrollController();
@override
void initState() {
@@ -102,68 +105,81 @@ class _DynamicTableState extends State {
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(
+ child: Scrollbar(
+ controller: _verticalScrollController,
+ thumbVisibility: true,
+ trackVisibility: true,
+ child: Scrollbar(
+ controller: _horizontalScrollController,
+ thumbVisibility: false,
+ trackVisibility: false,
+ notificationPredicate: (notif) => notif.depth == 1,
+ child: SingleChildScrollView(
+ controller: _verticalScrollController,
+ child: SingleChildScrollView(
+ controller: _horizontalScrollController,
+ scrollDirection: Axis.horizontal,
+ child: SizedBox(
+ width: widget.size.width,
+ child: Column(
children: [
- if (widget.withCheckBox) _buildSelectAllCheckbox(),
- ...widget.headers.map((header) => _buildTableHeaderCell(header)),
- ],
- ),
- ),
- widget.isEmpty
- ? Expanded(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.center,
+ Container(
+ decoration: widget.headerDecoration ??
+ const BoxDecoration(
+ color: ColorsManager.boxColor,
+ ),
+ child: Row(
children: [
- Row(
- crossAxisAlignment: CrossAxisAlignment.center,
+ if (widget.withCheckBox) _buildSelectAllCheckbox(),
+ ...List.generate(widget.headers.length, (index) {
+ return _buildTableHeaderCell(widget.headers[index], index);
+ })
+ //...widget.headers.map((header) => _buildTableHeaderCell(header)),
+ ],
+ ),
+ ),
+ widget.isEmpty
+ ? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
- Column(
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ mainAxisAlignment: MainAxisAlignment.center,
children: [
- SvgPicture.asset(Assets.emptyTable),
- const SizedBox(
- height: 15,
+ Column(
+ children: [
+ SvgPicture.asset(Assets.emptyTable),
+ const SizedBox(
+ height: 15,
+ ),
+ Text(
+ widget.tableName == 'AccessManagement' ? 'No Password ' : 'No Devices',
+ style: Theme.of(context)
+ .textTheme
+ .bodySmall!
+ .copyWith(color: ColorsManager.grayColor),
+ )
+ ],
),
- Text(
- // no password
- widget.tableName == 'AccessManagement' ? 'No Password ' : 'No Devices',
- style:
- Theme.of(context).textTheme.bodySmall!.copyWith(color: ColorsManager.grayColor),
- )
],
),
],
+ )
+ : Column(
+ children: List.generate(widget.data.length, (index) {
+ final row = widget.data[index];
+ return Row(
+ children: [
+ if (widget.withCheckBox) _buildRowCheckbox(index, widget.size.height * 0.08),
+ ...row.map((cell) => _buildTableCell(cell.toString(), widget.size.height * 0.08)),
+ ],
+ );
+ }),
),
- ],
- ),
- )
- : 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)),
- ],
- );
- },
- ),
- ),
- ),
- ],
+ ],
+ ),
+ ),
+ ),
),
),
),
@@ -173,7 +189,6 @@ class _DynamicTableState extends State {
Widget _buildSelectAllCheckbox() {
return Container(
width: 50,
- padding: const EdgeInsets.all(8.0),
decoration: const BoxDecoration(
border: Border.symmetric(
vertical: BorderSide(color: ColorsManager.boxDivider),
@@ -198,6 +213,7 @@ class _DynamicTableState extends State {
width: 1.0,
),
),
+ color: ColorsManager.whiteColors,
),
alignment: Alignment.centerLeft,
child: Center(
@@ -211,7 +227,7 @@ class _DynamicTableState extends State {
);
}
- Widget _buildTableHeaderCell(String title) {
+ Widget _buildTableHeaderCell(String title, int index) {
return Expanded(
child: Container(
decoration: const BoxDecoration(
@@ -219,15 +235,16 @@ class _DynamicTableState extends State {
vertical: BorderSide(color: ColorsManager.boxDivider),
),
),
+ constraints: const BoxConstraints.expand(height: 40),
alignment: Alignment.centerLeft,
child: Padding(
- padding: const EdgeInsets.all(8.0),
+ padding: EdgeInsets.symmetric(horizontal: index == widget.headers.length - 1 ? 12 : 8.0, vertical: 4),
child: Text(
title,
- style: const TextStyle(
+ style: context.textTheme.titleSmall!.copyWith(
+ color: ColorsManager.grayColor,
+ fontSize: 12,
fontWeight: FontWeight.w400,
- fontSize: 13,
- color: Color(0xFF999999),
),
maxLines: 2,
),
@@ -276,6 +293,7 @@ class _DynamicTableState extends State {
width: 1.0,
),
),
+ color: Colors.white,
),
alignment: Alignment.centerLeft,
child: Text(
@@ -286,7 +304,7 @@ class _DynamicTableState extends State {
: (batteryLevel != null && batteryLevel > 20)
? ColorsManager.green
: statusColor,
- fontSize: 10,
+ fontSize: 13,
fontWeight: FontWeight.w400),
maxLines: 2,
),
diff --git a/lib/pages/common/date_time_widget.dart b/lib/pages/common/date_time_widget.dart
index 0965377e..8dbcc9aa 100644
--- a/lib/pages/common/date_time_widget.dart
+++ b/lib/pages/common/date_time_widget.dart
@@ -81,7 +81,10 @@ class DateTimeWebWidget extends StatelessWidget {
const SizedBox(
width: 30,
),
- const Icon(Icons.arrow_right_alt),
+ const Icon(
+ Icons.arrow_right_alt,
+ color: ColorsManager.grayColor,
+ ),
const SizedBox(
width: 30,
),
diff --git a/lib/pages/common/text_field/custom_text_field.dart b/lib/pages/common/text_field/custom_text_field.dart
index c85e911d..b695da4a 100644
--- a/lib/pages/common/text_field/custom_text_field.dart
+++ b/lib/pages/common/text_field/custom_text_field.dart
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart';
+import 'package:syncrow_web/utils/style.dart';
class StatefulTextField extends StatefulWidget {
const StatefulTextField(
@@ -25,13 +26,15 @@ class StatefulTextField extends StatefulWidget {
class _StatefulTextFieldState extends State {
@override
Widget build(BuildContext context) {
- return CustomTextField(
- title: widget.title,
- controller: widget.controller,
- hintText: widget.hintText,
- width: widget.width,
- elevation: widget.elevation,
- onSubmittedFun: widget.onSubmitted);
+ return Container(
+ child: CustomTextField(
+ title: widget.title,
+ controller: widget.controller,
+ hintText: widget.hintText,
+ width: widget.width,
+ elevation: widget.elevation,
+ onSubmittedFun: widget.onSubmitted),
+ );
}
}
@@ -73,17 +76,20 @@ class CustomTextField extends StatelessWidget {
child: Container(
width: width,
height: 45,
- decoration: BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.circular(8),
- ),
+ decoration: containerDecoration,
+
+ // decoration: BoxDecoration(
+ // color: Colors.white,
+ // borderRadius: BorderRadius.circular(8),
+ // ),
child: TextFormField(
controller: controller,
style: const TextStyle(color: Colors.black),
decoration: InputDecoration(
hintText: hintText,
hintStyle: const TextStyle(fontSize: 12),
- contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
+ contentPadding:
+ const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
border: InputBorder.none,
),
onFieldSubmitted: (_) {
diff --git a/lib/pages/common/text_field/custom_web_textfield.dart b/lib/pages/common/text_field/custom_web_textfield.dart
index 756463e2..630e334b 100644
--- a/lib/pages/common/text_field/custom_web_textfield.dart
+++ b/lib/pages/common/text_field/custom_web_textfield.dart
@@ -13,6 +13,7 @@ class CustomWebTextField extends StatelessWidget {
this.validator,
this.hintText,
this.height,
+ this.onSubmitted,
});
final bool isRequired;
@@ -22,6 +23,7 @@ class CustomWebTextField extends StatelessWidget {
final String? Function(String?)? validator;
final String? hintText;
final double? height;
+ final ValueChanged? onSubmitted;
@override
Widget build(BuildContext context) {
@@ -32,23 +34,25 @@ class CustomWebTextField extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
-
- Row(
- children: [
- if (isRequired)
- Text('* ',
+ Row(
+ children: [
+ if (isRequired)
+ Text(
+ '* ',
style: Theme.of(context)
- .textTheme.bodyMedium!
+ .textTheme
+ .bodyMedium!
.copyWith(color: Colors.red),
),
- Text(
- textFieldName,
- style: Theme.of(context)
- .textTheme.bodySmall!
- .copyWith(color: Colors.black, fontSize: 13),
- ),
- ],
- ),
+ Text(
+ textFieldName,
+ style: Theme.of(context)
+ .textTheme
+ .bodySmall!
+ .copyWith(color: Colors.black, fontSize: 13),
+ ),
+ ],
+ ),
const SizedBox(
width: 10,
),
@@ -68,17 +72,7 @@ class CustomWebTextField extends StatelessWidget {
),
Container(
height: height ?? 35,
- decoration: containerDecoration.copyWith(
- color: const Color(0xFFF5F6F7),
- boxShadow: [
- BoxShadow(
- color: Colors.grey.withOpacity(0.3),
- spreadRadius: 2,
- blurRadius: 3,
- offset: const Offset(1, 1), // changes position of shadow
- ),
- ]
- ),
+ decoration: containerDecoration,
child: TextFormField(
validator: validator,
controller: controller,
@@ -88,6 +82,7 @@ class CustomWebTextField extends StatelessWidget {
hintStyle: context.textTheme.titleSmall!
.copyWith(color: Colors.grey, fontSize: 12),
hintText: hintText ?? 'Please enter'),
+ onFieldSubmitted: onSubmitted,
),
),
],
diff --git a/lib/pages/device_managment/ac/view/ac_device_control.dart b/lib/pages/device_managment/ac/view/ac_device_control.dart
index 37d3a402..5197d722 100644
--- a/lib/pages/device_managment/ac/view/ac_device_control.dart
+++ b/lib/pages/device_managment/ac/view/ac_device_control.dart
@@ -40,7 +40,7 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
: 1,
mainAxisExtent: 140,
crossAxisSpacing: 12,
- mainAxisSpacing: 12,
+ mainAxisSpacing: 16,
),
children: [
ToggleWidget(
@@ -81,6 +81,7 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
+ padding: const EdgeInsets.all(0),
onPressed: () {},
icon: const Icon(
Icons.remove,
@@ -108,6 +109,7 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
),
Text('m', style: context.textTheme.bodySmall!.copyWith(color: ColorsManager.blackColor)),
IconButton(
+ padding: const EdgeInsets.all(0),
onPressed: () {},
icon: const Icon(
Icons.add,
@@ -127,7 +129,7 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
deviceId: device.uuid!,
code: 'child_lock',
value: state.status.childLock,
- label: 'Child Lock',
+ label: 'Lock',
icon: state.status.childLock ? Assets.acLock : Assets.unlock,
onChange: (value) {
context.read().add(
diff --git a/lib/pages/device_managment/all_devices/helper/route_controls_based_code.dart b/lib/pages/device_managment/all_devices/helper/route_controls_based_code.dart
index d4b5b21a..8edb0a1e 100644
--- a/lib/pages/device_managment/all_devices/helper/route_controls_based_code.dart
+++ b/lib/pages/device_managment/all_devices/helper/route_controls_based_code.dart
@@ -18,6 +18,8 @@ import 'package:syncrow_web/pages/device_managment/main_door_sensor/view/main_do
import 'package:syncrow_web/pages/device_managment/one_g_glass_switch/view/one_gang_glass_batch_control_view.dart';
import 'package:syncrow_web/pages/device_managment/one_gang_switch/view/wall_light_batch_control.dart';
import 'package:syncrow_web/pages/device_managment/one_gang_switch/view/wall_light_device_control.dart';
+import 'package:syncrow_web/pages/device_managment/power_clamp/view/power_clamp_batch_control_view.dart';
+import 'package:syncrow_web/pages/device_managment/power_clamp/view/smart_power_device_control.dart';
import 'package:syncrow_web/pages/device_managment/three_g_glass_switch/view/three_gang_glass_switch_batch_control_view.dart';
import 'package:syncrow_web/pages/device_managment/three_g_glass_switch/view/three_gang_glass_switch_control_view.dart';
import 'package:syncrow_web/pages/device_managment/three_gang_switch/view/living_room_batch_controls.dart';
@@ -94,6 +96,10 @@ mixin RouteControlsBasedCode {
return WaterLeakView(
deviceId: device.uuid!,
);
+ case 'PC':
+ return SmartPowerDeviceControl(
+ deviceId: device.uuid!,
+ );
default:
return const SizedBox();
}
@@ -224,6 +230,13 @@ mixin RouteControlsBasedCode {
.map((e) => e.uuid!)
.toList(),
);
+ case 'PC':
+ return PowerClampBatchControlView(
+ deviceIds: devices
+ .where((e) => (e.productType == 'PC'))
+ .map((e) => e.uuid!)
+ .toList(),
+ );
default:
return const SizedBox();
}
diff --git a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart
index 2787c7b9..49a4dc35 100644
--- a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart
+++ b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart
@@ -8,7 +8,6 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo
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/helpers/responsice_layout_helper/responsive_layout_helper.dart';
import 'package:syncrow_web/utils/style.dart';
@@ -58,12 +57,15 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
'Low Battery ($lowBatteryCount)',
];
- final buttonLabel = (selectedDevices.length > 1) ? 'Batch Control' : 'Control';
+ final buttonLabel =
+ (selectedDevices.length > 1) ? 'Batch Control' : 'Control';
return Column(
children: [
Container(
- padding: isLargeScreenSize(context) ? const EdgeInsets.all(30) : const EdgeInsets.all(15),
+ padding: isLargeScreenSize(context)
+ ? const EdgeInsets.all(30)
+ : const EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -72,7 +74,9 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
tabs: tabs,
selectedIndex: selectedIndex,
onTabChanged: (index) {
- context.read().add(SelectedFilterChanged(index));
+ context
+ .read()
+ .add(SelectedFilterChanged(index));
},
),
const SizedBox(height: 20),
@@ -94,11 +98,14 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
),
);
} else if (selectedDevices.length > 1) {
- final productTypes = selectedDevices.map((device) => device.productType).toSet();
+ final productTypes = selectedDevices
+ .map((device) => device.productType)
+ .toSet();
if (productTypes.length == 1) {
showDialog(
context: context,
- builder: (context) => DeviceBatchControlDialog(
+ builder: (context) =>
+ DeviceBatchControlDialog(
devices: selectedDevices,
),
);
@@ -112,7 +119,9 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
- color: isControlButtonEnabled ? Colors.white : Colors.grey,
+ color: isControlButtonEnabled
+ ? Colors.white
+ : Colors.grey,
),
),
),
@@ -123,16 +132,20 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
),
Expanded(
child: Padding(
- padding: isLargeScreenSize(context) ? const EdgeInsets.all(30) : const EdgeInsets.all(15),
+ padding: isLargeScreenSize(context)
+ ? const EdgeInsets.all(30)
+ : const EdgeInsets.all(15),
child: DynamicTable(
withSelectAll: true,
cellDecoration: containerDecoration,
onRowSelected: (index, isSelected, row) {
final selectedDevice = devicesToShow[index];
- context.read().add(SelectDevice(selectedDevice));
+ context
+ .read()
+ .add(SelectDevice(selectedDevice));
},
withCheckBox: true,
- size: context.screenSize,
+ size: MediaQuery.of(context).size,
uuidIndex: 2,
headers: const [
'Device Name',
@@ -152,17 +165,26 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
device.uuid ?? '',
device.unit?.name ?? '',
device.room?.name ?? '',
- device.batteryLevel != null ? '${device.batteryLevel}%' : '-',
- formatDateTime(DateTime.fromMillisecondsSinceEpoch((device.createTime ?? 0) * 1000)),
+ device.batteryLevel != null
+ ? '${device.batteryLevel}%'
+ : '-',
+ formatDateTime(DateTime.fromMillisecondsSinceEpoch(
+ (device.createTime ?? 0) * 1000)),
device.online == true ? 'Online' : 'Offline',
- formatDateTime(DateTime.fromMillisecondsSinceEpoch((device.updateTime ?? 0) * 1000)),
+ formatDateTime(DateTime.fromMillisecondsSinceEpoch(
+ (device.updateTime ?? 0) * 1000)),
];
}).toList(),
onSelectionChanged: (selectedRows) {
- context.read().add(UpdateSelection(selectedRows));
+ context
+ .read()
+ .add(UpdateSelection(selectedRows));
},
- initialSelectedIds:
- context.read().selectedDevices.map((device) => device.uuid!).toList(),
+ initialSelectedIds: context
+ .read()
+ .selectedDevices
+ .map((device) => device.uuid!)
+ .toList(),
isEmpty: devicesToShow.isEmpty,
),
),
diff --git a/lib/pages/device_managment/all_devices/widgets/device_search_filters.dart b/lib/pages/device_managment/all_devices/widgets/device_search_filters.dart
index ddb2bc19..a6c202f4 100644
--- a/lib/pages/device_managment/all_devices/widgets/device_search_filters.dart
+++ b/lib/pages/device_managment/all_devices/widgets/device_search_filters.dart
@@ -4,6 +4,7 @@ import 'package:syncrow_web/pages/common/text_field/custom_text_field.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_managment_bloc.dart';
import 'package:syncrow_web/pages/common/buttons/search_reset_buttons.dart';
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
+import 'package:syncrow_web/utils/style.dart';
class DeviceSearchFilters extends StatefulWidget {
const DeviceSearchFilters({super.key});
@@ -12,7 +13,8 @@ class DeviceSearchFilters extends StatefulWidget {
State createState() => _DeviceSearchFiltersState();
}
-class _DeviceSearchFiltersState extends State with HelperResponsiveLayout {
+class _DeviceSearchFiltersState extends State
+ with HelperResponsiveLayout {
final TextEditingController communityController = TextEditingController();
final TextEditingController unitNameController = TextEditingController();
final TextEditingController productNameController = TextEditingController();
@@ -34,7 +36,8 @@ class _DeviceSearchFiltersState extends State with HelperRe
const SizedBox(width: 20),
_buildSearchField("Unit Name", unitNameController, 200),
const SizedBox(width: 20),
- _buildSearchField("Device Name / Product Name", productNameController, 300),
+ _buildSearchField(
+ "Device Name / Product Name", productNameController, 300),
const SizedBox(width: 20),
_buildSearchResetButtons(),
],
@@ -59,19 +62,22 @@ class _DeviceSearchFiltersState extends State with HelperRe
);
}
- Widget _buildSearchField(String title, TextEditingController controller, double width) {
- return StatefulTextField(
- title: title,
- width: width,
- elevation: 2,
- controller: controller,
- onSubmitted: () {
- context.read().add(SearchDevices(
- productName: productNameController.text,
- unitName: unitNameController.text,
- community: communityController.text,
- searchField: true));
- },
+ Widget _buildSearchField(
+ String title, TextEditingController controller, double width) {
+ return Container(
+ child: StatefulTextField(
+ title: title,
+ width: width,
+ elevation: 2,
+ controller: controller,
+ onSubmitted: () {
+ context.read().add(SearchDevices(
+ productName: productNameController.text,
+ unitName: unitNameController.text,
+ community: communityController.text,
+ searchField: true));
+ },
+ ),
);
}
diff --git a/lib/pages/device_managment/gateway/view/gateway_view.dart b/lib/pages/device_managment/gateway/view/gateway_view.dart
index 2bfc6822..d674e4d8 100644
--- a/lib/pages/device_managment/gateway/view/gateway_view.dart
+++ b/lib/pages/device_managment/gateway/view/gateway_view.dart
@@ -5,6 +5,7 @@ import 'package:syncrow_web/pages/device_managment/gateway/bloc/gate_way_bloc.da
import 'package:syncrow_web/pages/device_managment/shared/device_controls_container.dart';
import 'package:syncrow_web/pages/visitor_password/model/device_model.dart';
import 'package:syncrow_web/utils/color_manager.dart';
+import 'package:syncrow_web/utils/extension/build_context_x.dart';
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
class GateWayControlsView extends StatelessWidget with HelperResponsiveLayout {
@@ -25,25 +26,61 @@ class GateWayControlsView extends StatelessWidget with HelperResponsiveLayout {
if (state is GatewayLoadingState) {
return const Center(child: CircularProgressIndicator());
} else if (state is UpdateGatewayState) {
- return GridView.builder(
- padding: const EdgeInsets.symmetric(horizontal: 50),
- shrinkWrap: true,
- physics: const NeverScrollableScrollPhysics(),
- gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
- crossAxisCount: isLarge || isExtraLarge
- ? 3
- : isMedium
- ? 2
- : 1,
- mainAxisExtent: 140,
- crossAxisSpacing: 12,
- mainAxisSpacing: 12,
- ),
- itemCount: state.list.length,
- itemBuilder: (context, index) {
- final device = state.list[index];
- return _DeviceItem(device: device);
- },
+ return Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Container(
+ padding: const EdgeInsets.symmetric(horizontal: 50),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ "Bluetooth Devices:",
+ style: context.textTheme.bodyMedium!.copyWith(
+ color: ColorsManager.grayColor,
+ ),
+ ),
+ const SizedBox(height: 12),
+ Text(
+ "No devices found",
+ style: context.textTheme.bodySmall!.copyWith(
+ color: ColorsManager.blackColor,
+ ),
+ ),
+ const SizedBox(height: 30),
+ Text(
+ "ZigBee Devices:",
+ style: context.textTheme.bodyMedium!.copyWith(
+ color: ColorsManager.grayColor,
+ ),
+ ),
+ ],
+ ),
+ ),
+ const SizedBox(height: 12),
+ GridView.builder(
+ padding: const EdgeInsets.symmetric(horizontal: 50),
+ shrinkWrap: true,
+ physics: const NeverScrollableScrollPhysics(),
+ gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
+ crossAxisCount: isLarge || isExtraLarge
+ ? 3
+ : isMedium
+ ? 2
+ : 1,
+ mainAxisExtent: 140,
+ crossAxisSpacing: 12,
+ mainAxisSpacing: 12,
+ ),
+ itemCount: state.list.length,
+ itemBuilder: (context, index) {
+ final device = state.list[index];
+ return _DeviceItem(device: device);
+ },
+ ),
+ ],
);
} else {
return const Center(child: Text('Error fetching status'));
diff --git a/lib/pages/device_managment/power_clamp/bloc/smart_power_bloc.dart b/lib/pages/device_managment/power_clamp/bloc/smart_power_bloc.dart
new file mode 100644
index 00000000..52cccff4
--- /dev/null
+++ b/lib/pages/device_managment/power_clamp/bloc/smart_power_bloc.dart
@@ -0,0 +1,792 @@
+import 'dart:async';
+
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:intl/intl.dart';
+import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
+import 'package:syncrow_web/pages/device_managment/power_clamp/bloc/smart_power_event.dart';
+import 'package:syncrow_web/pages/device_managment/power_clamp/bloc/smart_power_state.dart';
+import 'package:syncrow_web/pages/device_managment/power_clamp/models/device_event.dart';
+import 'package:syncrow_web/pages/device_managment/power_clamp/models/power_clamp_batch_model.dart';
+import 'package:syncrow_web/pages/device_managment/power_clamp/models/power_clamp_model.dart';
+import 'package:syncrow_web/pages/device_managment/power_clamp/view/power_chart.dart';
+import 'package:syncrow_web/services/devices_mang_api.dart';
+
+class SmartPowerBloc extends Bloc {
+ SmartPowerBloc({required this.deviceId}) : super(SmartPowerInitial()) {
+ on(_onFetchDeviceStatus);
+ on(_onArrowPressed);
+ on(_onFetchBatchStatus);
+ on(_onPageChanged);
+ on(_onBatchControl);
+ on(_filterRecordsByDate);
+ on(checkDayMonthYearSelected);
+ on(_onFactoryReset);
+ }
+
+ late PowerClampModel deviceStatus;
+ late PowerClampBatchModel deviceBatchStatus;
+ final String deviceId;
+ Timer? _timer;
+ List