mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2026-10-25 18:47:56 +00:00
sos_device
This commit is contained in:
@@ -0,0 +1,259 @@
|
||||
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/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_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/services/api/devices_api.dart';
|
||||
import 'package:syncrow_app/services/api/spaces_api.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<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(waterContactState: '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;
|
||||
}
|
||||
}
|
||||
|
||||
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: 'sossensor_state',
|
||||
);
|
||||
recordGroups = response;
|
||||
emit(UpdateState(sensor: deviceStatus));
|
||||
} on DioException catch (e) {
|
||||
final errorData = e.response!.data;
|
||||
String errorMessage = errorData['message'];
|
||||
emit(SosFailedState(errorMessage: e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
// _listenToChanges() {
|
||||
// try {
|
||||
// DatabaseReference ref =
|
||||
// FirebaseDatabase.instance.ref('device-status/$WLId');
|
||||
// Stream<DatabaseEvent> stream = ref.onValue;
|
||||
|
||||
// stream.listen((DatabaseEvent event) async {
|
||||
// if (_timer != null) {
|
||||
// await Future.delayed(const Duration(seconds: 2));
|
||||
// }
|
||||
// Map<dynamic, dynamic> usersMap =
|
||||
// event.snapshot.value as Map<dynamic, dynamic>;
|
||||
// List<StatusModel> statusList = [];
|
||||
|
||||
// usersMap['status'].forEach((element) {
|
||||
// statusList.add(StatusModel(code: element['code'], value: true));
|
||||
// });
|
||||
|
||||
// deviceStatus = WaterLeakModel.fromJson(statusList);
|
||||
// if (!isClosed) {
|
||||
// add(
|
||||
// WaterLeakSwitch(switchD: deviceStatus.waterContactState),
|
||||
// );
|
||||
// }
|
||||
// });
|
||||
// } catch (_) {}
|
||||
// }
|
||||
|
||||
// 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 _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) {
|
||||
print('Save button clicked with selected option: $_selectedOption');
|
||||
_hasSelectionChanged = false;
|
||||
emit(SaveSelectionSuccessState());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_app/features/app_layout/model/space_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 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 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 {
|
||||
final String selectedOption;
|
||||
SelectOptionEvent({required this.selectedOption});
|
||||
}
|
||||
|
||||
class SaveSelectionEvent extends SosEvent {}
|
||||
@@ -0,0 +1,87 @@
|
||||
import 'package:equatable/equatable.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 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 => [];
|
||||
}
|
||||
Reference in New Issue
Block a user