mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2025-07-16 01:56:19 +00:00
sos_device
This commit is contained in:
@ -8,7 +8,7 @@ import 'package:syncrow_app/features/devices/model/device_control_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_report_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/group_devices_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/scene_switch_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_info_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/sex_scene_question_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/six_scene_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/status_model.dart';
|
||||
@ -68,7 +68,7 @@ class SixSceneBloc extends Bloc<SixSceneEvent, SixSceneState> {
|
||||
scene_id_group_id: '',
|
||||
switch_backlight: false);
|
||||
|
||||
SceneSwitch deviceInfo = SceneSwitch(
|
||||
DeviceInfoModel deviceInfo = DeviceInfoModel(
|
||||
activeTime: 0,
|
||||
category: "",
|
||||
categoryName: "",
|
||||
@ -175,7 +175,7 @@ class SixSceneBloc extends Bloc<SixSceneEvent, SixSceneState> {
|
||||
try {
|
||||
emit(SixSceneLoadingState());
|
||||
var response = await DevicesAPI.getDeviceInfo(sixSceneId);
|
||||
deviceInfo = SceneSwitch.fromJson(response);
|
||||
deviceInfo = DeviceInfoModel.fromJson(response);
|
||||
deviceName = deviceInfo.name;
|
||||
emit(LoadingDeviceInfo(deviceInfo: deviceInfo));
|
||||
} catch (e) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/group_devices_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/scene_switch_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_info_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/sex_scene_question_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/six_scene_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/subspace_model.dart';
|
||||
@ -121,7 +121,7 @@ class SceneSelectionUpdatedState extends SixSceneState {
|
||||
}
|
||||
|
||||
class LoadingDeviceInfo extends SixSceneState {
|
||||
final SceneSwitch deviceInfo;
|
||||
final DeviceInfoModel deviceInfo;
|
||||
const LoadingDeviceInfo({required this.deviceInfo});
|
||||
|
||||
@override
|
||||
|
@ -8,10 +8,10 @@ import 'package:syncrow_app/features/devices/model/device_control_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_report_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/four_scene_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/four_scene_question_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/question_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/four_scene_switch_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/group_devices_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/scene_switch_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_info_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/status_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/subspace_model.dart';
|
||||
import 'package:syncrow_app/features/scene/model/scenes_model.dart';
|
||||
@ -68,7 +68,7 @@ class FourSceneBloc extends Bloc<FourSceneEvent, FourSceneState> {
|
||||
scene_id_group_id: '',
|
||||
switch_backlight: false);
|
||||
|
||||
SceneSwitch deviceInfo = SceneSwitch(
|
||||
DeviceInfoModel deviceInfo = DeviceInfoModel(
|
||||
activeTime: 0,
|
||||
category: "",
|
||||
categoryName: "",
|
||||
@ -285,7 +285,7 @@ class FourSceneBloc extends Bloc<FourSceneEvent, FourSceneState> {
|
||||
try {
|
||||
emit(FourSceneLoadingState());
|
||||
var response = await DevicesAPI.getDeviceInfo(fourSceneId);
|
||||
deviceInfo = SceneSwitch.fromJson(response);
|
||||
deviceInfo = DeviceInfoModel.fromJson(response);
|
||||
deviceName = deviceInfo.name;
|
||||
emit(LoadingDeviceInfo(deviceInfo: deviceInfo));
|
||||
} catch (e) {
|
||||
@ -295,7 +295,7 @@ class FourSceneBloc extends Bloc<FourSceneEvent, FourSceneState> {
|
||||
|
||||
void _onSearchFaq(SearchFaqEvent event, Emitter<FourSceneState> emit) {
|
||||
emit(FourSceneLoadingState());
|
||||
List<FourSceneQuestionModel> _faqQuestions = faqQuestions.where((question) {
|
||||
List<QuestionModel> _faqQuestions = faqQuestions.where((question) {
|
||||
return question.question
|
||||
.toLowerCase()
|
||||
.contains(event.query.toLowerCase());
|
||||
@ -339,31 +339,31 @@ class FourSceneBloc extends Bloc<FourSceneEvent, FourSceneState> {
|
||||
DeviceReport recordGroups =
|
||||
DeviceReport(startTime: '0', endTime: '0', data: []);
|
||||
|
||||
final List<FourSceneQuestionModel> faqQuestions = [
|
||||
FourSceneQuestionModel(
|
||||
final List<QuestionModel> faqQuestions = [
|
||||
QuestionModel(
|
||||
id: 1,
|
||||
question: 'How does an SOS emergency button work?',
|
||||
answer:
|
||||
'The SOS emergency button sends an alert to your contacts when pressed.',
|
||||
),
|
||||
FourSceneQuestionModel(
|
||||
QuestionModel(
|
||||
id: 2,
|
||||
question: 'How long will an SOS alarm persist?',
|
||||
answer:
|
||||
'The SOS alarm will persist until it is manually turned off or after a set time.',
|
||||
),
|
||||
FourSceneQuestionModel(
|
||||
QuestionModel(
|
||||
id: 3,
|
||||
question: 'What should I do if the SOS button is unresponsive?',
|
||||
answer: 'Try restarting the device. If it persists, contact support.',
|
||||
),
|
||||
FourSceneQuestionModel(
|
||||
QuestionModel(
|
||||
id: 4,
|
||||
question: 'Can I use the SOS feature without a network connection?',
|
||||
answer:
|
||||
'No, a network connection is required to send the alert to your contacts.',
|
||||
),
|
||||
FourSceneQuestionModel(
|
||||
QuestionModel(
|
||||
id: 5,
|
||||
question: 'How often should I check the SOS battery?',
|
||||
answer:
|
||||
|
@ -1,9 +1,9 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/four_scene_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/four_scene_question_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/question_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/group_devices_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/scene_switch_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_info_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/subspace_model.dart';
|
||||
import 'package:syncrow_app/features/scene/model/scenes_model.dart';
|
||||
|
||||
@ -58,13 +58,13 @@ class NameEditingState extends FourSceneState {
|
||||
}
|
||||
|
||||
class FaqLoadedState extends FourSceneState {
|
||||
final List<FourSceneQuestionModel> filteredFaqQuestions;
|
||||
final List<QuestionModel> filteredFaqQuestions;
|
||||
|
||||
FaqLoadedState({this.filteredFaqQuestions = const []});
|
||||
}
|
||||
|
||||
class FaqSearchState extends FourSceneState {
|
||||
final List<FourSceneQuestionModel> filteredFaqQuestions;
|
||||
final List<QuestionModel> filteredFaqQuestions;
|
||||
|
||||
const FaqSearchState({this.filteredFaqQuestions = const []});
|
||||
}
|
||||
@ -116,7 +116,7 @@ class OptionSelectedState extends FourSceneState {
|
||||
}
|
||||
|
||||
class LoadingDeviceInfo extends FourSceneState {
|
||||
final SceneSwitch deviceInfo;
|
||||
final DeviceInfoModel deviceInfo;
|
||||
const LoadingDeviceInfo({required this.deviceInfo});
|
||||
|
||||
@override
|
||||
|
452
lib/features/devices/bloc/sos_bloc/sos_bloc.dart
Normal file
452
lib/features/devices/bloc/sos_bloc/sos_bloc.dart
Normal file
@ -0,0 +1,452 @@
|
||||
import 'dart:async';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
|
||||
import 'package:syncrow_app/features/app_layout/model/community_model.dart';
|
||||
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_info_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_report_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/question_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/sos_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/status_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/subspace_model.dart';
|
||||
import 'package:syncrow_app/navigation/routing_constants.dart';
|
||||
import 'package:syncrow_app/services/api/devices_api.dart';
|
||||
import 'package:syncrow_app/services/api/home_management_api.dart';
|
||||
import 'package:syncrow_app/services/api/spaces_api.dart';
|
||||
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
|
||||
|
||||
class SosBloc extends Bloc<SosEvent, SosState> {
|
||||
final String sosId;
|
||||
SosBloc({
|
||||
required this.sosId,
|
||||
}) : super(const SosState()) {
|
||||
on<SosInitial>(_fetchStatus);
|
||||
on<ReportLogsInitial>(fetchLogsForLastMonth);
|
||||
on<ToggleEnableAlarmEvent>(_toggleLowBattery);
|
||||
on<ToggleClosingReminderEvent>(_toggleClosingReminder);
|
||||
on<ChangeNameEvent>(_changeName);
|
||||
on<SearchFaqEvent>(_onSearchFaq);
|
||||
on<SosInitialQuestion>(_onSosInitial);
|
||||
on<FetchRoomsEvent>(_fetchRoomsAndDevices);
|
||||
on<SelectOptionEvent>(_onOptionSelected);
|
||||
on<SaveSelectionEvent>(_onSaveSelection);
|
||||
on<AssignRoomEvent>(_assignDevice);
|
||||
on<SosInitialDeviseInfo>(fetchDeviceInfo);
|
||||
// on<UnassignRoomEvent>(_unassignDevice);
|
||||
// on<ToggleWaterLeakAlarmEvent>(_toggleWaterLeakAlarm);
|
||||
}
|
||||
|
||||
final TextEditingController nameController =
|
||||
TextEditingController(text: '${'firstName'}');
|
||||
bool isSaving = false;
|
||||
bool editName = false;
|
||||
final FocusNode focusNode = FocusNode();
|
||||
Timer? _timer;
|
||||
bool enableAlarm = false;
|
||||
bool closingReminder = false;
|
||||
bool waterAlarm = false;
|
||||
SosModel deviceStatus =
|
||||
SosModel(sosContactState: 'normal', batteryPercentage: 0);
|
||||
|
||||
void _fetchStatus(SosInitial event, Emitter<SosState> emit) async {
|
||||
emit(SosLoadingState());
|
||||
try {
|
||||
var response = await DevicesAPI.getDeviceStatus(sosId);
|
||||
List<StatusModel> statusModelList = [];
|
||||
for (var status in response['status']) {
|
||||
statusModelList.add(StatusModel.fromJson(status));
|
||||
}
|
||||
deviceStatus = SosModel.fromJson(
|
||||
statusModelList,
|
||||
);
|
||||
emit(UpdateState(sensor: deviceStatus));
|
||||
|
||||
Future.delayed(const Duration(milliseconds: 500));
|
||||
// _listenToChanges();
|
||||
} catch (e) {
|
||||
emit(SosFailedState(errorMessage: e.toString()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DeviceInfoModel deviceInfo = DeviceInfoModel(
|
||||
activeTime: 0,
|
||||
category: "",
|
||||
categoryName: "",
|
||||
createTime: 0,
|
||||
gatewayId: "",
|
||||
icon: "",
|
||||
ip: "",
|
||||
lat: "",
|
||||
localKey: "",
|
||||
lon: "",
|
||||
model: "",
|
||||
name: "",
|
||||
nodeId: "",
|
||||
online: false,
|
||||
ownerId: "",
|
||||
productName: "",
|
||||
sub: false,
|
||||
timeZone: "",
|
||||
updateTime: 0,
|
||||
uuid: "",
|
||||
productUuid: "",
|
||||
productType: "",
|
||||
permissionType: "",
|
||||
macAddress: "",
|
||||
subspace: Subspace(
|
||||
uuid: "",
|
||||
createdAt: "",
|
||||
updatedAt: "",
|
||||
subspaceName: "",
|
||||
),
|
||||
);
|
||||
|
||||
void _onSearchFaq(SearchFaqEvent event, Emitter<SosState> emit) {
|
||||
emit(SosLoadingState());
|
||||
List<QuestionModel> _faqQuestions = faqQuestions.where((question) {
|
||||
return question.question
|
||||
.toLowerCase()
|
||||
.contains(event.query.toLowerCase());
|
||||
}).toList();
|
||||
emit(FaqSearchState(filteredFaqQuestions: _faqQuestions));
|
||||
}
|
||||
|
||||
void _changeName(ChangeNameEvent event, Emitter<SosState> emit) {
|
||||
emit(SosLoadingState());
|
||||
editName = event.value!;
|
||||
if (editName) {
|
||||
Future.delayed(const Duration(milliseconds: 500), () {
|
||||
focusNode.requestFocus();
|
||||
});
|
||||
} else {
|
||||
focusNode.unfocus();
|
||||
}
|
||||
emit(NameEditingState(editName: editName));
|
||||
}
|
||||
|
||||
void _toggleLowBattery(
|
||||
ToggleEnableAlarmEvent event, Emitter<SosState> emit) async {
|
||||
emit(LoadingNewSate(sosSensor: deviceStatus));
|
||||
try {
|
||||
enableAlarm = event.isLowBatteryEnabled;
|
||||
emit(UpdateState(sensor: deviceStatus));
|
||||
await DevicesAPI.controlDevice(
|
||||
DeviceControlModel(
|
||||
deviceId: sosId,
|
||||
code: 'low_battery',
|
||||
value: enableAlarm,
|
||||
),
|
||||
sosId,
|
||||
);
|
||||
} catch (e) {
|
||||
emit(SosFailedState(errorMessage: e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
void _toggleClosingReminder(
|
||||
ToggleClosingReminderEvent event, Emitter<SosState> emit) async {
|
||||
emit(LoadingNewSate(sosSensor: deviceStatus));
|
||||
try {
|
||||
closingReminder = event.isClosingReminderEnabled;
|
||||
emit(UpdateState(sensor: deviceStatus));
|
||||
|
||||
// API call to update the state, if necessary
|
||||
// await DevicesAPI.controlDevice(
|
||||
// DeviceControlModel(
|
||||
// deviceId: sosId,
|
||||
// code: 'closing_reminder',
|
||||
// value: closingReminder,
|
||||
// ),
|
||||
// sosId,
|
||||
// );
|
||||
} catch (e) {
|
||||
emit(SosFailedState(errorMessage: e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
DeviceReport recordGroups =
|
||||
DeviceReport(startTime: '0', endTime: '0', data: []);
|
||||
|
||||
Future<void> fetchLogsForLastMonth(
|
||||
ReportLogsInitial event, Emitter<SosState> emit) async {
|
||||
DateTime now = DateTime.now();
|
||||
DateTime lastMonth = DateTime(now.year, now.month - 1, now.day);
|
||||
int startTime = lastMonth.millisecondsSinceEpoch;
|
||||
int endTime = now.millisecondsSinceEpoch;
|
||||
try {
|
||||
emit(SosLoadingState());
|
||||
var response = await DevicesAPI.getReportLogs(
|
||||
startTime: startTime.toString(),
|
||||
endTime: endTime.toString(),
|
||||
deviceUuid: sosId,
|
||||
code: 'sos',
|
||||
);
|
||||
recordGroups = response;
|
||||
emit(UpdateState(sensor: deviceStatus));
|
||||
} on DioException catch (e) {
|
||||
final errorData = e.response!.data;
|
||||
String errorMessage = errorData['message'];
|
||||
emit(SosFailedState(errorMessage: e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
static String deviceName = '';
|
||||
|
||||
fetchDeviceInfo(SosInitialDeviseInfo event, Emitter<SosState> emit) async {
|
||||
try {
|
||||
emit(SosLoadingState());
|
||||
var response = await DevicesAPI.getDeviceInfo(sosId);
|
||||
deviceInfo = DeviceInfoModel.fromJson(response);
|
||||
deviceName = deviceInfo.name;
|
||||
emit(LoadingSosDeviceInfo(deviceInfo: deviceInfo));
|
||||
} catch (e) {
|
||||
emit(SosFailedState(errorMessage: e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
// Demo list of FAQ questions using the QuestionModel class
|
||||
final List<QuestionModel> faqQuestions = [
|
||||
QuestionModel(
|
||||
id: 1,
|
||||
question: 'How does an SOS emergency button work?',
|
||||
answer:
|
||||
'The SOS emergency button sends an alert to your contacts when pressed.',
|
||||
),
|
||||
QuestionModel(
|
||||
id: 2,
|
||||
question: 'How long will an SOS alarm persist?',
|
||||
answer:
|
||||
'The SOS alarm will persist until it is manually turned off or after a set time.',
|
||||
),
|
||||
QuestionModel(
|
||||
id: 3,
|
||||
question: 'What should I do if the SOS button is unresponsive?',
|
||||
answer: 'Try restarting the device. If it persists, contact support.',
|
||||
),
|
||||
QuestionModel(
|
||||
id: 4,
|
||||
question: 'Can I use the SOS feature without a network connection?',
|
||||
answer:
|
||||
'No, a network connection is required to send the alert to your contacts.',
|
||||
),
|
||||
QuestionModel(
|
||||
id: 5,
|
||||
question: 'How often should I check the SOS battery?',
|
||||
answer:
|
||||
'Check the SOS battery at least once a month to ensure it is operational.',
|
||||
),
|
||||
];
|
||||
Future<void> _onSosInitial(
|
||||
SosInitialQuestion event, Emitter<SosState> emit) async {
|
||||
emit(SosLoadingState());
|
||||
// SosModel sosModel = await fetchSosData(sosId); // Define this function as needed
|
||||
emit(FaqLoadedState(filteredFaqQuestions: faqQuestions));
|
||||
}
|
||||
|
||||
List<DeviceModel> allDevices = [];
|
||||
List<SubSpaceModel> roomsList = [];
|
||||
|
||||
void _fetchRoomsAndDevices(
|
||||
FetchRoomsEvent event, Emitter<SosState> emit) async {
|
||||
try {
|
||||
emit(SosLoadingState());
|
||||
roomsList = await SpacesAPI.getSubSpaceBySpaceId(
|
||||
event.unit.community.uuid, event.unit.id);
|
||||
emit(FetchRoomsState(devicesList: allDevices, roomsList: roomsList));
|
||||
} catch (e) {
|
||||
emit(const SosFailedState(errorMessage: 'Something went wrong'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String roomId = '';
|
||||
SpaceModel unit =
|
||||
SpaceModel(id: '', name: '', community: Community(uuid: '', name: ''));
|
||||
|
||||
String _selectedOption = '';
|
||||
bool _hasSelectionChanged = false;
|
||||
|
||||
void _onOptionSelected(SelectOptionEvent event, Emitter<SosState> emit) {
|
||||
emit(SosLoadingState());
|
||||
_selectedOption = event.selectedOption;
|
||||
_hasSelectionChanged = true;
|
||||
emit(OptionSelectedState(
|
||||
selectedOption: _selectedOption,
|
||||
hasSelectionChanged: _hasSelectionChanged));
|
||||
}
|
||||
|
||||
void _onSaveSelection(SaveSelectionEvent event, Emitter<SosState> emit) {
|
||||
if (_hasSelectionChanged) {
|
||||
_hasSelectionChanged = false;
|
||||
add(AssignRoomEvent(roomId: roomId, unit: unit, context: event.context));
|
||||
emit(SaveSelectionSuccessState());
|
||||
|
||||
// Navigator.pushNamedAndRemoveUntil(
|
||||
// event.context, Routes.homeRoute, (route) => false);
|
||||
var cubit = HomeCubit.getInstance();
|
||||
cubit.updatePageIndex(1);
|
||||
Navigator.pushReplacementNamed(event.context, Routes.homeRoute);
|
||||
}
|
||||
}
|
||||
|
||||
void _assignDevice(AssignRoomEvent event, Emitter<SosState> emit) async {
|
||||
try {
|
||||
// Map<String, bool> roomDevicesId = {};
|
||||
emit(SosLoadingState());
|
||||
|
||||
await HomeManagementAPI.assignDeviceToRoom(
|
||||
event.unit.community.uuid, event.unit.id, event.roomId, sosId);
|
||||
final devicesList = await DevicesAPI.getDevicesByRoomId(
|
||||
communityUuid: event.unit.community.uuid,
|
||||
spaceUuid: event.unit.id,
|
||||
roomId: event.roomId);
|
||||
|
||||
List<String> allDevicesIds = [];
|
||||
|
||||
allDevices.forEach((element) {
|
||||
allDevicesIds.add(element.uuid!);
|
||||
});
|
||||
emit(SaveSelectionSuccessState());
|
||||
|
||||
// devicesList.forEach((e) {
|
||||
// if (allDevicesIds.contains(e.uuid!)) {
|
||||
// roomDevicesId[e.uuid!] = true;
|
||||
// } else {
|
||||
// roomDevicesId[e.uuid!] = false;
|
||||
// }
|
||||
// });
|
||||
// emit(FetchDeviceByRoomIdState(
|
||||
// roomDevices: devicesList,
|
||||
// allDevices: allDevices,
|
||||
// roomDevicesId: roomDevicesId,
|
||||
// roomId: event.roomId));
|
||||
} catch (e) {
|
||||
emit(const SosFailedState(errorMessage: 'Something went wrong'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void _unassignDevice(UnassignRoomEvent event, Emitter<SosState> emit) async {
|
||||
try {
|
||||
Map<String, bool> roomDevicesId = {};
|
||||
emit(SosLoadingState());
|
||||
await HomeManagementAPI.unAssignDeviceToRoom(
|
||||
event.unit.community.uuid, event.unit.id, event.roomId, sosId);
|
||||
final devicesList = await DevicesAPI.getDevicesByRoomId(
|
||||
communityUuid: event.unit.community.uuid,
|
||||
spaceUuid: event.unit.id,
|
||||
roomId: event.roomId);
|
||||
|
||||
List<String> allDevicesIds = [];
|
||||
|
||||
allDevices.forEach((element) {
|
||||
allDevicesIds.add(element.uuid!);
|
||||
});
|
||||
|
||||
devicesList.forEach((e) {
|
||||
if (allDevicesIds.contains(e.uuid!)) {
|
||||
roomDevicesId[e.uuid!] = true;
|
||||
} else {
|
||||
roomDevicesId[e.uuid!] = false;
|
||||
}
|
||||
});
|
||||
// emit(FetchDeviceByRoomIdState(
|
||||
// roomDevices: devicesList,
|
||||
// allDevices: allDevices,
|
||||
// roomDevicesId: roomDevicesId,
|
||||
// roomId: event.roomId));
|
||||
} catch (e) {
|
||||
emit(const SosFailedState(errorMessage: 'Something went wrong'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, List<DeviceModel>> devicesByRoom = {};
|
||||
|
||||
// Your existing function
|
||||
void _fetchDevicesByRoomId(
|
||||
FetchDevicesByRoomIdEvent event, Emitter<SosState> emit) async {
|
||||
try {
|
||||
Map<String, bool> roomDevicesId = {};
|
||||
emit(SosLoadingState());
|
||||
|
||||
// Fetch devices for the specified room
|
||||
final devicesList = await DevicesAPI.getDevicesByRoomId(
|
||||
communityUuid: event.unit.community.uuid,
|
||||
spaceUuid: event.unit.id,
|
||||
roomId: event.roomId);
|
||||
|
||||
// Fetch all devices accessible by the user
|
||||
allDevices = await HomeManagementAPI.fetchDevicesByUserId();
|
||||
|
||||
// Map all accessible device IDs
|
||||
List<String> allDevicesIds = [];
|
||||
allDevices.forEach((element) {
|
||||
allDevicesIds.add(element.uuid!);
|
||||
});
|
||||
|
||||
// Mark devices as accessible/inaccessible for the room and add to devicesByRoom map
|
||||
devicesList.forEach((e) {
|
||||
roomDevicesId[e.uuid!] = allDevicesIds.contains(e.uuid!);
|
||||
});
|
||||
|
||||
// Update the devicesByRoom map with the devices in the current room
|
||||
devicesByRoom[event.roomId] = devicesList;
|
||||
|
||||
// emit(FetchDeviceByRoomIdState(
|
||||
// roomDevices: devicesList,
|
||||
// allDevices: allDevices,
|
||||
// roomDevicesId: roomDevicesId,
|
||||
// roomId: event.roomId));
|
||||
} catch (e) {
|
||||
emit(const SosFailedState(errorMessage: 'Something went wrong'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> saveName(SaveNameEvent event, Emitter<SosState> emit) async {
|
||||
if (_validateInputs()) return;
|
||||
try {
|
||||
add(const ChangeNameEvent(value: false));
|
||||
isSaving = true;
|
||||
emit(SosLoadingState());
|
||||
var response = await DevicesAPI.putDeviceName(
|
||||
deviceId: sosId, deviceName: nameController.text);
|
||||
add(SosInitialDeviseInfo());
|
||||
CustomSnackBar.displaySnackBar('Save Successfully');
|
||||
emit(SaveState());
|
||||
} catch (e) {
|
||||
emit(SosFailedState(errorMessage: e.toString()));
|
||||
} finally {
|
||||
isSaving = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool _validateInputs() {
|
||||
final nameError = fullNameValidator(nameController.text);
|
||||
if (nameError != null) {
|
||||
CustomSnackBar.displaySnackBar(nameError);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
String? fullNameValidator(String? value) {
|
||||
if (value == null) return 'name is required';
|
||||
final withoutExtraSpaces = value.replaceAll(RegExp(r"\s+"), ' ').trim();
|
||||
if (withoutExtraSpaces.length < 2 || withoutExtraSpaces.length > 30) {
|
||||
return 'name must be between 2 and 30 characters long';
|
||||
}
|
||||
if (RegExp(r"/[^ a-zA-Z0-9-\']/").hasMatch(withoutExtraSpaces)) {
|
||||
return 'Only alphanumeric characters, space, dash and single quote are allowed';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
196
lib/features/devices/bloc/sos_bloc/sos_event.dart
Normal file
196
lib/features/devices/bloc/sos_bloc/sos_event.dart
Normal file
@ -0,0 +1,196 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_info_model.dart';
|
||||
|
||||
abstract class SosEvent extends Equatable {
|
||||
const SosEvent();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class SosLoading extends SosEvent {}
|
||||
|
||||
class SosSwitch extends SosEvent {
|
||||
final String switchD;
|
||||
final String deviceId;
|
||||
final String productId;
|
||||
const SosSwitch(
|
||||
{required this.switchD, this.deviceId = '', this.productId = ''});
|
||||
|
||||
@override
|
||||
List<Object> get props => [switchD, deviceId, productId];
|
||||
}
|
||||
|
||||
class SosUpdated extends SosEvent {}
|
||||
class SosInitialDeviseInfo extends SosEvent {}
|
||||
|
||||
class SosInitial extends SosEvent {
|
||||
const SosInitial();
|
||||
}
|
||||
|
||||
class ReportLogsInitial extends SosEvent {
|
||||
const ReportLogsInitial();
|
||||
}
|
||||
|
||||
class SosChangeStatus extends SosEvent {}
|
||||
|
||||
class GetCounterEvent extends SosEvent {
|
||||
final String deviceCode;
|
||||
const GetCounterEvent({required this.deviceCode});
|
||||
@override
|
||||
List<Object> get props => [deviceCode];
|
||||
}
|
||||
|
||||
class ToggleEnableAlarmEvent extends SosEvent {
|
||||
final bool isLowBatteryEnabled;
|
||||
|
||||
const ToggleEnableAlarmEvent(this.isLowBatteryEnabled);
|
||||
|
||||
@override
|
||||
List<Object> get props => [isLowBatteryEnabled];
|
||||
}
|
||||
|
||||
class ToggleClosingReminderEvent extends SosEvent {
|
||||
final bool isClosingReminderEnabled;
|
||||
|
||||
const ToggleClosingReminderEvent(this.isClosingReminderEnabled);
|
||||
|
||||
@override
|
||||
List<Object> get props => [isClosingReminderEnabled];
|
||||
}
|
||||
|
||||
class ToggleSosAlarmEvent extends SosEvent {
|
||||
final bool isSosAlarmEnabled;
|
||||
|
||||
const ToggleSosAlarmEvent(this.isSosAlarmEnabled);
|
||||
|
||||
@override
|
||||
List<Object> get props => [isSosAlarmEnabled];
|
||||
}
|
||||
|
||||
class SetCounterValue extends SosEvent {
|
||||
final Duration duration;
|
||||
final String deviceCode;
|
||||
const SetCounterValue({required this.duration, required this.deviceCode});
|
||||
@override
|
||||
List<Object> get props => [duration, deviceCode];
|
||||
}
|
||||
|
||||
class StartTimer extends SosEvent {
|
||||
final int duration;
|
||||
|
||||
const StartTimer(this.duration);
|
||||
|
||||
@override
|
||||
List<Object> get props => [duration];
|
||||
}
|
||||
|
||||
class TickTimer extends SosEvent {
|
||||
final int remainingTime;
|
||||
|
||||
const TickTimer(this.remainingTime);
|
||||
|
||||
@override
|
||||
List<Object> get props => [remainingTime];
|
||||
}
|
||||
|
||||
class StopTimer extends SosEvent {}
|
||||
|
||||
class OnClose extends SosEvent {}
|
||||
class SaveNameEvent extends SosEvent {}
|
||||
|
||||
class ChangeNameEvent extends SosEvent {
|
||||
final bool? value;
|
||||
const ChangeNameEvent({this.value});
|
||||
}
|
||||
|
||||
class SearchFaqEvent extends SosEvent {
|
||||
final String query;
|
||||
|
||||
const SearchFaqEvent(this.query);
|
||||
}
|
||||
|
||||
class SosInitialQuestion extends SosEvent {
|
||||
const SosInitialQuestion();
|
||||
}
|
||||
|
||||
class FetchRoomsEvent extends SosEvent {
|
||||
final SpaceModel unit;
|
||||
|
||||
const FetchRoomsEvent({required this.unit});
|
||||
|
||||
@override
|
||||
List<Object> get props => [unit];
|
||||
}
|
||||
|
||||
|
||||
class SelectOptionEvent extends SosEvent {
|
||||
dynamic selectedOption;
|
||||
SelectOptionEvent({
|
||||
this.selectedOption,
|
||||
});
|
||||
}
|
||||
|
||||
class SaveSelectionEvent extends SosEvent {
|
||||
BuildContext context;
|
||||
SaveSelectionEvent({
|
||||
required this.context,
|
||||
});
|
||||
}
|
||||
|
||||
class AssignRoomEvent extends SosEvent {
|
||||
final String roomId;
|
||||
final SpaceModel unit;
|
||||
final BuildContext context;
|
||||
|
||||
const AssignRoomEvent({
|
||||
required this.roomId,
|
||||
required this.unit,
|
||||
required this.context,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object> get props => [
|
||||
roomId,
|
||||
unit,
|
||||
context,
|
||||
];
|
||||
}
|
||||
class UnassignRoomEvent extends SosEvent {
|
||||
final String roomId;
|
||||
final String deviceId;
|
||||
final SpaceModel unit;
|
||||
|
||||
const UnassignRoomEvent(
|
||||
{required this.roomId, required this.deviceId, required this.unit});
|
||||
|
||||
@override
|
||||
List<Object> get props => [roomId, unit];
|
||||
}
|
||||
|
||||
class FetchDevicesByRoomIdEvent extends SosEvent {
|
||||
final SpaceModel unit; // Represents the unit (e.g., room or space) context
|
||||
final String roomId; // Unique identifier for the room
|
||||
|
||||
// Constructor
|
||||
FetchDevicesByRoomIdEvent({
|
||||
required this.unit,
|
||||
required this.roomId,
|
||||
});
|
||||
|
||||
// Adding properties for Equatable to compare
|
||||
@override
|
||||
List<Object> get props => [unit, roomId];
|
||||
}
|
||||
|
||||
|
||||
class LoadingDeviceInfo extends SosEvent {
|
||||
DeviceInfoModel deviceInfo;
|
||||
LoadingDeviceInfo({required this.deviceInfo});
|
||||
|
||||
@override
|
||||
List<Object> get props => [deviceInfo];
|
||||
}
|
94
lib/features/devices/bloc/sos_bloc/sos_state.dart
Normal file
94
lib/features/devices/bloc/sos_bloc/sos_state.dart
Normal file
@ -0,0 +1,94 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_info_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/question_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/sos_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/subspace_model.dart';
|
||||
|
||||
class SosState extends Equatable {
|
||||
const SosState();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class SosInitialState extends SosState {}
|
||||
|
||||
class SosLoadingState extends SosState {}
|
||||
class SaveState extends SosState {}
|
||||
|
||||
class LoadingSosDeviceInfo extends SosState {
|
||||
final DeviceInfoModel? deviceInfo;
|
||||
const LoadingSosDeviceInfo({this.deviceInfo});
|
||||
}
|
||||
|
||||
class SosFailedState extends SosState {
|
||||
final String errorMessage;
|
||||
|
||||
const SosFailedState({required this.errorMessage});
|
||||
|
||||
@override
|
||||
List<Object> get props => [errorMessage];
|
||||
}
|
||||
|
||||
class UpdateState extends SosState {
|
||||
final SosModel sensor;
|
||||
const UpdateState({required this.sensor});
|
||||
|
||||
@override
|
||||
List<Object> get props => [sensor];
|
||||
}
|
||||
|
||||
class LoadingNewSate extends SosState {
|
||||
final SosModel sosSensor;
|
||||
const LoadingNewSate({required this.sosSensor});
|
||||
|
||||
@override
|
||||
List<Object> get props => [sosSensor];
|
||||
}
|
||||
|
||||
class NameEditingState extends SosState {
|
||||
final bool editName;
|
||||
|
||||
NameEditingState({required this.editName});
|
||||
}
|
||||
|
||||
class FaqLoadedState extends SosState {
|
||||
final List<QuestionModel> filteredFaqQuestions;
|
||||
|
||||
FaqLoadedState({this.filteredFaqQuestions = const []});
|
||||
}
|
||||
|
||||
class FaqSearchState extends SosState {
|
||||
final List<QuestionModel> filteredFaqQuestions;
|
||||
|
||||
const FaqSearchState({this.filteredFaqQuestions = const []});
|
||||
}
|
||||
|
||||
class FetchRoomsState extends SosState {
|
||||
final List<SubSpaceModel> roomsList;
|
||||
final List<DeviceModel> devicesList;
|
||||
|
||||
const FetchRoomsState({required this.devicesList, required this.roomsList});
|
||||
|
||||
@override
|
||||
List<Object> get props => [devicesList];
|
||||
}
|
||||
|
||||
class OptionSelectedState extends SosState {
|
||||
final String selectedOption;
|
||||
final bool hasSelectionChanged;
|
||||
|
||||
OptionSelectedState({
|
||||
required this.selectedOption,
|
||||
required this.hasSelectionChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object> get props => [selectedOption, hasSelectionChanged];
|
||||
}
|
||||
|
||||
class SaveSelectionSuccessState extends SosState {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class SceneSwitch {
|
||||
class DeviceInfoModel {
|
||||
final int activeTime;
|
||||
final String category;
|
||||
final String categoryName;
|
||||
@ -27,7 +27,7 @@ class SceneSwitch {
|
||||
final String macAddress;
|
||||
final Subspace subspace;
|
||||
|
||||
SceneSwitch({
|
||||
DeviceInfoModel({
|
||||
required this.activeTime,
|
||||
required this.category,
|
||||
required this.categoryName,
|
||||
@ -55,8 +55,8 @@ class SceneSwitch {
|
||||
required this.subspace,
|
||||
});
|
||||
|
||||
factory SceneSwitch.fromJson(Map<String, dynamic> json) {
|
||||
return SceneSwitch(
|
||||
factory DeviceInfoModel.fromJson(Map<String, dynamic> json) {
|
||||
return DeviceInfoModel(
|
||||
activeTime: json['activeTime'],
|
||||
category: json['category'],
|
||||
categoryName: json['categoryName'],
|
@ -1,9 +1,9 @@
|
||||
class FourSceneQuestionModel {
|
||||
class QuestionModel {
|
||||
final int id;
|
||||
final String question;
|
||||
final String answer;
|
||||
|
||||
FourSceneQuestionModel({
|
||||
QuestionModel({
|
||||
required this.id,
|
||||
required this.question,
|
||||
required this.answer,
|
28
lib/features/devices/model/sos_model.dart
Normal file
28
lib/features/devices/model/sos_model.dart
Normal file
@ -0,0 +1,28 @@
|
||||
import 'package:syncrow_app/features/devices/model/status_model.dart';
|
||||
|
||||
class SosModel {
|
||||
String sosContactState;
|
||||
int batteryPercentage;
|
||||
|
||||
SosModel({
|
||||
required this.sosContactState,
|
||||
required this.batteryPercentage,
|
||||
});
|
||||
|
||||
factory SosModel.fromJson(List<StatusModel> jsonList) {
|
||||
late String _sosContactState;
|
||||
late int _batteryPercentage;
|
||||
|
||||
for (int i = 0; i < jsonList.length; i++) {
|
||||
if (jsonList[i].code == 'sos') {
|
||||
_sosContactState = jsonList[i].value ?? '';
|
||||
} else if (jsonList[i].code == 'battery_percentage') {
|
||||
_batteryPercentage = jsonList[i].value ?? 0;
|
||||
}
|
||||
}
|
||||
return SosModel(
|
||||
sosContactState: _sosContactState,
|
||||
batteryPercentage: _batteryPercentage,
|
||||
);
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ import 'package:syncrow_app/features/devices/bloc/four_scene_bloc/four_scene_blo
|
||||
import 'package:syncrow_app/features/devices/bloc/four_scene_bloc/four_scene_event.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/four_scene_bloc/four_scene_state.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/four_scene_question_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/question_model.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/four_scene_switch/four_scene_setting/question_page_four_scene.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||
@ -30,7 +30,7 @@ class FaqFourScenePage extends StatelessWidget {
|
||||
builder: (context, state) {
|
||||
final sensor = BlocProvider.of<FourSceneBloc>(context);
|
||||
|
||||
List<FourSceneQuestionModel> displayedQuestions = [];
|
||||
List<QuestionModel> displayedQuestions = [];
|
||||
if (state is FaqSearchState) {
|
||||
displayedQuestions = state.filteredFaqQuestions;
|
||||
} else if (state is FaqLoadedState) {
|
||||
|
@ -5,7 +5,7 @@ import 'package:syncrow_app/features/devices/bloc/four_scene_bloc/four_scene_blo
|
||||
import 'package:syncrow_app/features/devices/bloc/four_scene_bloc/four_scene_event.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/four_scene_bloc/four_scene_state.dart';
|
||||
import 'package:syncrow_app/features/devices/model/four_scene_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/four_scene_question_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/question_model.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_button.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||
@ -15,7 +15,7 @@ import 'package:syncrow_app/generated/assets.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class QuestionPageFourScene extends StatelessWidget {
|
||||
final FourSceneQuestionModel? questionModel;
|
||||
final QuestionModel? questionModel;
|
||||
|
||||
const QuestionPageFourScene({super.key, this.questionModel});
|
||||
|
||||
|
@ -18,6 +18,7 @@ import 'package:syncrow_app/features/devices/view/widgets/lights/light_interface
|
||||
import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_Interface.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/one_touch/one_touch_screen.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/power_clamp/power_clamp_page.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_screen.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/three_touch/three_touch_interface.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/two_gang/two_gang_Interface.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/two_touch/two_touch_Interface.dart';
|
||||
@ -228,6 +229,13 @@ void showDeviceInterface(DeviceModel device, BuildContext context) {
|
||||
pageBuilder: (context, animation1, animation2) =>
|
||||
FourSceneScreen(device: device)));
|
||||
|
||||
case DeviceType.SOS:
|
||||
Navigator.push(
|
||||
context,
|
||||
PageRouteBuilder(
|
||||
pageBuilder: (context, animation1, animation2) =>
|
||||
SosScreen(device: device)));
|
||||
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
@ -0,0 +1,112 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class AlarmManagementPage extends StatelessWidget {
|
||||
const AlarmManagementPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultScaffold(
|
||||
title: 'Alarm Settings',
|
||||
child: BlocProvider(
|
||||
create: (context) => SosBloc(sosId: ''),
|
||||
child: BlocBuilder<SosBloc, SosState>(
|
||||
builder: (context, state) {
|
||||
final _bloc = BlocProvider.of<SosBloc>(context);
|
||||
|
||||
return state is LoadingNewSate
|
||||
? const Center(
|
||||
child: DefaultContainer(
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: CircularProgressIndicator()),
|
||||
)
|
||||
: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
const BodyMedium(
|
||||
text: 'The Alarm Management',
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 12,
|
||||
fontColor: ColorsManager.grayColor,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
DefaultContainer(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 10, right: 10),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 50,
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
leading: const BodyMedium(
|
||||
text: 'SOS Alarm',
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 15,
|
||||
),
|
||||
trailing: Transform.scale(
|
||||
scale: .8,
|
||||
child: CupertinoSwitch(
|
||||
value: _bloc.enableAlarm,
|
||||
onChanged: (value) {
|
||||
context.read<SosBloc>().add(
|
||||
ToggleEnableAlarmEvent(value));
|
||||
},
|
||||
applyTheme: true,
|
||||
)),
|
||||
),
|
||||
),
|
||||
const Divider(
|
||||
color: ColorsManager.graysColor,
|
||||
),
|
||||
SizedBox(
|
||||
height: 50,
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
leading: const BodyLarge(
|
||||
text: 'Low Battery Reminder',
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 15,
|
||||
),
|
||||
trailing: Transform.scale(
|
||||
scale: .8,
|
||||
child: CupertinoSwitch(
|
||||
value: _bloc.closingReminder,
|
||||
onChanged: (value) {
|
||||
context.read<SosBloc>().add(
|
||||
ToggleClosingReminderEvent(
|
||||
value));
|
||||
},
|
||||
applyTheme: true,
|
||||
)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
231
lib/features/devices/view/widgets/sos/sos_records_screen.dart
Normal file
231
lib/features/devices/view/widgets/sos/sos_records_screen.dart
Normal file
@ -0,0 +1,231 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
|
||||
|
||||
import 'package:syncrow_app/features/devices/model/device_report_model.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
|
||||
import 'package:syncrow_app/generated/assets.dart';
|
||||
import 'package:syncrow_app/utils/context_extension.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class SosRecordsScreen extends StatefulWidget {
|
||||
final String sosId;
|
||||
const SosRecordsScreen({super.key, required this.sosId});
|
||||
|
||||
@override
|
||||
State<SosRecordsScreen> createState() => _SosRecordsScreenState();
|
||||
}
|
||||
|
||||
class _SosRecordsScreenState extends State<SosRecordsScreen> {
|
||||
int _selectedIndex = 0;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultScaffold(
|
||||
title: 'Records',
|
||||
child: BlocProvider(
|
||||
create: (context) =>
|
||||
SosBloc(sosId: widget.sosId)..add(const ReportLogsInitial()),
|
||||
child: BlocBuilder<SosBloc, SosState>(
|
||||
builder: (context, state) {
|
||||
final waterSensorBloc = BlocProvider.of<SosBloc>(context);
|
||||
final Map<String, List<DeviceEvent>> groupedRecords = {};
|
||||
|
||||
if (state is LoadingNewSate) {
|
||||
return const Center(
|
||||
child: DefaultContainer(
|
||||
width: 50, height: 50, child: CircularProgressIndicator()),
|
||||
);
|
||||
} else if (state is UpdateState) {
|
||||
for (var record in waterSensorBloc.recordGroups.data!) {
|
||||
final DateTime eventDateTime =
|
||||
DateTime.fromMillisecondsSinceEpoch(record.eventTime!);
|
||||
final String formattedDate =
|
||||
DateFormat('EEEE, dd/MM/yyyy').format(eventDateTime);
|
||||
if (groupedRecords.containsKey(formattedDate)) {
|
||||
groupedRecords[formattedDate]!.add(record);
|
||||
} else {
|
||||
groupedRecords[formattedDate] = [record];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DefaultTabController(
|
||||
length: 2,
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
decoration: const ShapeDecoration(
|
||||
color: ColorsManager.onPrimaryColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(30)),
|
||||
),
|
||||
),
|
||||
child: TabBar(
|
||||
onTap: (value) {
|
||||
setState(() {
|
||||
_selectedIndex = value;
|
||||
});
|
||||
},
|
||||
indicatorColor: Colors.white,
|
||||
dividerHeight: 0,
|
||||
indicatorSize: TabBarIndicatorSize.tab,
|
||||
indicator: const ShapeDecoration(
|
||||
color: ColorsManager.slidingBlueColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(20)),
|
||||
),
|
||||
),
|
||||
tabs: [
|
||||
Tab(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
child: BodySmall(
|
||||
text: 'Record',
|
||||
style: context.bodySmall.copyWith(
|
||||
color: _selectedIndex == 0
|
||||
? Colors.white
|
||||
: ColorsManager.blackColor,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Tab(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
child: Text(
|
||||
'Automation Log',
|
||||
style: context.bodySmall.copyWith(
|
||||
color: _selectedIndex == 1
|
||||
? Colors.white
|
||||
: ColorsManager.blackColor,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
children: [
|
||||
groupedRecords.isEmpty
|
||||
? Center(
|
||||
child: SvgPicture.asset(
|
||||
Assets.emptyLog,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
)
|
||||
: ListView.builder(
|
||||
itemCount: groupedRecords.length,
|
||||
itemBuilder: (context, index) {
|
||||
final String date =
|
||||
groupedRecords.keys.elementAt(index);
|
||||
final List<DeviceEvent> recordsForDate =
|
||||
groupedRecords[date]!;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Text(
|
||||
date,
|
||||
style: const TextStyle(
|
||||
color: ColorsManager.grayColor,
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
),
|
||||
DefaultContainer(
|
||||
child: Column(
|
||||
children: [
|
||||
...recordsForDate
|
||||
.asMap()
|
||||
.entries
|
||||
.map((entry) {
|
||||
final int idx = entry.key;
|
||||
final DeviceEvent record =
|
||||
entry.value;
|
||||
final DateTime eventDateTime =
|
||||
DateTime
|
||||
.fromMillisecondsSinceEpoch(
|
||||
record.eventTime!);
|
||||
final String formattedTime =
|
||||
DateFormat('HH:mm:ss')
|
||||
.format(eventDateTime);
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
ListTile(
|
||||
leading: SvgPicture.asset(
|
||||
record.value == 'true'
|
||||
? Assets
|
||||
.leakDetectedIcon
|
||||
: Assets
|
||||
.leakNormalIcon,
|
||||
height: 25,
|
||||
width: 25,
|
||||
),
|
||||
title: const Text(
|
||||
"SOS Alert Triggered",
|
||||
style: const TextStyle(
|
||||
fontWeight:
|
||||
FontWeight.bold,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
subtitle:
|
||||
Text(formattedTime),
|
||||
),
|
||||
if (idx !=
|
||||
recordsForDate.length - 1)
|
||||
const Divider(
|
||||
color: ColorsManager
|
||||
.graysColor,
|
||||
),
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
Container(
|
||||
height: 10,
|
||||
width: 20,
|
||||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
Assets.emptyLog,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
217
lib/features/devices/view/widgets/sos/sos_screen.dart
Normal file
217
lib/features/devices/view/widgets/sos/sos_screen.dart
Normal file
@ -0,0 +1,217 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/sos_model.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_alarm_management_page.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_records_screen.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_settings.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/battery_bar.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
|
||||
import 'package:syncrow_app/generated/assets.dart';
|
||||
|
||||
class SosScreen extends StatelessWidget {
|
||||
final DeviceModel? device;
|
||||
|
||||
|
||||
const SosScreen({super.key, this.device});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultScaffold(
|
||||
title: 'SOS',
|
||||
actions: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => SosSettings(device: device!)),
|
||||
);
|
||||
},
|
||||
child: SvgPicture.asset(Assets.assetsIconsSettings)),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
)
|
||||
],
|
||||
child: BlocProvider(
|
||||
create: (context) =>
|
||||
SosBloc(sosId: device?.uuid ?? '')..add(const SosInitial()),
|
||||
child: BlocBuilder<SosBloc, SosState>(
|
||||
builder: (context, state) {
|
||||
final sensor = BlocProvider.of<SosBloc>(context);
|
||||
SosModel model =
|
||||
SosModel(batteryPercentage: 0, sosContactState: 'normal');
|
||||
if (state is LoadingNewSate) {
|
||||
model = state.sosSensor;
|
||||
} else if (state is UpdateState) {
|
||||
model = state.sensor;
|
||||
}
|
||||
return state is SosLoadingState
|
||||
? const Center(
|
||||
child: DefaultContainer(
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: CircularProgressIndicator()),
|
||||
)
|
||||
: RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
sensor.add(const SosInitial());
|
||||
},
|
||||
child: ListView(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: MediaQuery.sizeOf(context).height * 0.8,
|
||||
child: Column(
|
||||
children: [
|
||||
BatteryBar(
|
||||
batteryPercentage: model.batteryPercentage,
|
||||
),
|
||||
Expanded(
|
||||
flex: 4,
|
||||
child: InkWell(
|
||||
overlayColor: WidgetStateProperty.all(
|
||||
Colors.transparent),
|
||||
onTap: () {},
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius:
|
||||
BorderRadius.circular(890),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color:
|
||||
Colors.white.withOpacity(0.1),
|
||||
blurRadius: 24,
|
||||
offset: const Offset(-5, -5),
|
||||
blurStyle: BlurStyle.outer,
|
||||
),
|
||||
BoxShadow(
|
||||
color: Colors.black
|
||||
.withOpacity(0.11),
|
||||
blurRadius: 25,
|
||||
offset: const Offset(5, 5),
|
||||
blurStyle: BlurStyle.outer,
|
||||
),
|
||||
BoxShadow(
|
||||
color: Colors.black
|
||||
.withOpacity(0.13),
|
||||
blurRadius: 30,
|
||||
offset: const Offset(5, 5),
|
||||
blurStyle: BlurStyle.inner,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: SvgPicture.asset(
|
||||
model.sosContactState == 'normal'
|
||||
? Assets.redSos
|
||||
: Assets.greenSos,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: DefaultContainer(
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
SosRecordsScreen(
|
||||
sosId: device!.uuid!)),
|
||||
);
|
||||
},
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxHeight: 46, maxWidth: 50),
|
||||
child: SvgPicture.asset(
|
||||
Assets.doorRecordsIcon),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
const Flexible(
|
||||
child: FittedBox(
|
||||
child: BodySmall(
|
||||
text: 'Records',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Expanded(
|
||||
child: DefaultContainer(
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
const AlarmManagementPage()),
|
||||
);
|
||||
},
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxHeight: 46, maxWidth: 50),
|
||||
child: SvgPicture.asset(Assets
|
||||
.doorNotificationSetting),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
const Flexible(
|
||||
child: FittedBox(
|
||||
child: BodySmall(
|
||||
text: 'Alarm Settings',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,227 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class DisconnectDeviceDialog extends StatelessWidget {
|
||||
final Function()? cancelTab;
|
||||
final Function()? confirmTab;
|
||||
|
||||
const DisconnectDeviceDialog({
|
||||
super.key,
|
||||
required this.cancelTab,
|
||||
required this.confirmTab,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
const BodyLarge(
|
||||
text: 'Disconnect Device',
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: ColorsManager.red,
|
||||
fontSize: 16,
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 15, right: 15),
|
||||
child: Divider(
|
||||
color: ColorsManager.textGray,
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 15, right: 20, top: 15, bottom: 20),
|
||||
child: Column(
|
||||
children: [
|
||||
Center(
|
||||
child: Text(
|
||||
'This will disconnect your device from this Application')),
|
||||
],
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(
|
||||
right: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 0.5,
|
||||
),
|
||||
top: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 1.0,
|
||||
),
|
||||
)),
|
||||
child: SizedBox(
|
||||
child: InkWell(
|
||||
onTap: cancelTab,
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(15),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Cancel',
|
||||
style: TextStyle(
|
||||
color: ColorsManager.textGray,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(
|
||||
left: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 0.5,
|
||||
),
|
||||
top: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 1.0,
|
||||
),
|
||||
)),
|
||||
child: InkWell(
|
||||
onTap: confirmTab,
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(15),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Disconnect',
|
||||
style: TextStyle(
|
||||
color: ColorsManager.red,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
),
|
||||
)),
|
||||
))
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DisconnectWipeData extends StatelessWidget {
|
||||
final Function()? cancelTab;
|
||||
final Function()? confirmTab;
|
||||
|
||||
const DisconnectWipeData({
|
||||
super.key,
|
||||
required this.cancelTab,
|
||||
required this.confirmTab,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
const BodyLarge(
|
||||
text: 'Disconnect and Wipe Data',
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: ColorsManager.red,
|
||||
fontSize: 16,
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 15, right: 15),
|
||||
child: Divider(
|
||||
color: ColorsManager.textGray,
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 15, right: 20, top: 15, bottom: 20),
|
||||
child: Column(
|
||||
children: [
|
||||
Center(
|
||||
child: Text(
|
||||
'This will disconnect your device from this Application and wipe all the data')),
|
||||
],
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(
|
||||
right: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 0.5,
|
||||
),
|
||||
top: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 1.0,
|
||||
),
|
||||
)),
|
||||
child: SizedBox(
|
||||
child: InkWell(
|
||||
onTap: cancelTab,
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(15),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Cancel',
|
||||
style: TextStyle(
|
||||
color: ColorsManager.textGray,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(
|
||||
left: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 0.5,
|
||||
),
|
||||
top: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 1.0,
|
||||
),
|
||||
)),
|
||||
child: InkWell(
|
||||
onTap: confirmTab,
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(15),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Disconnect',
|
||||
style: TextStyle(
|
||||
color: ColorsManager.red,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
),
|
||||
)),
|
||||
))
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/question_model.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_setting/question_page.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||
import 'package:syncrow_app/generated/assets.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class FaqSosPage extends StatelessWidget {
|
||||
final DeviceModel? device;
|
||||
|
||||
const FaqSosPage({super.key, this.device});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
TextEditingController _searchController = TextEditingController();
|
||||
return DefaultScaffold(
|
||||
title: 'FAQ',
|
||||
child: BlocProvider(
|
||||
create: (context) =>
|
||||
SosBloc(sosId: device?.uuid ?? '')..add(const SosInitialQuestion()),
|
||||
child: BlocBuilder<SosBloc, SosState>(
|
||||
builder: (context, state) {
|
||||
final sensor = BlocProvider.of<SosBloc>(context);
|
||||
|
||||
List<QuestionModel> displayedQuestions = [];
|
||||
if (state is FaqSearchState) {
|
||||
displayedQuestions = state.filteredFaqQuestions;
|
||||
} else if (state is FaqLoadedState) {
|
||||
displayedQuestions = state.filteredFaqQuestions;
|
||||
}
|
||||
return state is SosLoadingState
|
||||
? const Center(
|
||||
child: DefaultContainer(
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: CircularProgressIndicator()),
|
||||
)
|
||||
: RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
sensor.add(const SosInitial());
|
||||
},
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
DefaultContainer(
|
||||
padding: const EdgeInsets.all(5),
|
||||
child: TextFormField(
|
||||
controller: _searchController,
|
||||
onChanged: (value) {
|
||||
sensor.add(SearchFaqEvent(value));
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Enter your questions',
|
||||
hintStyle: const TextStyle(
|
||||
color: ColorsManager.textGray,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400),
|
||||
suffixIcon: Container(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
margin: const EdgeInsets.all(10.0),
|
||||
child: SvgPicture.asset(
|
||||
Assets.searchIcon,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.04,
|
||||
),
|
||||
BodyMedium(
|
||||
text: _searchController.text.isEmpty
|
||||
? 'Device Related FAQs'
|
||||
: '${displayedQuestions.length} Help Topics',
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 12,
|
||||
fontColor: ColorsManager.grayColor,
|
||||
),
|
||||
Expanded(
|
||||
child: DefaultContainer(
|
||||
child: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: displayedQuestions.length,
|
||||
itemBuilder: (context, index) {
|
||||
final faq = displayedQuestions[index];
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => QuestionPage(
|
||||
questionModel: faq,
|
||||
)),
|
||||
);
|
||||
},
|
||||
child: SizedBox(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: BodyMedium(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
text: faq.question,
|
||||
),
|
||||
),
|
||||
const Icon(
|
||||
Icons.keyboard_arrow_right,
|
||||
color: ColorsManager.textGray,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Divider(
|
||||
color: ColorsManager.dividerColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
)),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,219 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_app/features/app_layout/model/space_model.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
|
||||
import 'package:syncrow_app/features/devices/model/sos_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/subspace_model.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||
import 'package:syncrow_app/navigation/routing_constants.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class LocationSosPage extends StatelessWidget {
|
||||
final SpaceModel? space;
|
||||
final String? deviceId;
|
||||
|
||||
const LocationSosPage({
|
||||
super.key,
|
||||
this.space,
|
||||
this.deviceId,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String roomIdSelected = '';
|
||||
|
||||
return Scaffold(
|
||||
body: BlocProvider(
|
||||
create: (context) => SosBloc(sosId: deviceId ?? '')
|
||||
..add(const SosInitial())
|
||||
..add(SosInitialDeviseInfo())
|
||||
..add(FetchRoomsEvent(unit: space!)),
|
||||
child: BlocBuilder<SosBloc, SosState>(
|
||||
builder: (context, state) {
|
||||
final _bloc = BlocProvider.of<SosBloc>(context);
|
||||
SosModel model =
|
||||
SosModel(batteryPercentage: 0, sosContactState: '');
|
||||
if (state is SaveSelectionSuccessState) {
|
||||
new Future.delayed(const Duration(microseconds: 500), () {
|
||||
_bloc.add(SosInitial());
|
||||
Navigator.of(context).pop(true);
|
||||
});
|
||||
}
|
||||
return state is SosLoadingState
|
||||
? const Center(
|
||||
child: DefaultContainer(
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
)
|
||||
: DefaultScaffold(
|
||||
actions: [
|
||||
BlocBuilder<SosBloc, SosState>(
|
||||
builder: (context, state) {
|
||||
final bool canSave = state is OptionSelectedState &&
|
||||
state.hasSelectionChanged;
|
||||
return InkWell(
|
||||
onTap: canSave
|
||||
? () {
|
||||
context.read<SosBloc>().add(AssignRoomEvent(
|
||||
context: context,
|
||||
roomId: roomIdSelected,
|
||||
unit: space!));
|
||||
}
|
||||
: null,
|
||||
child: BodyMedium(
|
||||
text: 'Save',
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 16,
|
||||
fontColor: canSave
|
||||
? ColorsManager.slidingBlueColor
|
||||
: ColorsManager.primaryTextColor,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
],
|
||||
child: RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
// sensor.add(const SosInitial());
|
||||
},
|
||||
child: ListView(
|
||||
shrinkWrap: true,
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
children: [
|
||||
const BodyMedium(
|
||||
text: 'Smart Device Location',
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 12,
|
||||
fontColor: ColorsManager.grayColor,
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
DefaultContainer(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: ListView.builder(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
itemCount: _bloc.roomsList.length,
|
||||
itemBuilder: (context, index) {
|
||||
final fromRoom = _bloc.roomsList[index];
|
||||
final isSelected = (state
|
||||
is OptionSelectedState &&
|
||||
state.selectedOption == fromRoom.id) ||
|
||||
(state is! OptionSelectedState &&
|
||||
fromRoom.id ==
|
||||
_bloc.deviceInfo.subspace.uuid);
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
_buildCheckboxOption(
|
||||
label: fromRoom.name!,
|
||||
isSelected: isSelected,
|
||||
onTap: (label) {
|
||||
context.read<SosBloc>().add(
|
||||
SelectOptionEvent(
|
||||
selectedOption: fromRoom.id!,
|
||||
),
|
||||
);
|
||||
roomIdSelected = fromRoom.id!;
|
||||
},
|
||||
),
|
||||
if (index < _bloc.roomsList.length - 1) ...[
|
||||
const SizedBox(height: 10),
|
||||
const Divider(
|
||||
color: ColorsManager.dividerColor,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
],
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CircularCheckbox extends StatefulWidget {
|
||||
final bool value;
|
||||
final ValueChanged<bool?> onChanged;
|
||||
|
||||
CircularCheckbox({required this.value, required this.onChanged});
|
||||
|
||||
@override
|
||||
_CircularCheckboxState createState() => _CircularCheckboxState();
|
||||
}
|
||||
|
||||
class _CircularCheckboxState extends State<CircularCheckbox> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
widget.onChanged(!widget.value);
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: widget.value
|
||||
? ColorsManager.primaryColorWithOpacity.withOpacity(0.01)
|
||||
: Colors.grey,
|
||||
width: 2.0,
|
||||
),
|
||||
color: widget.value
|
||||
? ColorsManager.primaryColorWithOpacity
|
||||
: Colors.transparent,
|
||||
),
|
||||
width: 24.0,
|
||||
height: 24.0,
|
||||
child: widget.value
|
||||
? const Icon(
|
||||
Icons.check,
|
||||
color: Colors.white,
|
||||
size: 16.0,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildCheckboxOption({
|
||||
required String label,
|
||||
required bool isSelected,
|
||||
required Function(String) onTap,
|
||||
}) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 10, top: 10),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
BodyMedium(
|
||||
text: label,
|
||||
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w400),
|
||||
),
|
||||
CircularCheckbox(
|
||||
value: isSelected,
|
||||
onChanged: (bool? value) {
|
||||
if (value == true) {
|
||||
onTap(label);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
|
||||
import 'package:syncrow_app/features/devices/model/question_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/sos_model.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_button.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||
import 'package:syncrow_app/generated/assets.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class QuestionPage extends StatelessWidget {
|
||||
final QuestionModel? questionModel;
|
||||
|
||||
const QuestionPage({super.key, this.questionModel});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultScaffold(
|
||||
title: 'FAQ',
|
||||
child: BlocProvider(
|
||||
create: (context) => SosBloc(sosId: '')..add(const SosInitial()),
|
||||
child: BlocBuilder<SosBloc, SosState>(
|
||||
builder: (context, state) {
|
||||
final sensor = BlocProvider.of<SosBloc>(context);
|
||||
SosModel model =
|
||||
SosModel(batteryPercentage: 0, sosContactState: 'normal');
|
||||
if (state is LoadingNewSate) {
|
||||
model = state.sosSensor;
|
||||
} else if (state is UpdateState) {
|
||||
model = state.sensor;
|
||||
}
|
||||
return state is SosLoadingState
|
||||
? const Center(
|
||||
child: DefaultContainer(
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: CircularProgressIndicator()),
|
||||
)
|
||||
: RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
sensor.add(const SosInitial());
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
DefaultContainer(
|
||||
padding: EdgeInsets.all(15),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
BodyLarge(
|
||||
text: questionModel!.question,
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: ColorsManager.blackColor,
|
||||
),
|
||||
SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
BodyMedium(
|
||||
text: questionModel!.answer,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: ColorsManager.secondaryTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.15,
|
||||
),
|
||||
Center(
|
||||
child: SizedBox(
|
||||
width: 180,
|
||||
child: DefaultButton(
|
||||
backgroundColor: ColorsManager.grayButtonColors,
|
||||
borderRadius: 50,
|
||||
onPressed: () {},
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.thumbUp,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
BodyMedium(
|
||||
text: 'Helpful',
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: ColorsManager.blackColor,
|
||||
),
|
||||
],
|
||||
)),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
Center(
|
||||
child: SizedBox(
|
||||
width: 180,
|
||||
child: DefaultButton(
|
||||
backgroundColor: ColorsManager.grayButtonColors,
|
||||
borderRadius: 50,
|
||||
onPressed: () {},
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.thumbDown,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
BodyMedium(
|
||||
text: 'Not Helpful',
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: ColorsManager.blackColor,
|
||||
),
|
||||
],
|
||||
)),
|
||||
),
|
||||
),
|
||||
],
|
||||
));
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/sos_model.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_button.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class ShareSosPage extends StatelessWidget {
|
||||
final DeviceModel? device;
|
||||
|
||||
const ShareSosPage({super.key, this.device});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultScaffold(
|
||||
title: 'Share Device',
|
||||
child: BlocProvider(
|
||||
create: (context) =>
|
||||
SosBloc(sosId: device?.uuid ?? '')..add(const SosInitial()),
|
||||
child: BlocBuilder<SosBloc, SosState>(
|
||||
builder: (context, state) {
|
||||
final sensor = BlocProvider.of<SosBloc>(context);
|
||||
SosModel model =
|
||||
SosModel(batteryPercentage: 0, sosContactState: 'normal');
|
||||
if (state is LoadingNewSate) {
|
||||
model = state.sosSensor;
|
||||
} else if (state is UpdateState) {
|
||||
model = state.sensor;
|
||||
}
|
||||
return state is SosLoadingState
|
||||
? const Center(
|
||||
child: DefaultContainer(
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: CircularProgressIndicator()),
|
||||
)
|
||||
: RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
sensor.add(const SosInitial());
|
||||
},
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const BodyLarge(
|
||||
text: 'Sharing Method Not Supported',
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: ColorsManager.blackColor,
|
||||
),
|
||||
const BodyMedium(
|
||||
text:
|
||||
'Currently, you cannot use the specified method to share Bluetooth mesh devices Zigbee devices, infrared devices, Bluetooth Beacon Devices, and certain Bluetooth LE devices with other users.',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: ColorsManager.secondaryTextColor,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
const BodyLarge(
|
||||
text: 'Recommended Sharing Method',
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: ColorsManager.blackColor,
|
||||
),
|
||||
const BodyMedium(
|
||||
text:
|
||||
'If the recipient is a home member or a reliable user, tap Me > Home Management > Add Member and add the recipient to your home. Then, devices in the home can be shared with the recipient in bulk.',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: ColorsManager.secondaryTextColor,
|
||||
),
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.15,
|
||||
),
|
||||
Center(
|
||||
child: SizedBox(
|
||||
width: 250,
|
||||
child: DefaultButton(
|
||||
backgroundColor: ColorsManager.blueColor1,
|
||||
borderRadius: 50,
|
||||
onPressed: () {
|
||||
|
||||
},
|
||||
child: Text('Add Home Member')),
|
||||
),
|
||||
)
|
||||
],
|
||||
));
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/sos_model.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class SosInfoPage extends StatelessWidget {
|
||||
final DeviceModel? device;
|
||||
|
||||
const SosInfoPage({super.key, this.device});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultScaffold(
|
||||
title: 'Device Information',
|
||||
child: BlocProvider(
|
||||
create: (context) => SosBloc(sosId: device?.uuid ?? '')
|
||||
..add(const SosInitial())
|
||||
..add(SosInitialDeviseInfo()),
|
||||
child: BlocBuilder<SosBloc, SosState>(
|
||||
builder: (context, state) {
|
||||
final _bloc = BlocProvider.of<SosBloc>(context);
|
||||
SosModel model =
|
||||
SosModel(batteryPercentage: 0, sosContactState: '');
|
||||
if (state is LoadingNewSate) {
|
||||
model = state.sosSensor;
|
||||
} else if (state is UpdateState) {
|
||||
model = state.sensor;
|
||||
}
|
||||
return state is SosLoadingState
|
||||
? const Center(
|
||||
child: DefaultContainer(
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: CircularProgressIndicator()),
|
||||
)
|
||||
: RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
_bloc.add(const SosInitial());
|
||||
},
|
||||
child: DefaultContainer(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 5, right: 5),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
const BodyLarge(
|
||||
text: 'Virtual ID',
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: ColorsManager.blackColor,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
BodySmall(
|
||||
text: _bloc.deviceInfo.productUuid,
|
||||
fontColor: ColorsManager.primaryTextColor,
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Clipboard.setData(
|
||||
ClipboardData(
|
||||
text: _bloc.deviceInfo.productUuid,
|
||||
),
|
||||
);
|
||||
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text("Copied to Clipboard"),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: const Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.copy,
|
||||
color: ColorsManager.blueColor,
|
||||
),
|
||||
BodyMedium(
|
||||
text: 'Copy',
|
||||
fontColor: ColorsManager.blueColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
const Divider(
|
||||
color: ColorsManager.dividerColor,
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const BodyLarge(
|
||||
text: 'MAC',
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: ColorsManager.blackColor,
|
||||
),
|
||||
BodySmall(
|
||||
text: _bloc.deviceInfo.macAddress,
|
||||
fontColor: ColorsManager.primaryTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
const Divider(
|
||||
color: ColorsManager.dividerColor,
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const BodyLarge(
|
||||
text: 'Time Zone',
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: ColorsManager.blackColor,
|
||||
),
|
||||
BodySmall(
|
||||
text: _bloc.deviceInfo.timeZone,
|
||||
fontColor: ColorsManager.primaryTextColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
]),
|
||||
)));
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,191 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/sos_model.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_setting/location_setting.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||
import 'package:syncrow_app/generated/assets.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class SosProfilePage extends StatelessWidget {
|
||||
final DeviceModel? device;
|
||||
|
||||
const SosProfilePage({super.key, this.device});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var spaces = HomeCubit.getInstance().spaces;
|
||||
|
||||
return DefaultScaffold(
|
||||
title: 'Device Settings',
|
||||
leading: IconButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(true);
|
||||
},
|
||||
icon: const Icon(Icons.arrow_back_ios)),
|
||||
child: BlocProvider(
|
||||
create: (context) => SosBloc(sosId: device?.uuid ?? '')
|
||||
..add(const SosInitial())
|
||||
..add(SosInitialDeviseInfo()),
|
||||
child: BlocBuilder<SosBloc, SosState>(
|
||||
builder: (context, state) {
|
||||
final _bloc = BlocProvider.of<SosBloc>(context);
|
||||
SosModel model =
|
||||
SosModel(batteryPercentage: 0, sosContactState: '');
|
||||
if (state is LoadingNewSate) {
|
||||
model = state.sosSensor;
|
||||
} else if (state is UpdateState) {
|
||||
model = state.sensor;
|
||||
}
|
||||
return state is SosLoadingState
|
||||
? const Center(
|
||||
child: DefaultContainer(
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: CircularProgressIndicator()),
|
||||
)
|
||||
: RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
_bloc.add(const SosInitial());
|
||||
},
|
||||
child: ListView(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 60,
|
||||
backgroundColor: Colors.white,
|
||||
child: CircleAvatar(
|
||||
radius: 55,
|
||||
backgroundColor: ColorsManager.graysColor,
|
||||
child: ClipOval(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Center(
|
||||
child: SvgPicture.asset(
|
||||
Assets.fourSceneIcon,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
SizedBox(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
IntrinsicWidth(
|
||||
child: ConstrainedBox(
|
||||
constraints:
|
||||
const BoxConstraints(maxWidth: 200),
|
||||
child: TextFormField(
|
||||
maxLength: 30,
|
||||
style: const TextStyle(
|
||||
color: Colors.black,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
focusNode: _bloc.focusNode,
|
||||
controller: _bloc.nameController,
|
||||
enabled: _bloc.editName,
|
||||
onEditingComplete: () {
|
||||
_bloc.add(SaveNameEvent());
|
||||
},
|
||||
decoration: const InputDecoration(
|
||||
hintText: "Your Name",
|
||||
border: InputBorder.none,
|
||||
fillColor: Colors.white10,
|
||||
counterText: '',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
_bloc.add(const ChangeNameEvent(value: true));
|
||||
},
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||
child: Icon(
|
||||
Icons.edit_outlined,
|
||||
size: 20,
|
||||
color: ColorsManager.textPrimaryColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const BodyMedium(
|
||||
text: 'Smart Device Information',
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 12,
|
||||
fontColor: ColorsManager.grayColor,
|
||||
),
|
||||
DefaultContainer(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
bool val = await Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => LocationSosPage(
|
||||
space: spaces!.first,
|
||||
deviceId: device?.uuid ?? '',
|
||||
)),
|
||||
);
|
||||
if (val == true) {
|
||||
_bloc.add(SosInitialDeviseInfo());
|
||||
}
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const SizedBox(
|
||||
child: Text('Location'),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
child: BodyMedium(
|
||||
text: _bloc
|
||||
.deviceInfo.subspace.subspaceName,
|
||||
fontColor: ColorsManager.textGray,
|
||||
),
|
||||
),
|
||||
const Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 15,
|
||||
color: ColorsManager.textGray,
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class SosUpdateNote extends StatelessWidget {
|
||||
final Function()? cancelTab;
|
||||
final Function()? confirmTab;
|
||||
|
||||
const SosUpdateNote({
|
||||
super.key,
|
||||
required this.cancelTab,
|
||||
required this.confirmTab,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
BodyLarge(
|
||||
text: 'Update Note',
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: ColorsManager.switchButton.withOpacity(0.6),
|
||||
fontSize: 16,
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 15, right: 15),
|
||||
child: Divider(
|
||||
color: ColorsManager.textGray,
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 15, right: 20, top: 15, bottom: 20),
|
||||
child: Column(
|
||||
children: [
|
||||
Center(
|
||||
child: Text(
|
||||
'This update may take a long time. Make sure that the device is fully charged. The device will be unavailable during the update.',
|
||||
textAlign: TextAlign.center,
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(
|
||||
right: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 0.5,
|
||||
),
|
||||
top: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 1.0,
|
||||
),
|
||||
)),
|
||||
child: SizedBox(
|
||||
child: InkWell(
|
||||
onTap: cancelTab,
|
||||
child: const Padding(
|
||||
padding: const EdgeInsets.only(top: 15, bottom: 15),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Cancel',
|
||||
style: TextStyle(
|
||||
color: ColorsManager.textGray,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(
|
||||
left: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 0.5,
|
||||
),
|
||||
top: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 1.0,
|
||||
),
|
||||
)),
|
||||
child: InkWell(
|
||||
onTap: confirmTab,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 15, bottom: 15),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Start Update',
|
||||
style: TextStyle(
|
||||
color:
|
||||
ColorsManager.switchButton.withOpacity(0.6),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
),
|
||||
)),
|
||||
))
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,344 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:percent_indicator/linear_percent_indicator.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_setting/sos_update_note.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_button.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||
import 'package:syncrow_app/generated/assets.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class SosUpdatePage extends StatelessWidget {
|
||||
const SosUpdatePage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultScaffold(
|
||||
title: 'Device Update',
|
||||
child: BlocProvider(
|
||||
create: (context) => SosBloc(sosId: '')..add(const SosInitial()),
|
||||
child: BlocBuilder<SosBloc, SosState>(
|
||||
builder: (context, state) {
|
||||
return state is SosLoadingState
|
||||
? const Center(
|
||||
child: DefaultContainer(
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: CircularProgressIndicator()),
|
||||
)
|
||||
: RefreshIndicator(
|
||||
onRefresh: () async {},
|
||||
child: Column(
|
||||
children: [
|
||||
// SizedBox(
|
||||
// height: MediaQuery.of(context).size.height * 0.15,
|
||||
// ),
|
||||
DefaultContainer(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 50,
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
leading: SizedBox(
|
||||
width: 200,
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: const BoxDecoration(
|
||||
color:
|
||||
ColorsManager.primaryColor,
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(50))),
|
||||
child: SvgPicture.asset(
|
||||
Assets.checkUpdateIcon,
|
||||
fit: BoxFit.fill,
|
||||
height: 25,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {},
|
||||
child: const BodyMedium(
|
||||
text: 'Automatic Update',
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
trailing: Container(
|
||||
width: 100,
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.end,
|
||||
children: [
|
||||
const BodyMedium(
|
||||
text: 'Off',
|
||||
fontColor: ColorsManager.textGray,
|
||||
),
|
||||
Transform.scale(
|
||||
scale: .8,
|
||||
child: CupertinoSwitch(
|
||||
value: true,
|
||||
onChanged: (value) {},
|
||||
applyTheme: true,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
UpdateSosContainerWithProgressBar(
|
||||
sosDescription:
|
||||
'Connectivity Issue Resolved Fixed a bug that caused the SOS button to disconnect from the app intermittently.',
|
||||
sosVersion: 'SOS v2.0.5',
|
||||
),
|
||||
// const UpdatedContainer(
|
||||
// sosVersion: 'SOS v1.0.13',
|
||||
// sosDescription: 'SOS is up to date',
|
||||
// ),
|
||||
|
||||
// const NewUpdateContainer(
|
||||
// sosVersion: 'SOS v2.0.5',
|
||||
// sosDescription:
|
||||
// 'Connectivity Issue Resolved Fixed a bug that caused the SOS button to disconnect from the app intermittently.',
|
||||
// ),
|
||||
const SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
],
|
||||
));
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class UpdatedContainer extends StatelessWidget {
|
||||
final String? sosVersion;
|
||||
final String? sosDescription;
|
||||
const UpdatedContainer({
|
||||
this.sosVersion,
|
||||
this.sosDescription,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultContainer(
|
||||
height: MediaQuery.of(context).size.height * 0.35,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(25),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.emptyUpdateIcon,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
BodyMedium(
|
||||
text: sosVersion!,
|
||||
fontColor: ColorsManager.primaryTextColor,
|
||||
),
|
||||
BodyMedium(
|
||||
text: sosDescription!,
|
||||
fontColor: ColorsManager.blackColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NewUpdateContainer extends StatelessWidget {
|
||||
final String? sosVersion;
|
||||
final String? sosDescription;
|
||||
const NewUpdateContainer({
|
||||
this.sosVersion,
|
||||
this.sosDescription,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultContainer(
|
||||
height: MediaQuery.of(context).size.height * 0.50,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(25),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.emptyUpdateIcon,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
const BodyMedium(
|
||||
text: 'New Update Available Now!',
|
||||
fontColor: ColorsManager.blueColor,
|
||||
),
|
||||
BodyMedium(
|
||||
text: sosVersion!,
|
||||
fontColor: ColorsManager.primaryTextColor,
|
||||
),
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width * 0.7,
|
||||
child: BodyMedium(
|
||||
text: sosDescription!,
|
||||
fontColor: ColorsManager.textPrimaryColor,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.6,
|
||||
child: DefaultButton(
|
||||
borderRadius: 25,
|
||||
backgroundColor: ColorsManager.blueColor1,
|
||||
height: 150,
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return SosUpdateNote(
|
||||
cancelTab: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
confirmTab: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: const BodyMedium(
|
||||
text: 'Update Now',
|
||||
fontColor: Colors.white,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class UpdateSosContainerWithProgressBar extends StatelessWidget {
|
||||
final String? sosVersion;
|
||||
final String? sosDescription;
|
||||
const UpdateSosContainerWithProgressBar({
|
||||
this.sosVersion,
|
||||
this.sosDescription,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
DefaultContainer(
|
||||
height: MediaQuery.of(context).size.height * 0.50,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(25),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.emptyUpdateIcon,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
const BodyMedium(
|
||||
text: 'New Update Available Now!',
|
||||
fontColor: ColorsManager.blueColor,
|
||||
),
|
||||
BodyMedium(
|
||||
text: sosVersion!,
|
||||
fontColor: ColorsManager.primaryTextColor,
|
||||
),
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.7,
|
||||
child: BodyMedium(
|
||||
text: sosDescription!,
|
||||
fontColor: ColorsManager.textPrimaryColor,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
LinearPercentIndicator(
|
||||
barRadius: Radius.circular(10),
|
||||
width: 170.0,
|
||||
animation: true,
|
||||
animationDuration: 1000,
|
||||
lineHeight: 5.0,
|
||||
percent: 0.2,
|
||||
linearStrokeCap: LinearStrokeCap.butt,
|
||||
progressColor: ColorsManager.blueColor1,
|
||||
),
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.7,
|
||||
child: const BodyMedium(
|
||||
text: 'Downloading Update please be patient',
|
||||
fontColor: ColorsManager.textPrimaryColor,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.7,
|
||||
child: const BodyMedium(
|
||||
text:
|
||||
'Please keep the power of the device connected during the upgrade process.',
|
||||
fontColor: ColorsManager.textPrimaryColor,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class UpdateInfoDialog extends StatelessWidget {
|
||||
final Function()? cancelTab;
|
||||
final Function()? confirmTab;
|
||||
|
||||
const UpdateInfoDialog({
|
||||
super.key,
|
||||
required this.cancelTab,
|
||||
required this.confirmTab,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
BodyLarge(
|
||||
text: 'Update Available',
|
||||
fontWeight: FontWeight.w700,
|
||||
fontColor: ColorsManager.switchButton.withOpacity(0.6),
|
||||
fontSize: 16,
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 15, right: 15),
|
||||
child: Divider(
|
||||
color: ColorsManager.textGray,
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 15, right: 20, top: 15, bottom: 20),
|
||||
child: Column(
|
||||
children: [
|
||||
Center(
|
||||
child: Text(
|
||||
'An update is available for your device. Version 2.1.0 includes new features and important fixes to enhance performance and security.',
|
||||
textAlign: TextAlign.center,
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(
|
||||
right: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 0.5,
|
||||
),
|
||||
top: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 1.0,
|
||||
),
|
||||
)),
|
||||
child: SizedBox(
|
||||
child: InkWell(
|
||||
onTap: cancelTab,
|
||||
child: const Padding(
|
||||
padding: const EdgeInsets.only(top: 15, bottom: 15),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Remind me later',
|
||||
style: TextStyle(
|
||||
color: ColorsManager.textGray,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(
|
||||
left: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 0.5,
|
||||
),
|
||||
top: BorderSide(
|
||||
color: ColorsManager.textGray,
|
||||
width: 1.0,
|
||||
),
|
||||
)),
|
||||
child: InkWell(
|
||||
onTap: confirmTab,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 15, bottom: 15),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Update Now',
|
||||
style: TextStyle(
|
||||
color:
|
||||
ColorsManager.switchButton.withOpacity(0.6),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
),
|
||||
)),
|
||||
))
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
484
lib/features/devices/view/widgets/sos/sos_settings.dart
Normal file
484
lib/features/devices/view/widgets/sos/sos_settings.dart
Normal file
@ -0,0 +1,484 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_event.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/sos_bloc/sos_state.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/sos_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/subspace_model.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_setting/delete_dialog.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_setting/sos_profile_page.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_setting/faq_sos_page.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_setting/share_sos_page.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_setting/sos_info_page.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_setting/sos_update_page.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/sos/sos_setting/update_dialog_sos.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
|
||||
import 'package:syncrow_app/generated/assets.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
|
||||
class SosSettings extends StatelessWidget {
|
||||
final DeviceModel? device;
|
||||
const SosSettings({
|
||||
super.key,
|
||||
this.device,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultScaffold(
|
||||
title: 'Device Settings',
|
||||
child: BlocProvider(
|
||||
create: (context) => SosBloc(sosId: device?.uuid ?? '')
|
||||
..add(const SosInitial())
|
||||
..add(SosInitialDeviseInfo()),
|
||||
child: BlocBuilder<SosBloc, SosState>(
|
||||
builder: (context, state) {
|
||||
final _bloc = BlocProvider.of<SosBloc>(context);
|
||||
|
||||
SosModel model =
|
||||
SosModel(batteryPercentage: 0, sosContactState: 'normal');
|
||||
if (state is LoadingNewSate) {
|
||||
model = state.sosSensor;
|
||||
} else if (state is UpdateState) {
|
||||
model = state.sensor;
|
||||
}
|
||||
return state is SosLoadingState
|
||||
? const Center(
|
||||
child: DefaultContainer(
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: CircularProgressIndicator()),
|
||||
)
|
||||
: ListView(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 10,
|
||||
),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => SosProfilePage(
|
||||
device: device,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Stack(
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
const SizedBox(height: 20),
|
||||
DefaultContainer(
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(30)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(left: 90),
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
const BodyMedium(
|
||||
text: 'SOS',
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
BodySmall(
|
||||
text: _bloc.deviceInfo
|
||||
.subspace.subspaceName),
|
||||
],
|
||||
),
|
||||
const Icon(
|
||||
Icons.edit_outlined,
|
||||
color: ColorsManager.grayColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Positioned(
|
||||
top: 0,
|
||||
left: 20,
|
||||
child: CircleAvatar(
|
||||
radius: 40,
|
||||
backgroundColor: Colors.white,
|
||||
child: CircleAvatar(
|
||||
radius: 40,
|
||||
backgroundColor: Colors.grey,
|
||||
child: ClipOval(
|
||||
child: SvgPicture.asset(
|
||||
Assets.sosProfileIcon,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const BodyMedium(
|
||||
text: 'Device Management',
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 12,
|
||||
fontColor: ColorsManager.grayColor,
|
||||
),
|
||||
DefaultContainer(
|
||||
child: SettingWidget(
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
SosInfoPage(device: device!)),
|
||||
);
|
||||
},
|
||||
text: 'Device Information',
|
||||
icon: Assets.infoIcon,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const BodyMedium(
|
||||
text: 'Device Offline Notification',
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 12,
|
||||
fontColor: ColorsManager.grayColor,
|
||||
),
|
||||
DefaultContainer(
|
||||
child: Column(
|
||||
children: [
|
||||
SettingWidget(
|
||||
onChanged: (p0) {},
|
||||
isNotification: true,
|
||||
onTap: () {},
|
||||
text: 'Offline Notification',
|
||||
icon: Assets.notificationIcon,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const BodyMedium(
|
||||
text: 'Others',
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 12,
|
||||
fontColor: ColorsManager.grayColor,
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
DefaultContainer(
|
||||
child: Column(
|
||||
children: [
|
||||
SettingWidget(
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
ShareSosPage(device: device!)),
|
||||
);
|
||||
},
|
||||
text: 'Share Device',
|
||||
icon: Assets.shareIcon,
|
||||
),
|
||||
const Divider(
|
||||
color: ColorsManager.dividerColor,
|
||||
),
|
||||
SettingWidget(
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
FaqSosPage(device: device!)),
|
||||
);
|
||||
},
|
||||
text: 'Device FAQ',
|
||||
icon: Assets.faqIcon,
|
||||
),
|
||||
const Divider(
|
||||
color: ColorsManager.dividerColor,
|
||||
),
|
||||
SettingWidget(
|
||||
onTapUpdate: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return UpdateInfoDialog(
|
||||
cancelTab: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
confirmTab: () {
|
||||
// context
|
||||
// .read<
|
||||
// CreateSceneBloc>()
|
||||
// .add(DeleteSceneEvent(
|
||||
// sceneId: sceneId,
|
||||
// unitUuid: HomeCubit
|
||||
// .getInstance()
|
||||
// .selectedSpace!
|
||||
// .id!,
|
||||
// ));
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
isUpdate: true,
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
const SosUpdatePage()),
|
||||
);
|
||||
},
|
||||
text: 'Device Update',
|
||||
icon: Assets.updateIcon,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return Container(
|
||||
height: 200,
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const BodyMedium(
|
||||
text: 'Remove Device',
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 16,
|
||||
fontColor: ColorsManager.red,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
const SizedBox(
|
||||
width: 250,
|
||||
child: Divider(
|
||||
color: ColorsManager.dividerColor,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return DisconnectDeviceDialog(
|
||||
cancelTab: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
confirmTab: () {
|
||||
// context
|
||||
// .read<
|
||||
// CreateSceneBloc>()
|
||||
// .add(DeleteSceneEvent(
|
||||
// sceneId: sceneId,
|
||||
// unitUuid: HomeCubit
|
||||
// .getInstance()
|
||||
// .selectedSpace!
|
||||
// .id!,
|
||||
// ));
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: const BodyMedium(
|
||||
text: 'Disconnect Device',
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 15,
|
||||
fontColor:
|
||||
ColorsManager.textPrimaryColor,
|
||||
),
|
||||
),
|
||||
const Icon(
|
||||
Icons.keyboard_arrow_right,
|
||||
color: ColorsManager.textGray,
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return DisconnectWipeData(
|
||||
cancelTab: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
confirmTab: () {
|
||||
// context
|
||||
// .read<
|
||||
// CreateSceneBloc>()
|
||||
// .add(DeleteSceneEvent(
|
||||
// sceneId: sceneId,
|
||||
// unitUuid: HomeCubit
|
||||
// .getInstance()
|
||||
// .selectedSpace!
|
||||
// .id!,
|
||||
// ));
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: const BodyMedium(
|
||||
text:
|
||||
'Disconnect Device and Wipe Data',
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 15,
|
||||
fontColor:
|
||||
ColorsManager.textPrimaryColor,
|
||||
),
|
||||
),
|
||||
const Icon(
|
||||
Icons.keyboard_arrow_right,
|
||||
color: ColorsManager.textGray,
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: const Center(
|
||||
child: BodyMedium(
|
||||
text: 'Remove Device',
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 15,
|
||||
fontColor: ColorsManager.red,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SettingWidget extends StatelessWidget {
|
||||
final String? text;
|
||||
final bool? isUpdate;
|
||||
final bool? isNotification;
|
||||
final String? icon;
|
||||
final Function()? onTap;
|
||||
final Function()? onTapUpdate;
|
||||
final Function(bool)? onChanged;
|
||||
const SettingWidget(
|
||||
{super.key,
|
||||
this.text,
|
||||
this.icon,
|
||||
this.onTap,
|
||||
this.isUpdate,
|
||||
this.onChanged,
|
||||
this.isNotification = false,
|
||||
this.onTapUpdate});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
decoration: const BoxDecoration(
|
||||
color: ColorsManager.primaryColor,
|
||||
borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||
child: SvgPicture.asset(
|
||||
icon!,
|
||||
fit: BoxFit.none,
|
||||
height: 30,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 8,
|
||||
),
|
||||
Expanded(
|
||||
flex: isUpdate == true ? 5 : 10,
|
||||
child: BodyMedium(
|
||||
text: text!,
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w400,
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
isUpdate == true
|
||||
? InkWell(
|
||||
onTap: onTapUpdate,
|
||||
child: const BodyMedium(
|
||||
text: '1 Update Available',
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontColor: ColorsManager.blueColor,
|
||||
),
|
||||
)
|
||||
: SizedBox(),
|
||||
isNotification == false
|
||||
? const Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
color: ColorsManager.graysColor,
|
||||
size: 20,
|
||||
)
|
||||
: Transform.scale(
|
||||
scale: .8,
|
||||
child: CupertinoSwitch(
|
||||
value: true,
|
||||
onChanged: onChanged,
|
||||
applyTheme: true,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
58
lib/features/devices/view/widgets/sos/sos_status_bar.dart
Normal file
58
lib/features/devices/view/widgets/sos/sos_status_bar.dart
Normal file
@ -0,0 +1,58 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:syncrow_app/features/devices/model/smart_door_model.dart';
|
||||
import 'package:syncrow_app/generated/assets.dart';
|
||||
|
||||
class SosStatusBar extends StatelessWidget {
|
||||
const SosStatusBar({
|
||||
required this.smartDoorModel,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final SmartDoorModel smartDoorModel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
SvgPicture.asset(Assets.assetsIconsWifi),
|
||||
Transform.rotate(
|
||||
angle: 1.5708, // 90 degrees in radians (π/2 or 1.5708)
|
||||
child: Icon(
|
||||
_getBatteryIcon(smartDoorModel.residualElectricity),
|
||||
color: _getBatteryColor(smartDoorModel.residualElectricity),
|
||||
size: 30,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
IconData _getBatteryIcon(int batteryLevel) {
|
||||
// if (batteryState == BatteryState.charging) {
|
||||
// return Icons.battery_charging_full;
|
||||
// } else
|
||||
if (batteryLevel >= 80) {
|
||||
return Icons.battery_full;
|
||||
} else if (batteryLevel >= 60) {
|
||||
return Icons.battery_4_bar;
|
||||
} else if (batteryLevel >= 40) {
|
||||
return Icons.battery_3_bar;
|
||||
} else if (batteryLevel >= 20) {
|
||||
return Icons.battery_2_bar;
|
||||
} else {
|
||||
return Icons.battery_alert;
|
||||
}
|
||||
}
|
||||
|
||||
Color _getBatteryColor(int batteryLevel) {
|
||||
if (batteryLevel >= 80) {
|
||||
return Colors.green;
|
||||
} else if (batteryLevel >= 40) {
|
||||
return Colors.yellowAccent;
|
||||
} else {
|
||||
return Colors.red;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user