mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-16 18:16:34 +00:00
Compare commits
51 Commits
SP-1275-FE
...
Fix-Factor
Author | SHA1 | Date | |
---|---|---|---|
72ae3b1727 | |||
e0be44a507 | |||
d4a7dd5854 | |||
50eb890d18 | |||
9eefd522b7 | |||
4989a0e95c | |||
3c6b9f9ef4 | |||
86b8771694 | |||
ea1d3d18c8 | |||
1bfab8cc76 | |||
7dcaa20da1 | |||
616adccfdd | |||
abf6555485 | |||
be0533645e | |||
254e03e3c7 | |||
db1f29e2b2 | |||
dba89027e3 | |||
6bea4c2f4a | |||
e2ec986bb9 | |||
ceb1e1d23a | |||
ee12980b47 | |||
4849bb41ba | |||
ebcd89d2a5 | |||
a7bdbfe3ec | |||
db84a9aa5e | |||
1493e35f6a | |||
f19cc616be | |||
06383018b9 | |||
9e3a78f6b7 | |||
a27b2e758c | |||
1023170788 | |||
140f4ff5e2 | |||
cbaeecc968 | |||
2a95720cb0 | |||
4fae2d6be0 | |||
5b84076572 | |||
9bf37243a6 | |||
acad0e8c9c | |||
79f5ef7871 | |||
6493f02bcc | |||
c7c8898763 | |||
62ee9a72d6 | |||
55695ca5db | |||
c2f5a8df10 | |||
cd9821679e | |||
bfd3d4542e | |||
35a99ccda7 | |||
978934399e | |||
bc32fe7941 | |||
cb6d50d367 | |||
97eb1c152b |
@ -25,7 +25,7 @@ jobs:
|
||||
- name: Set up Flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
flutter-version: '3.22.2' # Specify the Flutter version you want to use
|
||||
flutter-version: '3.27.3' # Specify the Flutter version you want to use
|
||||
|
||||
- name: Install dependencies
|
||||
run: flutter pub get
|
||||
|
@ -25,7 +25,7 @@ jobs:
|
||||
- name: Set up Flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
flutter-version: '3.22.2' # Specify the Flutter version you want to use
|
||||
flutter-version: '3.27.3' # Specify the Flutter version you want to use
|
||||
|
||||
- name: Install dependencies
|
||||
run: flutter pub get
|
||||
|
4
assets/icons/device_tag_ic.svg
Normal file
4
assets/icons/device_tag_ic.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="8" height="9" viewBox="0 0 8 9" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.13918 0.5H4.10294C4.0408 0.5 3.98117 0.524721 3.93722 0.568668L0.251783 4.25398C-0.0839278 4.58982 -0.0839278 5.13617 0.251783 5.47188L3.02848 8.24852C3.1906 8.41064 3.40686 8.49994 3.63734 8.5H3.6374C3.86794 8.5 4.0842 8.41064 4.24638 8.24846L7.9317 4.56308C7.97565 4.51914 8.00037 4.4595 8.00037 4.39736L8.00043 1.36113C8.00037 0.886312 7.61399 0.5 7.13918 0.5ZM7.53159 4.30031L3.91488 7.91702C3.84127 7.9907 3.74269 8.03122 3.6374 8.03122C3.53205 8.03122 3.43353 7.9907 3.35992 7.91708L0.583222 5.14045C0.43026 4.98748 0.43026 4.73845 0.583222 4.58542L4.19999 0.968775H7.13918C7.35556 0.968775 7.53165 1.14481 7.53165 1.36119L7.53159 4.30031Z" fill="#999999"/>
|
||||
<path d="M5.93455 1.8291C5.73782 1.8291 5.55288 1.90577 5.41377 2.04487C5.27466 2.18392 5.19806 2.36886 5.19806 2.56559C5.19806 2.76232 5.27466 2.94726 5.41377 3.08637C5.55288 3.22548 5.73782 3.30208 5.93455 3.30208C6.13121 3.30208 6.31616 3.22548 6.45527 3.08637C6.59437 2.94726 6.67098 2.76232 6.67098 2.56559C6.67098 2.36886 6.59437 2.18392 6.45533 2.04487C6.31622 1.90577 6.13128 1.8291 5.93455 1.8291ZM6.12383 2.75487C6.07329 2.80547 6.00602 2.83331 5.93455 2.83331C5.86301 2.83331 5.79581 2.80547 5.74527 2.75487C5.69467 2.70433 5.66683 2.63707 5.66683 2.56559C5.66683 2.49412 5.69467 2.42685 5.74527 2.37631C5.79581 2.32571 5.86307 2.29788 5.93455 2.29788C6.00602 2.29788 6.07323 2.32571 6.12383 2.37631C6.17443 2.42685 6.20226 2.49412 6.20226 2.56559C6.20226 2.63707 6.17437 2.70433 6.12383 2.75487Z" fill="#999999"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
@ -201,20 +201,17 @@ class ForgetPasswordWebPage extends StatelessWidget {
|
||||
!state.isButtonEnabled &&
|
||||
state.remainingTime != 1
|
||||
? null
|
||||
: () {
|
||||
:
|
||||
() {
|
||||
if (forgetBloc
|
||||
.forgetEmailKey.currentState!
|
||||
.validate() ||
|
||||
forgetBloc
|
||||
.forgetRegionKey.currentState!
|
||||
.forgetEmailKey
|
||||
.currentState!
|
||||
.validate()) {
|
||||
if (forgetBloc
|
||||
.forgetRegionKey.currentState!
|
||||
.validate()) {
|
||||
forgetBloc.add(StartTimerEvent());
|
||||
}
|
||||
forgetBloc.add(
|
||||
StartTimerEvent());
|
||||
}
|
||||
},
|
||||
|
||||
child: Text(
|
||||
'Get Code ${state is TimerState && !state.isButtonEnabled && state.remainingTime != 1 ? "(${forgetBloc.formattedTime(state.remainingTime)}) " : ""}',
|
||||
style: TextStyle(
|
||||
|
@ -13,6 +13,7 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||
late AcStatusModel deviceStatus;
|
||||
final String deviceId;
|
||||
Timer? _timer;
|
||||
Timer? _countdownTimer;
|
||||
|
||||
AcBloc({required this.deviceId}) : super(AcsInitialState()) {
|
||||
on<AcFetchDeviceStatusEvent>(_onFetchAcStatus);
|
||||
@ -21,7 +22,16 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||
on<AcBatchControlEvent>(_onAcBatchControl);
|
||||
on<AcFactoryResetEvent>(_onFactoryReset);
|
||||
on<AcStatusUpdated>(_onAcStatusUpdated);
|
||||
on<OnClose>(_onClose);
|
||||
on<IncreaseTimeEvent>(_handleIncreaseTime);
|
||||
on<DecreaseTimeEvent>(_handleDecreaseTime);
|
||||
on<UpdateTimerEvent>(_handleUpdateTimer);
|
||||
on<ToggleScheduleEvent>(_handleToggleTimer);
|
||||
on<ApiCountdownValueEvent>(_handleApiCountdownValue);
|
||||
}
|
||||
bool timerActive = false;
|
||||
int scheduledHours = 0;
|
||||
int scheduledMinutes = 0;
|
||||
|
||||
FutureOr<void> _onFetchAcStatus(
|
||||
AcFetchDeviceStatusEvent event, Emitter<AcsState> emit) async {
|
||||
@ -30,8 +40,23 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||
final status =
|
||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||
deviceStatus = AcStatusModel.fromJson(event.deviceId, status.status);
|
||||
if (deviceStatus.countdown1 != 0) {
|
||||
// Convert API value to minutes
|
||||
final totalMinutes = deviceStatus.countdown1 * 6;
|
||||
scheduledHours = totalMinutes ~/ 60;
|
||||
scheduledMinutes = totalMinutes % 60;
|
||||
timerActive = true;
|
||||
_startCountdownTimer(emit);
|
||||
}
|
||||
|
||||
emit(ACStatusLoaded(
|
||||
status: deviceStatus,
|
||||
scheduledHours: scheduledHours,
|
||||
scheduledMinutes: scheduledMinutes,
|
||||
isTimerActive: timerActive,
|
||||
));
|
||||
|
||||
_listenToChanges(event.deviceId);
|
||||
emit(ACStatusLoaded(deviceStatus));
|
||||
} catch (e) {
|
||||
emit(AcsFailedState(error: e.toString()));
|
||||
}
|
||||
@ -70,31 +95,16 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||
|
||||
void _onAcStatusUpdated(AcStatusUpdated event, Emitter<AcsState> emit) {
|
||||
deviceStatus = event.deviceStatus;
|
||||
emit(ACStatusLoaded(deviceStatus));
|
||||
emit(ACStatusLoaded(status: deviceStatus));
|
||||
}
|
||||
|
||||
// Future<void> testFirebaseConnection() async {
|
||||
// // Reference to a test node in your database
|
||||
// final testRef = FirebaseDatabase.instance.ref("test");
|
||||
|
||||
// // Write a test value
|
||||
// await testRef.set("Hello, Firebase!");
|
||||
|
||||
// // Listen for changes on the test node
|
||||
// testRef.onValue.listen((DatabaseEvent event) {
|
||||
// final data = event.snapshot.value;
|
||||
// print("Data from Firebase: $data");
|
||||
// // If you see "Hello, Firebase!" printed in your console, it means the connection works.
|
||||
// });
|
||||
// }
|
||||
|
||||
FutureOr<void> _onAcControl(
|
||||
AcControlEvent event, Emitter<AcsState> emit) async {
|
||||
final oldValue = _getValueByCode(event.code);
|
||||
|
||||
_updateLocalValue(event.code, event.value, emit);
|
||||
|
||||
emit(ACStatusLoaded(deviceStatus));
|
||||
emit(ACStatusLoaded(status: deviceStatus));
|
||||
|
||||
await _runDebounce(
|
||||
isBatch: false,
|
||||
@ -151,7 +161,7 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||
void _revertValueAndEmit(
|
||||
String deviceId, String code, dynamic oldValue, Emitter<AcsState> emit) {
|
||||
_updateLocalValue(code, oldValue, emit);
|
||||
emit(ACStatusLoaded(deviceStatus));
|
||||
emit(ACStatusLoaded(status: deviceStatus));
|
||||
}
|
||||
|
||||
void _updateLocalValue(String code, dynamic value, Emitter<AcsState> emit) {
|
||||
@ -184,11 +194,16 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||
if (value is bool) {
|
||||
deviceStatus = deviceStatus.copyWith(childLock: value);
|
||||
}
|
||||
|
||||
case 'countdown_time':
|
||||
if (value is int) {
|
||||
deviceStatus = deviceStatus.copyWith(countdown1: value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
emit(ACStatusLoaded(deviceStatus));
|
||||
emit(ACStatusLoaded(status: deviceStatus));
|
||||
}
|
||||
|
||||
dynamic _getValueByCode(String code) {
|
||||
@ -203,6 +218,8 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||
return deviceStatus.fanSpeedsString;
|
||||
case 'child_lock':
|
||||
return deviceStatus.childLock;
|
||||
case 'countdown_time':
|
||||
return deviceStatus.countdown1;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@ -216,7 +233,7 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||
await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
||||
deviceStatus =
|
||||
AcStatusModel.fromJson(event.devicesIds.first, status.status);
|
||||
emit(ACStatusLoaded(deviceStatus));
|
||||
emit(ACStatusLoaded(status: deviceStatus));
|
||||
} catch (e) {
|
||||
emit(AcsFailedState(error: e.toString()));
|
||||
}
|
||||
@ -228,7 +245,7 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||
|
||||
_updateLocalValue(event.code, event.value, emit);
|
||||
|
||||
emit(ACStatusLoaded(deviceStatus));
|
||||
emit(ACStatusLoaded(status: deviceStatus));
|
||||
|
||||
await _runDebounce(
|
||||
isBatch: true,
|
||||
@ -257,4 +274,144 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
||||
emit(AcsFailedState(error: e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
void _onClose(OnClose event, Emitter<AcsState> emit) {
|
||||
_countdownTimer?.cancel();
|
||||
_timer?.cancel();
|
||||
}
|
||||
|
||||
void _handleIncreaseTime(IncreaseTimeEvent event, Emitter<AcsState> emit) {
|
||||
if (state is! ACStatusLoaded) return;
|
||||
final currentState = state as ACStatusLoaded;
|
||||
int newHours = scheduledHours;
|
||||
int newMinutes = scheduledMinutes + 30;
|
||||
newHours += newMinutes ~/ 60;
|
||||
newMinutes = newMinutes % 60;
|
||||
if (newHours > 23) {
|
||||
newHours = 23;
|
||||
newMinutes = 59;
|
||||
}
|
||||
scheduledHours = newHours;
|
||||
scheduledMinutes = newMinutes;
|
||||
|
||||
emit(currentState.copyWith(
|
||||
scheduledHours: scheduledHours,
|
||||
scheduledMinutes: scheduledMinutes,
|
||||
));
|
||||
}
|
||||
|
||||
void _handleDecreaseTime(DecreaseTimeEvent event, Emitter<AcsState> emit) {
|
||||
if (state is! ACStatusLoaded) return;
|
||||
final currentState = state as ACStatusLoaded;
|
||||
int totalMinutes = (scheduledHours * 60) + scheduledMinutes;
|
||||
totalMinutes = (totalMinutes - 30).clamp(0, 1440);
|
||||
scheduledHours = totalMinutes ~/ 60;
|
||||
scheduledMinutes = totalMinutes % 60;
|
||||
|
||||
emit(currentState.copyWith(
|
||||
scheduledHours: scheduledHours,
|
||||
scheduledMinutes: scheduledMinutes,
|
||||
));
|
||||
}
|
||||
|
||||
Future<void> _handleToggleTimer(
|
||||
ToggleScheduleEvent event, Emitter<AcsState> emit) async {
|
||||
if (state is! ACStatusLoaded) return;
|
||||
final currentState = state as ACStatusLoaded;
|
||||
|
||||
timerActive = !timerActive;
|
||||
|
||||
if (timerActive) {
|
||||
final totalMinutes = scheduledHours * 60 + scheduledMinutes;
|
||||
if (totalMinutes <= 0) {
|
||||
timerActive = false;
|
||||
emit(currentState.copyWith(isTimerActive: timerActive));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final scaledValue = totalMinutes ~/ 6;
|
||||
await _runDebounce(
|
||||
isBatch: false,
|
||||
deviceId: deviceId,
|
||||
code: 'countdown_time',
|
||||
value: scaledValue,
|
||||
oldValue: scaledValue,
|
||||
emit: emit,
|
||||
);
|
||||
_startCountdownTimer(emit);
|
||||
emit(currentState.copyWith(isTimerActive: timerActive));
|
||||
} catch (e) {
|
||||
timerActive = false;
|
||||
emit(AcsFailedState(error: e.toString()));
|
||||
}
|
||||
} else {
|
||||
await _runDebounce(
|
||||
isBatch: false,
|
||||
deviceId: deviceId,
|
||||
code: 'countdown_time',
|
||||
value: 0,
|
||||
oldValue: 0,
|
||||
emit: emit,
|
||||
);
|
||||
_countdownTimer?.cancel();
|
||||
scheduledHours = 0;
|
||||
scheduledMinutes = 0;
|
||||
emit(currentState.copyWith(
|
||||
isTimerActive: timerActive,
|
||||
scheduledHours: 0,
|
||||
scheduledMinutes: 0,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void _startCountdownTimer(Emitter<AcsState> emit) {
|
||||
_countdownTimer?.cancel();
|
||||
int totalSeconds = (scheduledHours * 3600) + (scheduledMinutes * 60);
|
||||
|
||||
_countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||
if (totalSeconds > 0) {
|
||||
totalSeconds--;
|
||||
scheduledHours = totalSeconds ~/ 3600;
|
||||
scheduledMinutes = (totalSeconds % 3600) ~/ 60;
|
||||
add(UpdateTimerEvent());
|
||||
} else {
|
||||
_countdownTimer?.cancel();
|
||||
timerActive = false;
|
||||
scheduledHours = 0;
|
||||
scheduledMinutes = 0;
|
||||
add(TimerCompletedEvent());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _handleUpdateTimer(UpdateTimerEvent event, Emitter<AcsState> emit) {
|
||||
if (state is ACStatusLoaded) {
|
||||
final currentState = state as ACStatusLoaded;
|
||||
emit(currentState.copyWith(
|
||||
scheduledHours: scheduledHours,
|
||||
scheduledMinutes: scheduledMinutes,
|
||||
isTimerActive: timerActive,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void _handleApiCountdownValue(
|
||||
ApiCountdownValueEvent event, Emitter<AcsState> emit) {
|
||||
if (state is ACStatusLoaded) {
|
||||
final totalMinutes = event.apiValue * 6;
|
||||
final scheduledHours = totalMinutes ~/ 60;
|
||||
scheduledMinutes = totalMinutes % 60;
|
||||
_startCountdownTimer(
|
||||
emit,
|
||||
);
|
||||
add(UpdateTimerEvent());
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
add(OnClose());
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ sealed class AcsEvent extends Equatable {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class AcUpdated extends AcsEvent {}
|
||||
|
||||
class AcFetchDeviceStatusEvent extends AcsEvent {
|
||||
@ -18,10 +19,12 @@ class AcFetchDeviceStatusEvent extends AcsEvent {
|
||||
@override
|
||||
List<Object> get props => [deviceId];
|
||||
}
|
||||
|
||||
class AcStatusUpdated extends AcsEvent {
|
||||
final AcStatusModel deviceStatus;
|
||||
AcStatusUpdated(this.deviceStatus);
|
||||
}
|
||||
|
||||
class AcFetchBatchStatusEvent extends AcsEvent {
|
||||
final List<String> devicesIds;
|
||||
|
||||
@ -73,3 +76,30 @@ class AcFactoryResetEvent extends AcsEvent {
|
||||
@override
|
||||
List<Object> get props => [deviceId, factoryResetModel];
|
||||
}
|
||||
|
||||
|
||||
|
||||
class OnClose extends AcsEvent {}
|
||||
|
||||
class IncreaseTimeEvent extends AcsEvent {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class DecreaseTimeEvent extends AcsEvent {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class ToggleScheduleEvent extends AcsEvent {}
|
||||
|
||||
class TimerCompletedEvent extends AcsEvent {}
|
||||
|
||||
class UpdateTimerEvent extends AcsEvent {
|
||||
}
|
||||
|
||||
class ApiCountdownValueEvent extends AcsEvent {
|
||||
final int apiValue;
|
||||
|
||||
const ApiCountdownValueEvent(this.apiValue);
|
||||
}
|
||||
|
@ -2,8 +2,9 @@ import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/ac/model/ac_model.dart';
|
||||
|
||||
abstract class AcsState extends Equatable {
|
||||
const AcsState();
|
||||
final bool isTimerActive;
|
||||
|
||||
const AcsState({this.isTimerActive = false});
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
@ -15,8 +16,30 @@ class AcsLoadingState extends AcsState {}
|
||||
class ACStatusLoaded extends AcsState {
|
||||
final AcStatusModel status;
|
||||
final DateTime timestamp;
|
||||
final int scheduledHours;
|
||||
final int scheduledMinutes;
|
||||
final bool isTimerActive;
|
||||
|
||||
ACStatusLoaded(this.status) : timestamp = DateTime.now();
|
||||
ACStatusLoaded({
|
||||
required this.status,
|
||||
this.scheduledHours = 0,
|
||||
this.scheduledMinutes = 0,
|
||||
this.isTimerActive = false,
|
||||
}) : timestamp = DateTime.now();
|
||||
ACStatusLoaded copyWith({
|
||||
AcStatusModel? status,
|
||||
int? scheduledHours,
|
||||
int? scheduledMinutes,
|
||||
bool? isTimerActive,
|
||||
int? remainingTime,
|
||||
}) {
|
||||
return ACStatusLoaded(
|
||||
status: status ?? this.status,
|
||||
scheduledHours: scheduledHours ?? this.scheduledHours,
|
||||
scheduledMinutes: scheduledMinutes ?? this.scheduledMinutes,
|
||||
isTimerActive: isTimerActive ?? this.isTimerActive,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object> get props => [status, timestamp];
|
||||
@ -40,3 +63,14 @@ class AcsFailedState extends AcsState {
|
||||
@override
|
||||
List<Object> get props => [error];
|
||||
}
|
||||
|
||||
class TimerRunInProgress extends AcsState {
|
||||
final int remainingTime;
|
||||
|
||||
const TimerRunInProgress(this.remainingTime);
|
||||
|
||||
@override
|
||||
List<Object> get props => [remainingTime];
|
||||
}
|
||||
|
||||
|
||||
|
@ -11,6 +11,7 @@ class AcStatusModel {
|
||||
final bool childLock;
|
||||
final TempModes acMode;
|
||||
final FanSpeeds acFanSpeed;
|
||||
final int countdown1;
|
||||
|
||||
AcStatusModel({
|
||||
required this.uuid,
|
||||
@ -18,6 +19,7 @@ class AcStatusModel {
|
||||
required this.modeString,
|
||||
required this.tempSet,
|
||||
required this.currentTemp,
|
||||
required this.countdown1,
|
||||
required this.fanSpeedsString,
|
||||
required this.childLock,
|
||||
}) : acMode = getACMode(modeString),
|
||||
@ -30,6 +32,7 @@ class AcStatusModel {
|
||||
late int currentTemp;
|
||||
late String fanSpeeds;
|
||||
late bool childLock;
|
||||
late int _countdown1 = 0;
|
||||
|
||||
for (var status in jsonList) {
|
||||
switch (status.code) {
|
||||
@ -51,6 +54,9 @@ class AcStatusModel {
|
||||
case 'child_lock':
|
||||
childLock = status.value ?? false;
|
||||
break;
|
||||
case 'countdown_time':
|
||||
_countdown1 = status.value ?? 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,6 +68,7 @@ class AcStatusModel {
|
||||
currentTemp: currentTemp,
|
||||
fanSpeedsString: fanSpeeds,
|
||||
childLock: childLock,
|
||||
countdown1: _countdown1,
|
||||
);
|
||||
}
|
||||
|
||||
@ -73,6 +80,7 @@ class AcStatusModel {
|
||||
int? currentTemp,
|
||||
String? fanSpeedsString,
|
||||
bool? childLock,
|
||||
int? countdown1,
|
||||
}) {
|
||||
return AcStatusModel(
|
||||
uuid: uuid ?? this.uuid,
|
||||
@ -82,6 +90,7 @@ class AcStatusModel {
|
||||
currentTemp: currentTemp ?? this.currentTemp,
|
||||
fanSpeedsString: fanSpeedsString ?? this.fanSpeedsString,
|
||||
childLock: childLock ?? this.childLock,
|
||||
countdown1: countdown1 ?? this.countdown1,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,6 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo
|
||||
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
|
||||
class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
||||
@ -23,11 +22,13 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
||||
final isExtraLarge = isExtraLargeScreenSize(context);
|
||||
final isLarge = isLargeScreenSize(context);
|
||||
final isMedium = isMediumScreenSize(context);
|
||||
|
||||
return BlocProvider(
|
||||
create: (context) => AcBloc(deviceId: device.uuid!)
|
||||
..add(AcFetchDeviceStatusEvent(device.uuid!)),
|
||||
child: BlocBuilder<AcBloc, AcsState>(
|
||||
builder: (context, state) {
|
||||
final acBloc = BlocProvider.of<AcBloc>(context);
|
||||
if (state is ACStatusLoaded) {
|
||||
return GridView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 50),
|
||||
@ -78,56 +79,101 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
||||
),
|
||||
ToggleWidget(
|
||||
label: '',
|
||||
labelWidget: Row(
|
||||
labelWidget: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
decoration: const ShapeDecoration(
|
||||
color: ColorsManager.primaryColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(30)),
|
||||
),
|
||||
),
|
||||
),
|
||||
Center(
|
||||
child: SizedBox(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
IconButton(
|
||||
padding: const EdgeInsets.all(0),
|
||||
onPressed: () {},
|
||||
icon: const Icon(
|
||||
Icons.remove,
|
||||
size: 28,
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
onPressed: () {
|
||||
if (acBloc.timerActive == false) {
|
||||
context
|
||||
.read<AcBloc>()
|
||||
.add(DecreaseTimeEvent());
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.remove,
|
||||
color: ColorsManager.greyColor),
|
||||
),
|
||||
Text(
|
||||
'06',
|
||||
style: context.textTheme.titleLarge!.copyWith(
|
||||
acBloc.scheduledHours
|
||||
.toString()
|
||||
.padLeft(2, '0'),
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleLarge!
|
||||
.copyWith(
|
||||
color: ColorsManager.dialogBlueTitle,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'h',
|
||||
style: context.textTheme.bodySmall!
|
||||
.copyWith(color: ColorsManager.blackColor),
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
color: ColorsManager.blackColor,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'30',
|
||||
style: context.textTheme.titleLarge!.copyWith(
|
||||
acBloc.scheduledMinutes
|
||||
.toString()
|
||||
.padLeft(2, '0'),
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleLarge!
|
||||
.copyWith(
|
||||
color: ColorsManager.dialogBlueTitle,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Text('m',
|
||||
style: context.textTheme.bodySmall!
|
||||
.copyWith(color: ColorsManager.blackColor)),
|
||||
Text(
|
||||
'm',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
color: ColorsManager.blackColor,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
padding: const EdgeInsets.all(0),
|
||||
onPressed: () {},
|
||||
icon: const Icon(
|
||||
Icons.add,
|
||||
size: 28,
|
||||
color: ColorsManager.greyColor,
|
||||
onPressed: () {
|
||||
if (acBloc.timerActive == false) {
|
||||
context
|
||||
.read<AcBloc>()
|
||||
.add(IncreaseTimeEvent());
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.add,
|
||||
color: ColorsManager.greyColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
value: false,
|
||||
value: acBloc.timerActive,
|
||||
code: 'ac_schedule',
|
||||
deviceId: device.uuid!,
|
||||
icon: Assets.acSchedule,
|
||||
onChange: (value) {},
|
||||
onChange: (value) {
|
||||
context.read<AcBloc>().add(ToggleScheduleEvent());
|
||||
},
|
||||
),
|
||||
ToggleWidget(
|
||||
deviceId: device.uuid!,
|
||||
|
@ -0,0 +1,18 @@
|
||||
class DeviceSubSpace {
|
||||
String? id;
|
||||
String? createdAt;
|
||||
String? updatedAt;
|
||||
String? subspaceName;
|
||||
bool? disabled;
|
||||
|
||||
DeviceSubSpace({this.id, this.createdAt, this.updatedAt, this.subspaceName, this.disabled});
|
||||
|
||||
DeviceSubSpace.fromJson(Map<String, dynamic> json) {
|
||||
id = json['uuid']?.toString() ?? '';
|
||||
createdAt = json['createdAt']?.toString() ?? '';
|
||||
updatedAt = json['updatedAt']?.toString() ?? '';
|
||||
subspaceName = json['subspaceName']?.toString() ?? '';
|
||||
subspaceName = json['subspaceName']?.toString() ?? '';
|
||||
disabled = json['disabled'] ?? false;
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
class DeviceTagModel {
|
||||
String? id;
|
||||
String? createdAt;
|
||||
String? updatedAt;
|
||||
String? name;
|
||||
|
||||
DeviceTagModel({
|
||||
this.id,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
this.name,
|
||||
});
|
||||
|
||||
DeviceTagModel.fromJson(Map<String, dynamic> json) {
|
||||
id = json['uuid']?.toString() ?? '';
|
||||
createdAt = json['createdAt']?.toString() ?? '';
|
||||
updatedAt = json['updatedAt']?.toString() ?? '';
|
||||
name = json['name']?.toString() ?? '';
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_community.model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_space_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_sub_space.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_subspace.model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_tag_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/room.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/unit.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/ac/ac_function.dart';
|
||||
@ -79,9 +81,11 @@ class AllDevicesModel {
|
||||
int? batteryLevel;
|
||||
String? productName;
|
||||
List<DeviceSpaceModel>? spaces;
|
||||
List<DeviceTagModel>? deviceTags;
|
||||
DeviceSubSpace? deviceSubSpace;
|
||||
|
||||
AllDevicesModel({
|
||||
this.room,
|
||||
AllDevicesModel(
|
||||
{this.room,
|
||||
this.subspace,
|
||||
this.unit,
|
||||
this.community,
|
||||
@ -110,7 +114,8 @@ class AllDevicesModel {
|
||||
this.batteryLevel,
|
||||
this.productName,
|
||||
this.spaces,
|
||||
});
|
||||
this.deviceTags,
|
||||
this.deviceSubSpace});
|
||||
|
||||
AllDevicesModel.fromJson(Map<String, dynamic> json) {
|
||||
room = (json['room'] != null && (json['room'] is Map))
|
||||
@ -148,12 +153,15 @@ class AllDevicesModel {
|
||||
updateTime = int.tryParse(json['updateTime']?.toString() ?? '');
|
||||
uuid = json['uuid']?.toString();
|
||||
batteryLevel = int.tryParse(json['battery']?.toString() ?? '');
|
||||
|
||||
productName = json['productName']?.toString();
|
||||
deviceTags = json['deviceTag'] != null && json['deviceTag'] is List
|
||||
? (json['deviceTag'] as List).map((tag) => DeviceTagModel.fromJson(tag)).toList()
|
||||
: [];
|
||||
deviceSubSpace = json['subspace'] != null
|
||||
? DeviceSubSpace.fromJson(json['subspace'])
|
||||
: DeviceSubSpace(subspaceName: '');
|
||||
if (json['spaces'] != null && json['spaces'] is List) {
|
||||
spaces = (json['spaces'] as List)
|
||||
.map((space) => DeviceSpaceModel.fromJson(space))
|
||||
.toList();
|
||||
spaces = (json['spaces'] as List).map((space) => DeviceSpaceModel.fromJson(space)).toList();
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,8 +209,7 @@ SOS
|
||||
String tempIcon = '';
|
||||
if (type == DeviceType.LightBulb) {
|
||||
tempIcon = Assets.lightBulb;
|
||||
} else if (type == DeviceType.CeilingSensor ||
|
||||
type == DeviceType.WallSensor) {
|
||||
} else if (type == DeviceType.CeilingSensor || type == DeviceType.WallSensor) {
|
||||
tempIcon = Assets.sensors;
|
||||
} else if (type == DeviceType.AC) {
|
||||
tempIcon = Assets.ac;
|
||||
@ -232,8 +239,6 @@ SOS
|
||||
// tempIcon = Assets.gang3touch;
|
||||
} else if (type == DeviceType.WaterLeak) {
|
||||
tempIcon = Assets.waterLeakNormal;
|
||||
} else if (type == DeviceType.WaterLeak) {
|
||||
tempIcon = Assets.waterLeakNormal;
|
||||
} else {
|
||||
tempIcon = Assets.logoHorizontal;
|
||||
}
|
||||
@ -249,76 +254,51 @@ SOS
|
||||
switch (productType) {
|
||||
case 'AC':
|
||||
return [
|
||||
SwitchFunction(
|
||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
ModeFunction(
|
||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
TempSetFunction(
|
||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
CurrentTempFunction(
|
||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
|
||||
LevelFunction(
|
||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
ChildLockFunction(
|
||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
SwitchFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
ModeFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
TempSetFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
CurrentTempFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
|
||||
LevelFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
ChildLockFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
];
|
||||
|
||||
case '1G':
|
||||
return [
|
||||
OneGangSwitchFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
OneGangCountdownFunction(
|
||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
OneGangCountdownFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
];
|
||||
|
||||
case '2G':
|
||||
return [
|
||||
TwoGangSwitch1Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
TwoGangSwitch2Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
TwoGangCountdown1Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
TwoGangCountdown2Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
TwoGangCountdown1Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
TwoGangCountdown2Function(deviceId: uuid ?? '', deviceName: name ?? ''),
|
||||
];
|
||||
|
||||
case '3G':
|
||||
return [
|
||||
ThreeGangSwitch1Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
ThreeGangSwitch2Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
ThreeGangSwitch3Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
ThreeGangCountdown1Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
ThreeGangCountdown2Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
ThreeGangCountdown3Function(
|
||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
ThreeGangSwitch1Function(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
ThreeGangSwitch2Function(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
ThreeGangSwitch3Function(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
ThreeGangCountdown1Function(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
ThreeGangCountdown2Function(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
ThreeGangCountdown3Function(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
];
|
||||
case 'WPS':
|
||||
return [
|
||||
//IF Functions
|
||||
PresenceStateFunction(
|
||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
|
||||
CurrentDistanceFunction(
|
||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
|
||||
IlluminanceValueFunction(
|
||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
|
||||
PresenceTimeFunction(
|
||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
|
||||
PresenceStateFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
|
||||
CurrentDistanceFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
|
||||
IlluminanceValueFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
|
||||
PresenceTimeFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
|
||||
|
||||
//THEN Functions
|
||||
FarDetectionFunction(
|
||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
|
||||
MotionSensitivityFunction(
|
||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
|
||||
MotionLessSensitivityFunction(
|
||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
|
||||
IndicatorFunction(
|
||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
NoOneTimeFunction(
|
||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
|
||||
|
||||
FarDetectionFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
|
||||
MotionSensitivityFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
|
||||
MotionLessSensitivityFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
|
||||
IndicatorFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||
NoOneTimeFunction(deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
|
||||
];
|
||||
case 'GW':
|
||||
return [
|
||||
|
@ -19,6 +19,7 @@ class FactoryResetModel {
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'devicesUuid': devicesUuid,
|
||||
'operationType': operationType,
|
||||
};
|
||||
}
|
||||
|
||||
@ -33,6 +34,7 @@ class FactoryResetModel {
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'devicesUuid': devicesUuid,
|
||||
'operationType': operationType,
|
||||
};
|
||||
}
|
||||
|
||||
@ -56,3 +58,4 @@ class FactoryResetModel {
|
||||
@override
|
||||
int get hashCode => devicesUuid.hashCode;
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,6 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_re
|
||||
import 'package:syncrow_web/pages/device_managment/main_door_sensor/bloc/main_door_sensor_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/main_door_sensor/bloc/main_door_sensor_event.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart';
|
||||
// import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart';
|
||||
|
||||
class MainDoorSensorBatchView extends StatelessWidget {
|
||||
const MainDoorSensorBatchView({super.key, required this.devicesIds});
|
||||
@ -13,26 +12,19 @@ class MainDoorSensorBatchView extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => MainDoorSensorBloc(),
|
||||
child: Builder(
|
||||
builder: (innerContext) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// SizedBox(
|
||||
// width: 170,
|
||||
// height: 140,
|
||||
// child: FirmwareUpdateWidget(
|
||||
// deviceId: devicesIds.first,
|
||||
// version: 12,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(
|
||||
// width: 12,
|
||||
// ),
|
||||
SizedBox(
|
||||
width: 170,
|
||||
height: 140,
|
||||
child: FactoryResetWidget(
|
||||
callFactoryReset: () {
|
||||
BlocProvider.of<MainDoorSensorBloc>(context).add(
|
||||
BlocProvider.of<MainDoorSensorBloc>(innerContext).add(
|
||||
MainDoorSensorFactoryReset(
|
||||
deviceId: devicesIds.first,
|
||||
factoryReset: FactoryResetModel(devicesUuid: devicesIds),
|
||||
@ -43,5 +35,8 @@ class MainDoorSensorBatchView extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -62,9 +62,6 @@ class ToggleWidget extends StatelessWidget {
|
||||
)),
|
||||
if (showToggle)
|
||||
Container(
|
||||
height: 20,
|
||||
width: 35,
|
||||
padding: const EdgeInsets.only(right: 16, top: 10),
|
||||
child: CupertinoSwitch(
|
||||
value: value,
|
||||
activeColor: ColorsManager.dialogBlueTitle,
|
||||
|
@ -13,7 +13,8 @@ import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_la
|
||||
|
||||
import '../models/sos_status_model.dart';
|
||||
|
||||
class SosDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
||||
class SosDeviceControlsView extends StatelessWidget
|
||||
with HelperResponsiveLayout {
|
||||
const SosDeviceControlsView({
|
||||
super.key,
|
||||
required this.device,
|
||||
@ -24,7 +25,8 @@ class SosDeviceControlsView extends StatelessWidget with HelperResponsiveLayout
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => SosDeviceBloc()..add(GetDeviceStatus(device.uuid!)),
|
||||
create: (context) =>
|
||||
SosDeviceBloc()..add(GetDeviceStatus(device.uuid!)),
|
||||
child: BlocBuilder<SosDeviceBloc, SosDeviceState>(
|
||||
builder: (context, state) {
|
||||
if (state is SosDeviceLoadingState) {
|
||||
@ -63,7 +65,8 @@ class SosDeviceControlsView extends StatelessWidget with HelperResponsiveLayout
|
||||
));
|
||||
}
|
||||
|
||||
Widget _buildStatusControls(BuildContext context, SosStatusModel deviceStatus) {
|
||||
Widget _buildStatusControls(
|
||||
BuildContext context, SosStatusModel deviceStatus) {
|
||||
final isExtraLarge = isExtraLargeScreenSize(context);
|
||||
final isLarge = isLargeScreenSize(context);
|
||||
final isMedium = isMediumScreenSize(context);
|
||||
@ -85,7 +88,7 @@ class SosDeviceControlsView extends StatelessWidget with HelperResponsiveLayout
|
||||
IconNameStatusContainer(
|
||||
isFullIcon: false,
|
||||
name: deviceStatus.sosStatus == 'sos' ? 'SOS' : 'Normal',
|
||||
icon: deviceStatus.sosStatus == 'sos' ? Assets.sos : Assets.sosNormal,
|
||||
icon: deviceStatus.sosStatus == 'sos' ? Assets.sosNormal : Assets.sos,
|
||||
onTap: () {},
|
||||
status: false,
|
||||
textColor: ColorsManager.blackColor,
|
||||
|
@ -30,6 +30,7 @@ class FunctionBloc extends Bloc<FunctionBlocEvent, FunctionBlocState> {
|
||||
condition: event.functionData.condition ?? existingData.condition,
|
||||
);
|
||||
} else {
|
||||
functions.clear();
|
||||
functions.add(event.functionData);
|
||||
}
|
||||
|
||||
|
@ -64,8 +64,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
TriggerSwitchTabsEvent event,
|
||||
Emitter<RoutineState> emit,
|
||||
) {
|
||||
emit(state.copyWith(
|
||||
routineTab: event.isRoutineTab, createRoutineView: false));
|
||||
emit(state.copyWith(routineTab: event.isRoutineTab, createRoutineView: false));
|
||||
add(ResetRoutineState());
|
||||
if (event.isRoutineTab) {
|
||||
add(const LoadScenes());
|
||||
@ -91,8 +90,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
final updatedIfItems = List<Map<String, dynamic>>.from(state.ifItems);
|
||||
|
||||
// Find the index of the item in teh current itemsList
|
||||
int index = updatedIfItems.indexWhere(
|
||||
(map) => map['uniqueCustomId'] == event.item['uniqueCustomId']);
|
||||
int index =
|
||||
updatedIfItems.indexWhere((map) => map['uniqueCustomId'] == event.item['uniqueCustomId']);
|
||||
// Replace the map if the index is valid
|
||||
if (index != -1) {
|
||||
updatedIfItems[index] = event.item;
|
||||
@ -101,21 +100,18 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
|
||||
if (event.isTabToRun) {
|
||||
emit(state.copyWith(
|
||||
ifItems: updatedIfItems, isTabToRun: true, isAutomation: false));
|
||||
emit(state.copyWith(ifItems: updatedIfItems, isTabToRun: true, isAutomation: false));
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
ifItems: updatedIfItems, isTabToRun: false, isAutomation: true));
|
||||
emit(state.copyWith(ifItems: updatedIfItems, isTabToRun: false, isAutomation: true));
|
||||
}
|
||||
}
|
||||
|
||||
void _onAddToThenContainer(
|
||||
AddToThenContainer event, Emitter<RoutineState> emit) {
|
||||
void _onAddToThenContainer(AddToThenContainer event, Emitter<RoutineState> emit) {
|
||||
final currentItems = List<Map<String, dynamic>>.from(state.thenItems);
|
||||
|
||||
// Find the index of the item in teh current itemsList
|
||||
int index = currentItems.indexWhere(
|
||||
(map) => map['uniqueCustomId'] == event.item['uniqueCustomId']);
|
||||
int index =
|
||||
currentItems.indexWhere((map) => map['uniqueCustomId'] == event.item['uniqueCustomId']);
|
||||
// Replace the map if the index is valid
|
||||
if (index != -1) {
|
||||
currentItems[index] = event.item;
|
||||
@ -126,45 +122,42 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
emit(state.copyWith(thenItems: currentItems));
|
||||
}
|
||||
|
||||
void _onAddFunctionsToRoutine(
|
||||
AddFunctionToRoutine event, Emitter<RoutineState> emit) {
|
||||
void _onAddFunctionsToRoutine(AddFunctionToRoutine event, Emitter<RoutineState> emit) {
|
||||
try {
|
||||
if (event.functions.isEmpty) return;
|
||||
|
||||
List<DeviceFunctionData> selectedFunction =
|
||||
List<DeviceFunctionData>.from(event.functions);
|
||||
// List<DeviceFunctionData> selectedFunction = List<DeviceFunctionData>.from(event.functions);
|
||||
|
||||
Map<String, List<DeviceFunctionData>> currentSelectedFunctions =
|
||||
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
|
||||
if (currentSelectedFunctions.containsKey(event.uniqueCustomId)) {
|
||||
List<DeviceFunctionData> currentFunctions =
|
||||
List<DeviceFunctionData>.from(
|
||||
currentSelectedFunctions[event.uniqueCustomId] ?? []);
|
||||
|
||||
List<String> functionCode = [];
|
||||
for (int i = 0; i < selectedFunction.length; i++) {
|
||||
for (int j = 0; j < currentFunctions.length; j++) {
|
||||
if (selectedFunction[i].functionCode ==
|
||||
currentFunctions[j].functionCode) {
|
||||
currentFunctions[j] = selectedFunction[i];
|
||||
if (!functionCode.contains(currentFunctions[j].functionCode)) {
|
||||
functionCode.add(currentFunctions[j].functionCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (currentSelectedFunctions.containsKey(event.uniqueCustomId)) {
|
||||
// List<DeviceFunctionData> currentFunctions =
|
||||
// List<DeviceFunctionData>.from(currentSelectedFunctions[event.uniqueCustomId] ?? []);
|
||||
|
||||
for (int i = 0; i < functionCode.length; i++) {
|
||||
selectedFunction
|
||||
.removeWhere((code) => code.functionCode == functionCode[i]);
|
||||
}
|
||||
// List<String> functionCode = [];
|
||||
// for (int i = 0; i < selectedFunction.length; i++) {
|
||||
// for (int j = 0; j < currentFunctions.length; j++) {
|
||||
// if (selectedFunction[i].functionCode == currentFunctions[j].functionCode) {
|
||||
// currentFunctions[j] = selectedFunction[i];
|
||||
// if (!functionCode.contains(currentFunctions[j].functionCode)) {
|
||||
// functionCode.add(currentFunctions[j].functionCode);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
currentSelectedFunctions[event.uniqueCustomId] =
|
||||
List.from(currentFunctions)..addAll(selectedFunction);
|
||||
} else {
|
||||
currentSelectedFunctions[event.uniqueCustomId] =
|
||||
List.from(event.functions);
|
||||
}
|
||||
// for (int i = 0; i < functionCode.length; i++) {
|
||||
// selectedFunction.removeWhere((code) => code.functionCode == functionCode[i]);
|
||||
// }
|
||||
|
||||
// currentSelectedFunctions[event.uniqueCustomId] = List.from(currentFunctions)
|
||||
// ..addAll(selectedFunction);
|
||||
// } else {
|
||||
// currentSelectedFunctions[event.uniqueCustomId] = List.from(event.functions);
|
||||
// }
|
||||
|
||||
currentSelectedFunctions[event.uniqueCustomId] = List.from(event.functions);
|
||||
|
||||
emit(state.copyWith(selectedFunctions: currentSelectedFunctions));
|
||||
} catch (e) {
|
||||
@ -172,30 +165,24 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onLoadScenes(
|
||||
LoadScenes event, Emitter<RoutineState> emit) async {
|
||||
Future<void> _onLoadScenes(LoadScenes event, Emitter<RoutineState> emit) async {
|
||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||
List<ScenesModel> scenes = [];
|
||||
try {
|
||||
BuildContext context = NavigationService.navigatorKey.currentContext!;
|
||||
var createRoutineBloc = context.read<CreateRoutineBloc>();
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
if (createRoutineBloc.selectedSpaceId == '' &&
|
||||
createRoutineBloc.selectedCommunityId == '') {
|
||||
if (createRoutineBloc.selectedSpaceId == '' && createRoutineBloc.selectedCommunityId == '') {
|
||||
var spaceBloc = context.read<SpaceTreeBloc>();
|
||||
for (var communityId in spaceBloc.state.selectedCommunities) {
|
||||
List<String> spacesList =
|
||||
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
||||
List<String> spacesList = spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
||||
for (var spaceId in spacesList) {
|
||||
scenes.addAll(
|
||||
await SceneApi.getScenes(spaceId, communityId, projectUuid));
|
||||
scenes.addAll(await SceneApi.getScenes(spaceId, communityId, projectUuid));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
scenes.addAll(await SceneApi.getScenes(
|
||||
createRoutineBloc.selectedSpaceId,
|
||||
createRoutineBloc.selectedCommunityId,
|
||||
projectUuid));
|
||||
createRoutineBloc.selectedSpaceId, createRoutineBloc.selectedCommunityId, projectUuid));
|
||||
}
|
||||
|
||||
emit(state.copyWith(
|
||||
@ -212,8 +199,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onLoadAutomation(
|
||||
LoadAutomation event, Emitter<RoutineState> emit) async {
|
||||
Future<void> _onLoadAutomation(LoadAutomation event, Emitter<RoutineState> emit) async {
|
||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||
List<ScenesModel> automations = [];
|
||||
final projectId = await ProjectManager.getProjectUUID() ?? '';
|
||||
@ -221,23 +207,17 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
BuildContext context = NavigationService.navigatorKey.currentContext!;
|
||||
var createRoutineBloc = context.read<CreateRoutineBloc>();
|
||||
try {
|
||||
|
||||
if (createRoutineBloc.selectedSpaceId == '' &&
|
||||
createRoutineBloc.selectedCommunityId == '') {
|
||||
if (createRoutineBloc.selectedSpaceId == '' && createRoutineBloc.selectedCommunityId == '') {
|
||||
var spaceBloc = context.read<SpaceTreeBloc>();
|
||||
for (var communityId in spaceBloc.state.selectedCommunities) {
|
||||
List<String> spacesList =
|
||||
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
||||
List<String> spacesList = spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
||||
for (var spaceId in spacesList) {
|
||||
automations.addAll(
|
||||
await SceneApi.getAutomation(spaceId, communityId, projectId));
|
||||
automations.addAll(await SceneApi.getAutomation(spaceId, communityId, projectId));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
automations.addAll(await SceneApi.getAutomation(
|
||||
createRoutineBloc.selectedSpaceId,
|
||||
createRoutineBloc.selectedCommunityId,
|
||||
projectId));
|
||||
createRoutineBloc.selectedSpaceId, createRoutineBloc.selectedCommunityId, projectId));
|
||||
}
|
||||
emit(state.copyWith(
|
||||
automations: automations,
|
||||
@ -253,16 +233,14 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _onSearchRoutines(
|
||||
SearchRoutines event, Emitter<RoutineState> emit) async {
|
||||
FutureOr<void> _onSearchRoutines(SearchRoutines event, Emitter<RoutineState> emit) async {
|
||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
emit(state.copyWith(isLoading: false, errorMessage: null));
|
||||
emit(state.copyWith(searchText: event.query));
|
||||
}
|
||||
|
||||
FutureOr<void> _onAddSelectedIcon(
|
||||
AddSelectedIcon event, Emitter<RoutineState> emit) {
|
||||
FutureOr<void> _onAddSelectedIcon(AddSelectedIcon event, Emitter<RoutineState> emit) {
|
||||
emit(state.copyWith(selectedIcon: event.icon));
|
||||
}
|
||||
|
||||
@ -276,8 +254,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
return actions.last['deviceId'] == 'delay';
|
||||
}
|
||||
|
||||
Future<void> _onCreateScene(
|
||||
CreateSceneEvent event, Emitter<RoutineState> emit) async {
|
||||
Future<void> _onCreateScene(CreateSceneEvent event, Emitter<RoutineState> emit) async {
|
||||
try {
|
||||
// Check if first action is delay
|
||||
// if (_isFirstActionDelay(state.thenItems)) {
|
||||
@ -290,8 +267,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
|
||||
if (_isLastActionDelay(state.thenItems)) {
|
||||
emit(state.copyWith(
|
||||
errorMessage:
|
||||
'A delay condition cannot be the only or the last action',
|
||||
errorMessage: 'A delay condition cannot be the only or the last action',
|
||||
isLoading: false,
|
||||
));
|
||||
return;
|
||||
@ -367,8 +343,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onCreateAutomation(
|
||||
CreateAutomationEvent event, Emitter<RoutineState> emit) async {
|
||||
Future<void> _onCreateAutomation(CreateAutomationEvent event, Emitter<RoutineState> emit) async {
|
||||
try {
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
if (state.routineName == null || state.routineName!.isEmpty) {
|
||||
@ -390,8 +365,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
|
||||
if (_isLastActionDelay(state.thenItems)) {
|
||||
emit(state.copyWith(
|
||||
errorMessage:
|
||||
'A delay condition cannot be the only or the last action',
|
||||
errorMessage: 'A delay condition cannot be the only or the last action',
|
||||
isLoading: false,
|
||||
));
|
||||
CustomSnackBar.redSnackBar('Cannot have delay as the last action');
|
||||
@ -482,8 +456,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
actions: actions,
|
||||
);
|
||||
|
||||
final result =
|
||||
await SceneApi.createAutomation(createAutomationModel, projectUuid);
|
||||
final result = await SceneApi.createAutomation(createAutomationModel, projectUuid);
|
||||
if (result['success']) {
|
||||
add(ResetRoutineState());
|
||||
add(const LoadAutomation());
|
||||
@ -504,21 +477,17 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _onRemoveDragCard(
|
||||
RemoveDragCard event, Emitter<RoutineState> emit) {
|
||||
FutureOr<void> _onRemoveDragCard(RemoveDragCard event, Emitter<RoutineState> emit) {
|
||||
if (event.isFromThen) {
|
||||
final thenItems = List<Map<String, dynamic>>.from(state.thenItems);
|
||||
final selectedFunctions =
|
||||
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
|
||||
final selectedFunctions = Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
|
||||
|
||||
thenItems.removeAt(event.index);
|
||||
selectedFunctions.remove(event.key);
|
||||
emit(state.copyWith(
|
||||
thenItems: thenItems, selectedFunctions: selectedFunctions));
|
||||
emit(state.copyWith(thenItems: thenItems, selectedFunctions: selectedFunctions));
|
||||
} else {
|
||||
final ifItems = List<Map<String, dynamic>>.from(state.ifItems);
|
||||
final selectedFunctions =
|
||||
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
|
||||
final selectedFunctions = Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
|
||||
|
||||
ifItems.removeAt(event.index);
|
||||
selectedFunctions.remove(event.key);
|
||||
@ -529,8 +498,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
isAutomation: false,
|
||||
isTabToRun: false));
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
ifItems: ifItems, selectedFunctions: selectedFunctions));
|
||||
emit(state.copyWith(ifItems: ifItems, selectedFunctions: selectedFunctions));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -542,141 +510,138 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
));
|
||||
}
|
||||
|
||||
FutureOr<void> _onEffectiveTimeEvent(
|
||||
EffectiveTimePeriodEvent event, Emitter<RoutineState> emit) {
|
||||
FutureOr<void> _onEffectiveTimeEvent(EffectiveTimePeriodEvent event, Emitter<RoutineState> emit) {
|
||||
emit(state.copyWith(effectiveTime: event.effectiveTime));
|
||||
}
|
||||
|
||||
FutureOr<void> _onSetRoutineName(
|
||||
SetRoutineName event, Emitter<RoutineState> emit) {
|
||||
FutureOr<void> _onSetRoutineName(SetRoutineName event, Emitter<RoutineState> emit) {
|
||||
emit(state.copyWith(
|
||||
routineName: event.name,
|
||||
));
|
||||
}
|
||||
|
||||
(
|
||||
List<Map<String, dynamic>>,
|
||||
List<Map<String, dynamic>>,
|
||||
Map<String, List<DeviceFunctionData>>
|
||||
) _createCardData(
|
||||
List<RoutineAction> actions,
|
||||
List<RoutineCondition>? conditions,
|
||||
Map<String, List<DeviceFunctionData>> currentFunctions,
|
||||
bool isTabToRun,
|
||||
) {
|
||||
final ifItems = isTabToRun
|
||||
? [
|
||||
{
|
||||
'entityId': 'tab_to_run',
|
||||
'uniqueCustomId': const Uuid().v4(),
|
||||
'deviceId': 'tab_to_run',
|
||||
'title': 'Tab to run',
|
||||
'productType': 'tab_to_run',
|
||||
'imagePath': Assets.tabToRun,
|
||||
}
|
||||
]
|
||||
: conditions?.map((condition) {
|
||||
final matchingDevice = state.devices.firstWhere(
|
||||
(device) => device.uuid == condition.entityId,
|
||||
orElse: () => AllDevicesModel(
|
||||
uuid: condition.entityId,
|
||||
name: condition.entityId,
|
||||
productType: condition.entityType,
|
||||
),
|
||||
);
|
||||
// (
|
||||
// List<Map<String, dynamic>>,
|
||||
// List<Map<String, dynamic>>,
|
||||
// Map<String, List<DeviceFunctionData>>
|
||||
// ) _createCardData(
|
||||
// List<RoutineAction> actions,
|
||||
// List<RoutineCondition>? conditions,
|
||||
// Map<String, List<DeviceFunctionData>> currentFunctions,
|
||||
// bool isTabToRun,
|
||||
// ) {
|
||||
// final ifItems = isTabToRun
|
||||
// ? [
|
||||
// {
|
||||
// 'entityId': 'tab_to_run',
|
||||
// 'uniqueCustomId': const Uuid().v4(),
|
||||
// 'deviceId': 'tab_to_run',
|
||||
// 'title': 'Tab to run',
|
||||
// 'productType': 'tab_to_run',
|
||||
// 'imagePath': Assets.tabToRun,
|
||||
// }
|
||||
// ]
|
||||
// : conditions?.map((condition) {
|
||||
// final matchingDevice = state.devices.firstWhere(
|
||||
// (device) => device.uuid == condition.entityId,
|
||||
// orElse: () => AllDevicesModel(
|
||||
// uuid: condition.entityId,
|
||||
// name: condition.entityId,
|
||||
// productType: condition.entityType,
|
||||
// ),
|
||||
// );
|
||||
|
||||
final cardData = {
|
||||
'entityId': condition.entityId,
|
||||
'uniqueCustomId': const Uuid().v4(),
|
||||
'deviceId': condition.entityId,
|
||||
'title': matchingDevice.name ?? condition.entityId,
|
||||
'productType': condition.entityType,
|
||||
'imagePath':
|
||||
matchingDevice.getDefaultIcon(condition.entityType),
|
||||
};
|
||||
// final cardData = {
|
||||
// 'entityId': condition.entityId,
|
||||
// 'uniqueCustomId': const Uuid().v4(),
|
||||
// 'deviceId': condition.entityId,
|
||||
// 'title': matchingDevice.name ?? condition.entityId,
|
||||
// 'productType': condition.entityType,
|
||||
// 'imagePath':
|
||||
// matchingDevice.getDefaultIcon(condition.entityType),
|
||||
// };
|
||||
|
||||
final functions = matchingDevice.functions;
|
||||
// final functions = matchingDevice.functions;
|
||||
|
||||
for (var function in functions) {
|
||||
if (function.code == condition.expr.statusCode) {
|
||||
currentFunctions[cardData['uniqueCustomId'] ?? ''] = [
|
||||
DeviceFunctionData(
|
||||
entityId: condition.entityId,
|
||||
functionCode: condition.expr.statusCode,
|
||||
value: condition.expr.statusValue,
|
||||
operationName: function.operationName,
|
||||
),
|
||||
];
|
||||
break;
|
||||
}
|
||||
}
|
||||
// for (var function in functions) {
|
||||
// if (function.code == condition.expr.statusCode) {
|
||||
// currentFunctions[cardData['uniqueCustomId'] ?? ''] = [
|
||||
// DeviceFunctionData(
|
||||
// entityId: condition.entityId,
|
||||
// functionCode: condition.expr.statusCode,
|
||||
// value: condition.expr.statusValue,
|
||||
// operationName: function.operationName,
|
||||
// ),
|
||||
// ];
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
return cardData;
|
||||
}).toList() ??
|
||||
[];
|
||||
// return cardData;
|
||||
// }).toList() ??
|
||||
// [];
|
||||
|
||||
final thenItems = actions.map((action) {
|
||||
final matchingDevice = state.devices.firstWhere(
|
||||
(device) => device.uuid == action.entityId,
|
||||
orElse: () => AllDevicesModel(
|
||||
uuid: action.entityId,
|
||||
name: action.entityId,
|
||||
productType: action.productType,
|
||||
),
|
||||
);
|
||||
// final thenItems = actions.map((action) {
|
||||
// final matchingDevice = state.devices.firstWhere(
|
||||
// (device) => device.uuid == action.entityId,
|
||||
// orElse: () => AllDevicesModel(
|
||||
// uuid: action.entityId,
|
||||
// name: action.entityId,
|
||||
// productType: action.productType,
|
||||
// ),
|
||||
// );
|
||||
|
||||
final cardData = {
|
||||
'entityId': action.entityId,
|
||||
'uniqueCustomId': const Uuid().v4(),
|
||||
'deviceId':
|
||||
action.actionExecutor == 'delay' ? 'delay' : action.entityId,
|
||||
'title': action.actionExecutor == 'delay'
|
||||
? 'Delay'
|
||||
: (matchingDevice.name ?? 'Device'),
|
||||
'productType': action.productType,
|
||||
'imagePath': matchingDevice.getDefaultIcon(action.productType),
|
||||
};
|
||||
// final cardData = {
|
||||
// 'entityId': action.entityId,
|
||||
// 'uniqueCustomId': const Uuid().v4(),
|
||||
// 'deviceId':
|
||||
// action.actionExecutor == 'delay' ? 'delay' : action.entityId,
|
||||
// 'title': action.actionExecutor == 'delay'
|
||||
// ? 'Delay'
|
||||
// : (matchingDevice.name ?? 'Device'),
|
||||
// 'productType': action.productType,
|
||||
// 'imagePath': matchingDevice.getDefaultIcon(action.productType),
|
||||
// };
|
||||
|
||||
final functions = matchingDevice.functions;
|
||||
// final functions = matchingDevice.functions;
|
||||
|
||||
if (action.executorProperty != null && action.actionExecutor != 'delay') {
|
||||
final functionCode = action.executorProperty!.functionCode;
|
||||
for (var function in functions) {
|
||||
if (function.code == functionCode) {
|
||||
currentFunctions[cardData['uniqueCustomId'] ?? ''] = [
|
||||
DeviceFunctionData(
|
||||
entityId: action.entityId,
|
||||
functionCode: functionCode ?? '',
|
||||
value: action.executorProperty!.functionValue,
|
||||
operationName: function.operationName,
|
||||
),
|
||||
];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (action.actionExecutor == 'delay') {
|
||||
final delayFunction = DelayFunction(
|
||||
deviceId: action.entityId,
|
||||
deviceName: 'Delay',
|
||||
);
|
||||
currentFunctions[cardData['uniqueCustomId'] ?? ''] = [
|
||||
DeviceFunctionData(
|
||||
entityId: action.entityId,
|
||||
functionCode: 'delay',
|
||||
value: action.executorProperty?.delaySeconds ?? 0,
|
||||
operationName: delayFunction.operationName,
|
||||
),
|
||||
];
|
||||
}
|
||||
// if (action.executorProperty != null && action.actionExecutor != 'delay') {
|
||||
// final functionCode = action.executorProperty!.functionCode;
|
||||
// for (var function in functions) {
|
||||
// if (function.code == functionCode) {
|
||||
// currentFunctions[cardData['uniqueCustomId'] ?? ''] = [
|
||||
// DeviceFunctionData(
|
||||
// entityId: action.entityId,
|
||||
// functionCode: functionCode ?? '',
|
||||
// value: action.executorProperty!.functionValue,
|
||||
// operationName: function.operationName,
|
||||
// ),
|
||||
// ];
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// } else if (action.actionExecutor == 'delay') {
|
||||
// final delayFunction = DelayFunction(
|
||||
// deviceId: action.entityId,
|
||||
// deviceName: 'Delay',
|
||||
// );
|
||||
// currentFunctions[cardData['uniqueCustomId'] ?? ''] = [
|
||||
// DeviceFunctionData(
|
||||
// entityId: action.entityId,
|
||||
// functionCode: 'delay',
|
||||
// value: action.executorProperty?.delaySeconds ?? 0,
|
||||
// operationName: delayFunction.operationName,
|
||||
// ),
|
||||
// ];
|
||||
// }
|
||||
|
||||
return cardData;
|
||||
}).toList();
|
||||
// return cardData;
|
||||
// }).toList();
|
||||
|
||||
return (thenItems, ifItems, currentFunctions);
|
||||
}
|
||||
// return (thenItems, ifItems, currentFunctions);
|
||||
// }
|
||||
|
||||
Future<void> _onGetSceneDetails(
|
||||
GetSceneDetails event, Emitter<RoutineState> emit) async {
|
||||
Future<void> _onGetSceneDetails(GetSceneDetails event, Emitter<RoutineState> emit) async {
|
||||
try {
|
||||
emit(state.copyWith(
|
||||
isLoading: true,
|
||||
@ -719,17 +684,15 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
? '${action.entityId}_automation'
|
||||
: action.actionExecutor == 'delay'
|
||||
? '${action.entityId}_delay'
|
||||
: action.entityId;
|
||||
: const Uuid().v4();
|
||||
|
||||
if (!deviceCards.containsKey(deviceId)) {
|
||||
// if (!deviceCards.containsKey(deviceId)) {
|
||||
deviceCards[deviceId] = {
|
||||
'entityId': action.entityId,
|
||||
'deviceId':
|
||||
action.actionExecutor == 'delay' ? 'delay' : action.entityId,
|
||||
'uniqueCustomId':
|
||||
action.type == 'automation' || action.actionExecutor == 'delay'
|
||||
? const Uuid().v4()
|
||||
: action.entityId,
|
||||
'deviceId': action.actionExecutor == 'delay' ? 'delay' : action.entityId,
|
||||
'uniqueCustomId': action.type == 'automation' || action.actionExecutor == 'delay'
|
||||
? action.entityId
|
||||
: const Uuid().v4(),
|
||||
'title': action.actionExecutor == 'delay'
|
||||
? 'Delay'
|
||||
: action.type == 'automation'
|
||||
@ -745,16 +708,21 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
'device': matchingDevice,
|
||||
'name': action.name,
|
||||
'type': action.type,
|
||||
'tag': matchingDevice?.deviceTags?.isNotEmpty ?? false
|
||||
? matchingDevice?.deviceTags![0].name ?? ''
|
||||
: '',
|
||||
'subSpace': matchingDevice?.deviceSubSpace?.subspaceName ?? '',
|
||||
};
|
||||
}
|
||||
// }
|
||||
|
||||
final cardData = deviceCards[deviceId]!;
|
||||
final uniqueCustomId = cardData['uniqueCustomId'].toString();
|
||||
|
||||
if (action.type == 'automation') {
|
||||
if (!updatedFunctions.containsKey(uniqueCustomId)) {
|
||||
updatedFunctions[uniqueCustomId] = [];
|
||||
}
|
||||
|
||||
if (action.type == 'automation') {
|
||||
updatedFunctions[uniqueCustomId]!.add(
|
||||
DeviceFunctionData(
|
||||
entityId: action.entityId,
|
||||
@ -764,14 +732,10 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
),
|
||||
);
|
||||
// emit(state.copyWith(automationActionExecutor: action.actionExecutor));
|
||||
} else if (action.executorProperty != null &&
|
||||
action.actionExecutor != 'delay') {
|
||||
if (!updatedFunctions.containsKey(uniqueCustomId)) {
|
||||
updatedFunctions[uniqueCustomId] = [];
|
||||
}
|
||||
final functions = matchingDevice?.functions;
|
||||
} else if (action.executorProperty != null && action.actionExecutor != 'delay') {
|
||||
final functions = matchingDevice?.functions ?? [];
|
||||
final functionCode = action.executorProperty?.functionCode;
|
||||
for (DeviceFunction function in functions ?? []) {
|
||||
for (DeviceFunction function in functions) {
|
||||
if (function.code == functionCode) {
|
||||
updatedFunctions[uniqueCustomId]!.add(
|
||||
DeviceFunctionData(
|
||||
@ -785,9 +749,6 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
}
|
||||
} else if (action.actionExecutor == 'delay') {
|
||||
if (!updatedFunctions.containsKey(uniqueCustomId)) {
|
||||
updatedFunctions[uniqueCustomId] = [];
|
||||
}
|
||||
final delayFunction = DelayFunction(
|
||||
deviceId: action.entityId,
|
||||
deviceName: 'Delay',
|
||||
@ -837,8 +798,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _onResetRoutineState(
|
||||
ResetRoutineState event, Emitter<RoutineState> emit) {
|
||||
FutureOr<void> _onResetRoutineState(ResetRoutineState event, Emitter<RoutineState> emit) {
|
||||
emit(state.copyWith(
|
||||
ifItems: [],
|
||||
thenItems: [],
|
||||
@ -861,6 +821,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
isUpdate: false,
|
||||
createRoutineView: false));
|
||||
}
|
||||
|
||||
FutureOr<void> _deleteScene(DeleteScene event, Emitter<RoutineState> emit) async {
|
||||
try {
|
||||
final projectId = await ProjectManager.getProjectUUID() ?? '';
|
||||
@ -915,8 +876,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
// }
|
||||
// }
|
||||
|
||||
FutureOr<void> _fetchDevices(
|
||||
FetchDevicesInRoutine event, Emitter<RoutineState> emit) async {
|
||||
FutureOr<void> _fetchDevices(FetchDevicesInRoutine event, Emitter<RoutineState> emit) async {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
try {
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
@ -925,21 +885,17 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
var createRoutineBloc = context.read<CreateRoutineBloc>();
|
||||
var spaceBloc = context.read<SpaceTreeBloc>();
|
||||
|
||||
if (createRoutineBloc.selectedSpaceId == '' &&
|
||||
createRoutineBloc.selectedCommunityId == '') {
|
||||
if (createRoutineBloc.selectedSpaceId == '' && createRoutineBloc.selectedCommunityId == '') {
|
||||
for (var communityId in spaceBloc.state.selectedCommunities) {
|
||||
List<String> spacesList =
|
||||
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
||||
List<String> spacesList = spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
||||
for (var spaceId in spacesList) {
|
||||
devices.addAll(await DevicesManagementApi()
|
||||
.fetchDevices(communityId, spaceId, projectUuid));
|
||||
devices.addAll(
|
||||
await DevicesManagementApi().fetchDevices(communityId, spaceId, projectUuid));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
devices.addAll(await DevicesManagementApi().fetchDevices(
|
||||
createRoutineBloc.selectedCommunityId,
|
||||
createRoutineBloc.selectedSpaceId,
|
||||
projectUuid));
|
||||
createRoutineBloc.selectedCommunityId, createRoutineBloc.selectedSpaceId, projectUuid));
|
||||
}
|
||||
|
||||
emit(state.copyWith(isLoading: false, devices: devices));
|
||||
@ -948,8 +904,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _onUpdateScene(
|
||||
UpdateScene event, Emitter<RoutineState> emit) async {
|
||||
FutureOr<void> _onUpdateScene(UpdateScene event, Emitter<RoutineState> emit) async {
|
||||
try {
|
||||
// Check if first action is delay
|
||||
// if (_isFirstActionDelay(state.thenItems)) {
|
||||
@ -963,8 +918,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
|
||||
if (_isLastActionDelay(state.thenItems)) {
|
||||
emit(state.copyWith(
|
||||
errorMessage:
|
||||
'A delay condition cannot be the only or the last action',
|
||||
errorMessage: 'A delay condition cannot be the only or the last action',
|
||||
isLoading: false,
|
||||
));
|
||||
return;
|
||||
@ -1017,8 +971,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
actions: actions,
|
||||
);
|
||||
|
||||
final result =
|
||||
await SceneApi.updateScene(createSceneModel, state.sceneId ?? '');
|
||||
final result = await SceneApi.updateScene(createSceneModel, state.sceneId ?? '');
|
||||
if (result['success']) {
|
||||
add(ResetRoutineState());
|
||||
add(const LoadScenes());
|
||||
@ -1037,8 +990,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _onUpdateAutomation(
|
||||
UpdateAutomation event, Emitter<RoutineState> emit) async {
|
||||
FutureOr<void> _onUpdateAutomation(UpdateAutomation event, Emitter<RoutineState> emit) async {
|
||||
try {
|
||||
if (state.routineName == null || state.routineName!.isEmpty) {
|
||||
emit(state.copyWith(
|
||||
@ -1203,9 +1155,9 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
),
|
||||
);
|
||||
|
||||
final deviceId = condition.entityId;
|
||||
final deviceId = const Uuid().v4();
|
||||
|
||||
if (!deviceIfCards.containsKey(deviceId)) {
|
||||
// if (!deviceIfCards.containsKey(deviceId)) {
|
||||
deviceIfCards[deviceId] = {
|
||||
'entityId': condition.entityId,
|
||||
'deviceId': condition.entityId,
|
||||
@ -1216,8 +1168,12 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
'imagePath': matchingDevice.getDefaultIcon(condition.productType),
|
||||
'device': matchingDevice,
|
||||
'type': 'condition',
|
||||
'tag': matchingDevice.deviceTags?.isNotEmpty ?? false
|
||||
? matchingDevice.deviceTags![0].name
|
||||
: '',
|
||||
'subSpace': matchingDevice.deviceSubSpace?.subspaceName ?? '',
|
||||
};
|
||||
}
|
||||
// }
|
||||
|
||||
final cardData = deviceIfCards[deviceId]!;
|
||||
final uniqueCustomId = cardData['uniqueCustomId'].toString();
|
||||
@ -1253,15 +1209,12 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
),
|
||||
);
|
||||
|
||||
final deviceId = action.actionExecutor == 'delay'
|
||||
? '${action.entityId}_delay'
|
||||
: action.entityId;
|
||||
final deviceId = const Uuid().v4();
|
||||
|
||||
if (!deviceThenCards.containsKey(deviceId)) {
|
||||
// if (!deviceThenCards.containsKey(deviceId)) {
|
||||
deviceThenCards[deviceId] = {
|
||||
'entityId': action.entityId,
|
||||
'deviceId':
|
||||
action.actionExecutor == 'delay' ? 'delay' : action.entityId,
|
||||
'deviceId': action.actionExecutor == 'delay' ? 'delay' : action.entityId,
|
||||
'uniqueCustomId': const Uuid().v4(),
|
||||
'title': action.actionExecutor == 'delay'
|
||||
? 'Delay'
|
||||
@ -1281,9 +1234,13 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
: action.type == 'automation'
|
||||
? 'automation'
|
||||
: 'action',
|
||||
'icon': action.icon ?? ''
|
||||
'icon': action.icon ?? '',
|
||||
'tag': matchingDevice.deviceTags?.isNotEmpty ?? false
|
||||
? matchingDevice.deviceTags![0].name
|
||||
: '',
|
||||
'subSpace': matchingDevice.deviceSubSpace?.subspaceName ?? '',
|
||||
};
|
||||
}
|
||||
// }
|
||||
|
||||
final cardData = deviceThenCards[deviceId]!;
|
||||
final uniqueCustomId = cardData['uniqueCustomId'].toString();
|
||||
@ -1292,8 +1249,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
updatedFunctions[uniqueCustomId] = [];
|
||||
}
|
||||
|
||||
if (action.executorProperty != null &&
|
||||
action.actionExecutor != 'delay') {
|
||||
if (action.executorProperty != null && action.actionExecutor != 'delay') {
|
||||
final functions = matchingDevice.functions;
|
||||
final functionCode = action.executorProperty!.functionCode;
|
||||
for (var function in functions) {
|
||||
@ -1335,14 +1291,10 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
}
|
||||
|
||||
final ifItems = deviceIfCards.values
|
||||
.where((card) => card['type'] == 'condition')
|
||||
.toList();
|
||||
final ifItems = deviceIfCards.values.where((card) => card['type'] == 'condition').toList();
|
||||
final thenItems = deviceThenCards.values
|
||||
.where((card) =>
|
||||
card['type'] == 'action' ||
|
||||
card['type'] == 'automation' ||
|
||||
card['type'] == 'scene')
|
||||
card['type'] == 'action' || card['type'] == 'automation' || card['type'] == 'scene')
|
||||
.toList();
|
||||
|
||||
emit(state.copyWith(
|
||||
@ -1364,8 +1316,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onSceneTrigger(
|
||||
SceneTrigger event, Emitter<RoutineState> emit) async {
|
||||
Future<void> _onSceneTrigger(SceneTrigger event, Emitter<RoutineState> emit) async {
|
||||
emit(state.copyWith(loadingSceneId: event.sceneId));
|
||||
|
||||
try {
|
||||
@ -1407,29 +1358,24 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
|
||||
if (success) {
|
||||
final updatedAutomations = await SceneApi.getAutomationByUnitId(
|
||||
event.automationStatusUpdate.spaceUuid,
|
||||
event.communityId,
|
||||
projectId);
|
||||
event.automationStatusUpdate.spaceUuid, event.communityId, projectId);
|
||||
|
||||
// Remove from loading set safely
|
||||
final updatedLoadingIds = {...state.loadingAutomationIds!}
|
||||
..remove(event.automationId);
|
||||
final updatedLoadingIds = {...state.loadingAutomationIds!}..remove(event.automationId);
|
||||
|
||||
emit(state.copyWith(
|
||||
automations: updatedAutomations,
|
||||
loadingAutomationIds: updatedLoadingIds,
|
||||
));
|
||||
} else {
|
||||
final updatedLoadingIds = {...state.loadingAutomationIds!}
|
||||
..remove(event.automationId);
|
||||
final updatedLoadingIds = {...state.loadingAutomationIds!}..remove(event.automationId);
|
||||
emit(state.copyWith(
|
||||
loadingAutomationIds: updatedLoadingIds,
|
||||
errorMessage: 'Update failed',
|
||||
));
|
||||
}
|
||||
} catch (e) {
|
||||
final updatedLoadingIds = {...state.loadingAutomationIds!}
|
||||
..remove(event.automationId);
|
||||
final updatedLoadingIds = {...state.loadingAutomationIds!}..remove(event.automationId);
|
||||
emit(state.copyWith(
|
||||
loadingAutomationIds: updatedLoadingIds,
|
||||
errorMessage: 'Update error: ${e.toString()}',
|
||||
|
@ -63,7 +63,11 @@ class _CreateNewRoutinesDialogState extends State<CreateNewRoutinesDialog> {
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 15, right: 15),
|
||||
child: CommunityDropdown(
|
||||
communities: _bloc.communities,
|
||||
communities: _bloc.communities..sort(
|
||||
(a, b) => a.name.toLowerCase().compareTo(
|
||||
b.name.toLowerCase(),
|
||||
),
|
||||
),
|
||||
selectedValue: _selectedCommunity,
|
||||
onChanged: (String? newValue) {
|
||||
setState(() {
|
||||
|
@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
@ -20,7 +21,7 @@ class SaveRoutineHelper {
|
||||
return AlertDialog(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
content: Container(
|
||||
width: 600,
|
||||
width: MediaQuery.sizeOf(context).width * 0.5,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
@ -30,14 +31,15 @@ class SaveRoutineHelper {
|
||||
children: [
|
||||
DialogHeader('Create a scene: ${state.routineName ?? ""}'),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Left side - IF
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
child: ListView(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
const Text(
|
||||
'IF:',
|
||||
@ -59,26 +61,7 @@ class SaveRoutineHelper {
|
||||
...state.ifItems.map((item) {
|
||||
final functions =
|
||||
state.selectedFunctions[item['uniqueCustomId']] ?? [];
|
||||
return ListTile(
|
||||
leading: SvgPicture.asset(
|
||||
item['imagePath'],
|
||||
width: 22,
|
||||
height: 22,
|
||||
),
|
||||
title:
|
||||
Text(item['title'], style: const TextStyle(fontSize: 14)),
|
||||
subtitle: Wrap(
|
||||
children: functions
|
||||
.map((f) => Text(
|
||||
'${f.operationName}: ${f.value}, ',
|
||||
style: const TextStyle(
|
||||
color: ColorsManager.grayColor, fontSize: 8),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 3,
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
return functionRow(item, context, functions);
|
||||
}),
|
||||
],
|
||||
),
|
||||
@ -87,8 +70,9 @@ class SaveRoutineHelper {
|
||||
// Right side - THEN items
|
||||
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
child: ListView(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
const Text(
|
||||
'THEN:',
|
||||
@ -100,37 +84,7 @@ class SaveRoutineHelper {
|
||||
...state.thenItems.map((item) {
|
||||
final functions =
|
||||
state.selectedFunctions[item['uniqueCustomId']] ?? [];
|
||||
return ListTile(
|
||||
leading: item['type'] == 'tap_to_run' || item['type'] == 'scene'
|
||||
? Image.memory(
|
||||
base64Decode(item['icon']),
|
||||
width: 22,
|
||||
height: 22,
|
||||
)
|
||||
: SvgPicture.asset(
|
||||
item['imagePath'],
|
||||
width: 22,
|
||||
height: 22,
|
||||
),
|
||||
title: Text(
|
||||
item['title'],
|
||||
style: context.textTheme.bodySmall?.copyWith(
|
||||
fontSize: 14,
|
||||
color: ColorsManager.grayColor,
|
||||
),
|
||||
),
|
||||
subtitle: Wrap(
|
||||
children: functions
|
||||
.map((f) => Text(
|
||||
'${f.operationName}: ${f.value}, ',
|
||||
style: context.textTheme.bodySmall?.copyWith(
|
||||
color: ColorsManager.grayColor, fontSize: 8),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 3,
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
return functionRow(item, context, functions);
|
||||
}),
|
||||
],
|
||||
),
|
||||
@ -177,4 +131,112 @@ class SaveRoutineHelper {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
static Widget functionRow(
|
||||
dynamic item, BuildContext context, List<DeviceFunctionData> functions) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 6),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
spacing: 8,
|
||||
children: [
|
||||
item['type'] == 'tap_to_run' || item['type'] == 'scene'
|
||||
? Image.memory(
|
||||
base64Decode(item['icon']),
|
||||
width: 22,
|
||||
height: 22,
|
||||
)
|
||||
: SvgPicture.asset(
|
||||
item['imagePath'],
|
||||
width: 22,
|
||||
height: 22,
|
||||
),
|
||||
Flexible(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
spacing: 2,
|
||||
children: [
|
||||
Text(
|
||||
item['title'],
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: context.textTheme.bodySmall?.copyWith(
|
||||
fontSize: 14,
|
||||
color: ColorsManager.textPrimaryColor,
|
||||
),
|
||||
),
|
||||
Wrap(
|
||||
children: functions
|
||||
.map((f) => Text(
|
||||
'${f.operationName}: ${f.value}',
|
||||
style: context.textTheme.bodySmall
|
||||
?.copyWith(color: ColorsManager.grayColor, fontSize: 8),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 3,
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
spacing: 2,
|
||||
children: [
|
||||
Visibility(
|
||||
visible: item['tag'] != null && item['tag'] != '',
|
||||
child: Row(
|
||||
spacing: 2,
|
||||
children: [
|
||||
SizedBox(width: 8, height: 8, child: SvgPicture.asset(Assets.deviceTagIcon)),
|
||||
Text(
|
||||
item['tag'] ?? '',
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
style: context.textTheme.bodySmall?.copyWith(
|
||||
color: ColorsManager.lightGreyColor,
|
||||
fontSize: 9,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: item['subSpace'] != null && item['subSpace'] != '',
|
||||
child: Row(
|
||||
spacing: 2,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 8, height: 8, child: SvgPicture.asset(Assets.spaceLocationIcon)),
|
||||
Text(
|
||||
item['subSpace'] ?? '',
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
style: context.textTheme.bodySmall?.copyWith(
|
||||
color: ColorsManager.lightGreyColor,
|
||||
fontSize: 9,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
// TODO: functions in conditions / status in actions
|
||||
class CpsOperationalValue {
|
||||
final String icon;
|
||||
final String description;
|
||||
@ -223,7 +222,6 @@ final class CpsSpatialMotionValueFunction extends CpsFunctions {
|
||||
}
|
||||
|
||||
final class CpsMaxDistanceOfDetectionFunction extends CpsFunctions {
|
||||
// confirm with BE
|
||||
CpsMaxDistanceOfDetectionFunction({
|
||||
required super.deviceId,
|
||||
required super.deviceName,
|
||||
@ -267,7 +265,7 @@ final class CpsMaxDistanceOfStaticDetectionFunction extends CpsFunctions {
|
||||
max = 10.0,
|
||||
step = 0.5,
|
||||
super(
|
||||
code: 'static_max_dis', // 0 / 500
|
||||
code: 'static_max_dis',
|
||||
operationName: 'Maximum Distance Of Static Detection',
|
||||
icon: Assets.currentDistanceIcon,
|
||||
);
|
||||
@ -302,7 +300,7 @@ final class CpsDetectionRangeFunction extends CpsFunctions {
|
||||
max = 25.5,
|
||||
step = 0.1,
|
||||
super(
|
||||
code: 'moving_range', // just then
|
||||
code: 'moving_range',
|
||||
operationName: 'Detection Range',
|
||||
icon: Assets.farDetection,
|
||||
);
|
||||
@ -372,7 +370,7 @@ final class CpsPresenceJudgementThrsholdFunction extends CpsFunctions {
|
||||
max = 255,
|
||||
step = 5,
|
||||
super(
|
||||
code: 'presence_reference', // max 255 // change widget
|
||||
code: 'presence_reference',
|
||||
operationName: 'Presence Judgement Threshold',
|
||||
icon: Assets.presenceJudgementThrshold,
|
||||
);
|
||||
@ -403,7 +401,7 @@ final class CpsMotionAmplitudeTriggerThresholdFunction extends CpsFunctions {
|
||||
max = 255,
|
||||
step = 5,
|
||||
super(
|
||||
code: 'moving_reference', // max 255 // change widget
|
||||
code: 'moving_reference',
|
||||
operationName: 'Motion Amplitude Trigger Threshold',
|
||||
icon: Assets.presenceJudgementThrshold,
|
||||
);
|
||||
@ -434,7 +432,7 @@ final class CpsPerpetualBoundaryFunction extends CpsFunctions {
|
||||
max = 5.00,
|
||||
step = 0.50,
|
||||
super(
|
||||
code: 'perceptual_boundary', // 0 / 500
|
||||
code: 'perceptual_boundary',
|
||||
operationName: 'Perpetual Boundary',
|
||||
icon: Assets.boundary,
|
||||
);
|
||||
@ -469,7 +467,7 @@ final class CpsMotionTriggerBoundaryFunction extends CpsFunctions {
|
||||
max = 5.0,
|
||||
step = 0.5,
|
||||
super(
|
||||
code: 'moving_boundary', // 0 / 500 / step 50
|
||||
code: 'moving_boundary',
|
||||
operationName: 'Motion Trigger Boundary',
|
||||
icon: Assets.motionMeter,
|
||||
);
|
||||
@ -504,7 +502,7 @@ final class CpsMotionTriggerTimeFunction extends CpsFunctions {
|
||||
max = 2.0,
|
||||
step = 0.1,
|
||||
super(
|
||||
code: 'moving_rigger_time', // 0 / 2000 steps 10
|
||||
code: 'moving_rigger_time',
|
||||
operationName: 'Motion Trigger Time',
|
||||
icon: Assets.motionMeter,
|
||||
);
|
||||
@ -539,7 +537,7 @@ final class CpsMotionToStaticTimeFunction extends CpsFunctions {
|
||||
max = 50.0,
|
||||
step = 1.0,
|
||||
super(
|
||||
code: 'moving_static_time', // 0 / 6000 steps 100
|
||||
code: 'moving_static_time',
|
||||
operationName: 'Motion To Static Time',
|
||||
icon: Assets.motionMeter,
|
||||
);
|
||||
@ -574,7 +572,7 @@ final class CpsEnteringNoBodyStateTimeFunction extends CpsFunctions {
|
||||
max = 300.0,
|
||||
step = 5.0,
|
||||
super(
|
||||
code: 'none_body_time', // 0 / 300000 / steps 500
|
||||
code: 'none_body_time',
|
||||
operationName: 'Entering Nobody State Time',
|
||||
icon: Assets.motionMeter,
|
||||
);
|
||||
@ -606,7 +604,7 @@ final class CpsSelfTestResultFunctions extends CpsFunctions {
|
||||
required super.deviceName,
|
||||
required super.type,
|
||||
}) : super(
|
||||
code: 'checking_result', // just in action
|
||||
code: 'checking_result',
|
||||
operationName: 'Self-Test Result',
|
||||
icon: Assets.selfTestResult,
|
||||
);
|
||||
@ -828,7 +826,7 @@ class CpsPresenceStatusFunctions extends CpsFunctions {
|
||||
required super.deviceName,
|
||||
required super.type,
|
||||
}) : super(
|
||||
code: 'presence_state', // just in action
|
||||
code: 'presence_state',
|
||||
operationName: 'Presence Status',
|
||||
icon: Assets.presenceSensor,
|
||||
);
|
||||
@ -864,7 +862,7 @@ final class CpsSportsParaFunction extends CpsFunctions {
|
||||
max = 100,
|
||||
step = 1,
|
||||
super(
|
||||
code: 'sports_para', // just in action
|
||||
code: 'sports_para',
|
||||
operationName: 'Sports Para',
|
||||
icon: Assets.sportsPara,
|
||||
);
|
||||
|
@ -29,8 +29,7 @@ class _RoutinesViewState extends State<RoutinesView> {
|
||||
final spaceId = result['space'];
|
||||
final _bloc = BlocProvider.of<CreateRoutineBloc>(context);
|
||||
final routineBloc = context.read<RoutineBloc>();
|
||||
_bloc.add(SaveCommunityIdAndSpaceIdEvent(
|
||||
communityID: communityId, spaceID: spaceId));
|
||||
_bloc.add(SaveCommunityIdAndSpaceIdEvent(communityID: communityId, spaceID: spaceId));
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
routineBloc.add(const CreateNewRoutineViewEvent(createRoutineView: true));
|
||||
}
|
||||
@ -49,7 +48,8 @@ class _RoutinesViewState extends State<RoutinesView> {
|
||||
child: SpaceTreeView(
|
||||
onSelect: () => context.read<RoutineBloc>()
|
||||
..add(const LoadScenes())
|
||||
..add(const LoadAutomation()),
|
||||
..add(const LoadAutomation())
|
||||
..add(FetchDevicesInRoutine()),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
@ -64,8 +64,7 @@ class _RoutinesViewState extends State<RoutinesView> {
|
||||
children: [
|
||||
Text(
|
||||
"Create New Routines",
|
||||
style:
|
||||
Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
|
@ -8,12 +8,12 @@ class DialogFooter extends StatelessWidget {
|
||||
final int? dialogWidth;
|
||||
|
||||
const DialogFooter({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.onCancel,
|
||||
required this.onConfirm,
|
||||
required this.isConfirmEnabled,
|
||||
this.dialogWidth,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -28,21 +28,19 @@ class DialogFooter extends StatelessWidget {
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildFooterButton(
|
||||
context,
|
||||
'Cancel',
|
||||
onCancel,
|
||||
),
|
||||
_buildFooterButton(
|
||||
context: context,
|
||||
text: 'Cancel',
|
||||
onTap: onCancel,
|
||||
),
|
||||
if (isConfirmEnabled) ...[
|
||||
Container(width: 1, height: 50, color: ColorsManager.greyColor),
|
||||
Expanded(
|
||||
child: _buildFooterButton(
|
||||
context,
|
||||
'Confirm',
|
||||
onConfirm,
|
||||
),
|
||||
_buildFooterButton(
|
||||
context: context,
|
||||
text: 'Confirm',
|
||||
onTap: onConfirm,
|
||||
textColor:
|
||||
isConfirmEnabled ? ColorsManager.primaryColorWithOpacity : Colors.red,
|
||||
),
|
||||
],
|
||||
],
|
||||
@ -50,23 +48,23 @@ class DialogFooter extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFooterButton(
|
||||
BuildContext context,
|
||||
String text,
|
||||
VoidCallback? onTap,
|
||||
) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: SizedBox(
|
||||
height: 50,
|
||||
child: Center(
|
||||
Widget _buildFooterButton({
|
||||
required BuildContext context,
|
||||
required String text,
|
||||
required VoidCallback? onTap,
|
||||
Color? textColor,
|
||||
}) {
|
||||
return Expanded(
|
||||
child: TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: ColorsManager.primaryColorWithOpacity,
|
||||
disabledForegroundColor: ColorsManager.primaryColor,
|
||||
),
|
||||
onPressed: onTap,
|
||||
child: Text(
|
||||
text,
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
color: text == 'Confirm'
|
||||
? ColorsManager.primaryColorWithOpacity
|
||||
: ColorsManager.textGray,
|
||||
),
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: textColor ?? ColorsManager.textGray,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -6,6 +6,7 @@ import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
|
||||
class DraggableCard extends StatelessWidget {
|
||||
@ -68,9 +69,9 @@ class DraggableCard extends StatelessWidget {
|
||||
Card(
|
||||
color: ColorsManager.whiteColors,
|
||||
child: Container(
|
||||
padding: padding ?? const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(16),
|
||||
width: 110,
|
||||
height: deviceFunctions.isEmpty ? 123 : null,
|
||||
height: deviceFunctions.isEmpty ? 160 : 180,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
@ -78,6 +79,7 @@ class DraggableCard extends StatelessWidget {
|
||||
children: [
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
height: 50,
|
||||
@ -112,8 +114,69 @@ class DraggableCard extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
Visibility(
|
||||
visible: deviceData['tag'] != null && deviceData['tag'] != '',
|
||||
child: Row(
|
||||
spacing: 2,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 8, height: 8, child: SvgPicture.asset(Assets.deviceTagIcon)),
|
||||
Flexible(
|
||||
child: Text(
|
||||
deviceData['tag'] ?? '',
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
style: context.textTheme.bodySmall?.copyWith(
|
||||
color: ColorsManager.lightGreyColor,
|
||||
fontSize: 9,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: deviceData['subSpace'] != null && deviceData['subSpace'] != '',
|
||||
child: const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: deviceData['subSpace'] != null && deviceData['subSpace'] != '',
|
||||
child: Row(
|
||||
spacing: 2,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 8,
|
||||
height: 8,
|
||||
child: SvgPicture.asset(Assets.spaceLocationIcon)),
|
||||
Flexible(
|
||||
child: Text(
|
||||
deviceData['subSpace'] ?? '',
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
style: context.textTheme.bodySmall?.copyWith(
|
||||
color: ColorsManager.lightGreyColor,
|
||||
fontSize: 9,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (deviceFunctions.isNotEmpty)
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
if (deviceFunctions.isNotEmpty)
|
||||
...deviceFunctions.map((function) => Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@ -123,7 +186,7 @@ class DraggableCard extends StatelessWidget {
|
||||
'${function.operationName}: ${_formatFunctionValue(function)}',
|
||||
style: context.textTheme.bodySmall?.copyWith(
|
||||
fontSize: 9,
|
||||
color: ColorsManager.textGray,
|
||||
color: ColorsManager.lightGreyColor,
|
||||
height: 1.2,
|
||||
),
|
||||
maxLines: 2,
|
||||
|
@ -17,7 +17,8 @@ class IfContainer extends StatelessWidget {
|
||||
builder: (context, state) {
|
||||
return DragTarget<Map<String, dynamic>>(
|
||||
builder: (context, candidateData, rejectedData) {
|
||||
return Container(
|
||||
return SingleChildScrollView(
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
@ -27,8 +28,7 @@ class IfContainer extends StatelessWidget {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text('IF',
|
||||
style:
|
||||
TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||
if (state.isAutomation && state.ifItems.isNotEmpty)
|
||||
AutomationOperatorSelector(
|
||||
selectedOperator: state.selectedAutomationOperator),
|
||||
@ -55,17 +55,16 @@ class IfContainer extends StatelessWidget {
|
||||
(index) => GestureDetector(
|
||||
onTap: () async {
|
||||
if (!state.isTabToRun) {
|
||||
final result =
|
||||
await DeviceDialogHelper.showDeviceDialog(
|
||||
final result = await DeviceDialogHelper.showDeviceDialog(
|
||||
context: context,
|
||||
data: state.ifItems[index],
|
||||
removeComparetors: false,
|
||||
dialogType: "IF");
|
||||
|
||||
if (result != null) {
|
||||
context.read<RoutineBloc>().add(
|
||||
AddToIfContainer(
|
||||
state.ifItems[index], false));
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToIfContainer(state.ifItems[index], false));
|
||||
} else if (![
|
||||
'AC',
|
||||
'1G',
|
||||
@ -74,11 +73,10 @@ class IfContainer extends StatelessWidget {
|
||||
'WPS',
|
||||
'GW',
|
||||
'CPS',
|
||||
].contains(
|
||||
state.ifItems[index]['productType'])) {
|
||||
context.read<RoutineBloc>().add(
|
||||
AddToIfContainer(
|
||||
state.ifItems[index], false));
|
||||
].contains(state.ifItems[index]['productType'])) {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToIfContainer(state.ifItems[index], false));
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -86,22 +84,21 @@ class IfContainer extends StatelessWidget {
|
||||
imagePath: state.ifItems[index]['imagePath'] ?? '',
|
||||
title: state.ifItems[index]['title'] ?? '',
|
||||
deviceData: state.ifItems[index],
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 4, vertical: 8),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 8),
|
||||
isFromThen: false,
|
||||
isFromIf: true,
|
||||
onRemove: () {
|
||||
context.read<RoutineBloc>().add(RemoveDragCard(
|
||||
index: index,
|
||||
isFromThen: false,
|
||||
key: state.ifItems[index]
|
||||
['uniqueCustomId']));
|
||||
key: state.ifItems[index]['uniqueCustomId']));
|
||||
},
|
||||
),
|
||||
)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
onAcceptWithDetails: (data) async {
|
||||
@ -124,14 +121,10 @@ class IfContainer extends StatelessWidget {
|
||||
removeComparetors: false);
|
||||
|
||||
if (result != null) {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToIfContainer(mutableData, false));
|
||||
context.read<RoutineBloc>().add(AddToIfContainer(mutableData, false));
|
||||
} else if (!['AC', '1G', '2G', '3G', 'WPS', 'GW', 'CPS']
|
||||
.contains(mutableData['productType'])) {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToIfContainer(mutableData, false));
|
||||
context.read<RoutineBloc>().add(AddToIfContainer(mutableData, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -177,9 +170,7 @@ class AutomationOperatorSelector extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(const ChangeAutomationOperator(operator: 'or'));
|
||||
context.read<RoutineBloc>().add(const ChangeAutomationOperator(operator: 'or'));
|
||||
},
|
||||
),
|
||||
Container(
|
||||
@ -205,9 +196,7 @@ class AutomationOperatorSelector extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(const ChangeAutomationOperator(operator: 'and'));
|
||||
context.read<RoutineBloc>().add(const ChangeAutomationOperator(operator: 'and'));
|
||||
},
|
||||
),
|
||||
],
|
||||
|
@ -121,8 +121,7 @@ class _RoutineViewCardState extends State<RoutineViewCard> {
|
||||
child: SizedBox(
|
||||
width: 16,
|
||||
height: 16,
|
||||
child:
|
||||
CircularProgressIndicator(strokeWidth: 2),
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
),
|
||||
),
|
||||
)
|
||||
@ -159,9 +158,7 @@ class _RoutineViewCardState extends State<RoutineViewCard> {
|
||||
height: iconSize,
|
||||
width: iconSize,
|
||||
fit: BoxFit.contain,
|
||||
errorBuilder:
|
||||
(context, error, stackTrace) =>
|
||||
Image.asset(
|
||||
errorBuilder: (context, error, stackTrace) => Image.asset(
|
||||
Assets.logo,
|
||||
height: iconSize,
|
||||
width: iconSize,
|
||||
@ -174,8 +171,7 @@ class _RoutineViewCardState extends State<RoutineViewCard> {
|
||||
width: iconSize,
|
||||
fit: BoxFit.contain,
|
||||
)
|
||||
: (widget.icon is String &&
|
||||
widget.icon.endsWith('.svg'))
|
||||
: (widget.icon is String && widget.icon.endsWith('.svg'))
|
||||
? SvgPicture.asset(
|
||||
height: iconSize,
|
||||
width: iconSize,
|
||||
@ -185,9 +181,7 @@ class _RoutineViewCardState extends State<RoutineViewCard> {
|
||||
: Icon(
|
||||
widget.icon,
|
||||
color: ColorsManager.dialogBlueTitle,
|
||||
size: widget.isSmallScreenSize(context)
|
||||
? 30
|
||||
: 40,
|
||||
size: widget.isSmallScreenSize(context) ? 30 : 40,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -200,11 +194,10 @@ class _RoutineViewCardState extends State<RoutineViewCard> {
|
||||
widget.textString,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 2,
|
||||
maxLines: 1,
|
||||
style: context.textTheme.bodySmall?.copyWith(
|
||||
color: ColorsManager.blackColor,
|
||||
fontSize:
|
||||
widget.isSmallScreenSize(context) ? 10 : 12,
|
||||
fontSize: widget.isSmallScreenSize(context) ? 10 : 12,
|
||||
),
|
||||
),
|
||||
if (widget.spaceName != '')
|
||||
@ -220,14 +213,10 @@ class _RoutineViewCardState extends State<RoutineViewCard> {
|
||||
widget.spaceName,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 2,
|
||||
style:
|
||||
context.textTheme.bodySmall?.copyWith(
|
||||
maxLines: 1,
|
||||
style: context.textTheme.bodySmall?.copyWith(
|
||||
color: ColorsManager.blackColor,
|
||||
fontSize:
|
||||
widget.isSmallScreenSize(context)
|
||||
? 10
|
||||
: 12,
|
||||
fontSize: widget.isSmallScreenSize(context) ? 10 : 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -51,12 +51,12 @@ class _RoutineDevicesState extends State<RoutineDevices> {
|
||||
'productType': device.productType,
|
||||
'functions': device.functions,
|
||||
'uniqueCustomId': '',
|
||||
'tag': device.deviceTags!.isNotEmpty ? device.deviceTags![0].name : '',
|
||||
'subSpace': device.deviceSubSpace?.subspaceName ?? '',
|
||||
};
|
||||
|
||||
if (state.searchText != null && state.searchText!.isNotEmpty) {
|
||||
return device.name!
|
||||
.toLowerCase()
|
||||
.contains(state.searchText!.toLowerCase())
|
||||
return device.name!.toLowerCase().contains(state.searchText!.toLowerCase())
|
||||
? DraggableCard(
|
||||
imagePath: deviceData['imagePath'] as String,
|
||||
title: deviceData['title'] as String,
|
||||
|
@ -11,6 +11,7 @@ import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/ceiling_senso
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/ceiling_sensor/cps_dialog_slider_selector.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/ceiling_sensor/cps_dialog_value_selector.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/ceiling_sensor/cps_functions_list.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/ceiling_sensor/cps_slider_helpers.dart';
|
||||
|
||||
class CeilingSensorDialog extends StatefulWidget {
|
||||
const CeilingSensorDialog({
|
||||
@ -34,6 +35,7 @@ class CeilingSensorDialog extends StatefulWidget {
|
||||
|
||||
class _CeilingSensorDialogState extends State<CeilingSensorDialog> {
|
||||
late final List<CpsFunctions> _cpsFunctions;
|
||||
late final String _dialogHeaderText;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -45,6 +47,9 @@ class _CeilingSensorDialogState extends State<CeilingSensorDialog> {
|
||||
}
|
||||
return function.type == 'IF' || function.type == 'BOTH';
|
||||
}).toList();
|
||||
|
||||
final isIfDialog = widget.dialogType == 'IF';
|
||||
_dialogHeaderText = isIfDialog ? 'Conditions' : 'Functions';
|
||||
}
|
||||
|
||||
@override
|
||||
@ -66,15 +71,18 @@ class _CeilingSensorDialogState extends State<CeilingSensorDialog> {
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const DialogHeader('Presence Sensor Condition'),
|
||||
DialogHeader('Presence Sensor $_dialogHeaderText'),
|
||||
Expanded(child: _buildMainContent(context, state)),
|
||||
DialogFooter(
|
||||
onCancel: () => Navigator.pop(context),
|
||||
onConfirm: state.addedFunctions.isNotEmpty
|
||||
? () {
|
||||
final functions = _updateValuesForAddedFunctions(
|
||||
state.addedFunctions,
|
||||
);
|
||||
context.read<RoutineBloc>().add(
|
||||
AddFunctionToRoutine(
|
||||
state.addedFunctions,
|
||||
functions,
|
||||
'${widget.uniqueCustomId}',
|
||||
),
|
||||
);
|
||||
@ -148,4 +156,64 @@ class _CeilingSensorDialogState extends State<CeilingSensorDialog> {
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
static const _mappableSteppedFunctions = <String>{
|
||||
'static_max_dis',
|
||||
'presence_reference',
|
||||
'moving_reference',
|
||||
'perceptual_boundary',
|
||||
'moving_boundary',
|
||||
'moving_rigger_time',
|
||||
'moving_static_time',
|
||||
'none_body_time',
|
||||
'moving_max_dis',
|
||||
'moving_range',
|
||||
'presence_range',
|
||||
};
|
||||
|
||||
List<DeviceFunctionData> _updateValuesForAddedFunctions(
|
||||
List<DeviceFunctionData> addedFunctions,
|
||||
) {
|
||||
return addedFunctions.map((function) {
|
||||
final shouldMapValue = _mappableSteppedFunctions.contains(
|
||||
function.functionCode,
|
||||
);
|
||||
if (shouldMapValue) {
|
||||
final mappedValue = _mapSteppedValue(
|
||||
value: function.value,
|
||||
inputStep: CpsSliderHelpers.dividendOfRange(function.functionCode),
|
||||
inputRange: CpsSliderHelpers.sliderRange(function.functionCode),
|
||||
outputRange: CpsSliderHelpers.mappedRange(function.functionCode),
|
||||
);
|
||||
return DeviceFunctionData(
|
||||
value: mappedValue,
|
||||
entityId: function.entityId,
|
||||
functionCode: function.functionCode,
|
||||
operationName: function.operationName,
|
||||
condition: function.condition,
|
||||
actionExecutor: function.actionExecutor,
|
||||
valueDescription: function.valueDescription,
|
||||
);
|
||||
}
|
||||
return function;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
int _mapSteppedValue({
|
||||
required (double min, double max) inputRange,
|
||||
required double inputStep,
|
||||
required (double min, double max, double dividend) outputRange,
|
||||
required double value,
|
||||
}) {
|
||||
final (inputMin, inputMax) = inputRange;
|
||||
final (outputMin, outputMax, outputStep) = outputRange;
|
||||
|
||||
final clampedValue = value.clamp(inputMin, inputMax);
|
||||
|
||||
final stepsFromMin = ((clampedValue - inputMin) / inputStep).round();
|
||||
|
||||
final mappedValue = outputMin + (stepsFromMin * outputStep);
|
||||
|
||||
return mappedValue.clamp(outputMin, outputMax).round();
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo
|
||||
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/ceiling_presence_sensor_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/ceiling_sensor/cps_slider_helpers.dart';
|
||||
import 'package:syncrow_web/pages/routines/widgets/slider_value_selector.dart';
|
||||
|
||||
class CpsDialogSliderSelector extends StatelessWidget {
|
||||
@ -31,10 +32,13 @@ class CpsDialogSliderSelector extends StatelessWidget {
|
||||
return SliderValueSelector(
|
||||
currentCondition: selectedFunctionData.condition,
|
||||
dialogType: dialogType,
|
||||
sliderRange: _sliderRange,
|
||||
displayedValue: _displayText,
|
||||
sliderRange: CpsSliderHelpers.sliderRange(selectedFunctionData.functionCode),
|
||||
displayedValue: CpsSliderHelpers.displayText(
|
||||
value: selectedFunctionData.value,
|
||||
functionCode: selectedFunctionData.functionCode,
|
||||
),
|
||||
initialValue: selectedFunctionData.value ?? 0,
|
||||
unit: _unit,
|
||||
unit: CpsSliderHelpers.unit(selectedFunctionData.functionCode),
|
||||
onConditionChanged: (condition) => context.read<FunctionBloc>().add(
|
||||
AddFunction(
|
||||
functionData: DeviceFunctionData(
|
||||
@ -52,85 +56,14 @@ class CpsDialogSliderSelector extends StatelessWidget {
|
||||
entityId: device?.uuid ?? '',
|
||||
functionCode: selectedFunction,
|
||||
operationName: operationName,
|
||||
value: value,
|
||||
value: double.parse(value.toStringAsFixed(2)),
|
||||
condition: selectedFunctionData.condition,
|
||||
),
|
||||
),
|
||||
),
|
||||
dividendOfRange: _dividendOfRange,
|
||||
dividendOfRange: CpsSliderHelpers.dividendOfRange(
|
||||
selectedFunctionData.functionCode,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
(double, double) get _sliderRange => switch (selectedFunctionData.functionCode) {
|
||||
'moving_speed' => (0, 32),
|
||||
'sensitivity' => (0, 10),
|
||||
'space_static_val' => (0, 255),
|
||||
'space_move_val' => (0, 255),
|
||||
'moving_max_dis' => (0, 10),
|
||||
'static_max_dis' => (0, 10),
|
||||
'moving_range' => (0, 25.5),
|
||||
'presence_range' => (0, 25.5),
|
||||
'presence_judgement_threshold' => (0, 255),
|
||||
'motion_amplitude_trigger_threshold' => (0, 255),
|
||||
'perceptual_boundary' => (0, 5),
|
||||
'moving_boundary' => (0, 5),
|
||||
'moving_rigger_time' => (0, 2),
|
||||
'moving_static_time' => (0, 50),
|
||||
'none_body_time' => (0, 300),
|
||||
_ => (0, 300),
|
||||
};
|
||||
|
||||
String get _displayText {
|
||||
final value = selectedFunctionData.value;
|
||||
final parsedValue = double.tryParse('$value');
|
||||
|
||||
return switch (selectedFunctionData.functionCode) {
|
||||
'moving_max_dis' ||
|
||||
'static_max_dis' ||
|
||||
'moving_range' ||
|
||||
'presence_range' ||
|
||||
'perceptual_boundary' ||
|
||||
'moving_boundary' =>
|
||||
parsedValue?.toStringAsFixed(1) ?? '0',
|
||||
'moving_rigger_time' => parsedValue?.toStringAsFixed(2) ?? '0',
|
||||
'moving_static_time' ||
|
||||
'none_body_time' =>
|
||||
parsedValue?.toStringAsFixed(2) ?? '0',
|
||||
_ => '${parsedValue?.toStringAsFixed(0) ?? 0}',
|
||||
};
|
||||
}
|
||||
|
||||
String get _unit {
|
||||
return switch (selectedFunctionData.functionCode) {
|
||||
'moving_max_dis' ||
|
||||
'static_max_dis' ||
|
||||
'moving_range' ||
|
||||
'presence_range' ||
|
||||
'perceptual_boundary' ||
|
||||
'moving_boundary' =>
|
||||
'M',
|
||||
'moving_rigger_time' || 'moving_static_time' || 'none_body_time' => 'sec',
|
||||
_ => '',
|
||||
};
|
||||
}
|
||||
|
||||
double get _dividendOfRange => switch (selectedFunctionData.functionCode) {
|
||||
'sensitivity' => 1,
|
||||
'moving_speed' => 1,
|
||||
'space_static_val' => 1,
|
||||
'space_move_val' => 1,
|
||||
'presence_reference' => 5,
|
||||
'moving_reference' => 5,
|
||||
'moving_max_dis' => 0.5,
|
||||
'static_max_dis' => 0.5,
|
||||
'moving_range' => 0.1,
|
||||
'presence_range' => 0.1,
|
||||
'perceptual_boundary' => 0.5,
|
||||
'moving_boundary' => 0.5,
|
||||
'moving_rigger_time' => 0.1,
|
||||
'moving_static_time' => 1.0,
|
||||
'none_body_time' => 5.0,
|
||||
'sports_para' => 1.0,
|
||||
_ => 1,
|
||||
};
|
||||
}
|
||||
|
@ -0,0 +1,90 @@
|
||||
abstract final class CpsSliderHelpers {
|
||||
static (double min, double max, double step) mappedRange(String functionCode) {
|
||||
final (defaultMin, defaultMax) = sliderRange(functionCode);
|
||||
final defaultDivdidend = dividendOfRange(functionCode);
|
||||
return switch (functionCode) {
|
||||
'static_max_dis' => (0, 500, 50),
|
||||
'presence_reference' => (0, 255, 5),
|
||||
'moving_reference' => (0, 255, 5),
|
||||
'perceptual_boundary' => (0, 500, 50),
|
||||
'moving_boundary' => (0, 500, 50),
|
||||
'moving_rigger_time' => (0, 2000, 100),
|
||||
'moving_static_time' => (0, 60000, 1000),
|
||||
'none_body_time' => (0, 300000, 5000),
|
||||
'moving_max_dis' => (0, 500, 50),
|
||||
'moving_range' => (0, 255, 5),
|
||||
'presence_range' => (0, 255, 5),
|
||||
_ => (defaultMin, defaultMax, defaultDivdidend),
|
||||
};
|
||||
}
|
||||
|
||||
static (double min, double max) sliderRange(String functionCode) =>
|
||||
switch (functionCode) {
|
||||
'moving_speed' => (0, 32),
|
||||
'sensitivity' => (0, 10),
|
||||
'space_static_val' => (0, 255),
|
||||
'space_move_val' => (0, 255),
|
||||
'moving_max_dis' => (0, 10),
|
||||
'static_max_dis' => (0, 10),
|
||||
'moving_range' => (0, 25.5),
|
||||
'presence_range' => (0, 25.5),
|
||||
'presence_judgement_threshold' => (0, 255),
|
||||
'motion_amplitude_trigger_threshold' => (0, 255),
|
||||
'perceptual_boundary' => (0, 5),
|
||||
'moving_boundary' => (0, 5),
|
||||
'moving_rigger_time' => (0, 2),
|
||||
'moving_static_time' => (0, 50),
|
||||
'none_body_time' => (0, 300),
|
||||
'sports_para' => (0, 100),
|
||||
_ => (0, 300),
|
||||
};
|
||||
|
||||
static double dividendOfRange(String functionCode) => switch (functionCode) {
|
||||
'presence_reference' => 5,
|
||||
'moving_reference' => 5,
|
||||
'moving_max_dis' => 0.5,
|
||||
'static_max_dis' => 0.5,
|
||||
'moving_range' => 0.1,
|
||||
'presence_range' => 0.1,
|
||||
'perceptual_boundary' => 0.5,
|
||||
'moving_boundary' => 0.5,
|
||||
'moving_rigger_time' => 0.1,
|
||||
'moving_static_time' => 1.0,
|
||||
'none_body_time' => 5.0,
|
||||
_ => 1,
|
||||
};
|
||||
|
||||
static String unit(String functionCode) => switch (functionCode) {
|
||||
'moving_max_dis' ||
|
||||
'static_max_dis' ||
|
||||
'moving_range' ||
|
||||
'presence_range' ||
|
||||
'perceptual_boundary' ||
|
||||
'moving_boundary' =>
|
||||
'M',
|
||||
'moving_rigger_time' || 'moving_static_time' || 'none_body_time' => 'sec',
|
||||
_ => '',
|
||||
};
|
||||
|
||||
static String displayText({
|
||||
required dynamic value,
|
||||
required String functionCode,
|
||||
}) {
|
||||
final parsedValue = double.tryParse('$value');
|
||||
|
||||
return switch (functionCode) {
|
||||
'moving_max_dis' ||
|
||||
'static_max_dis' ||
|
||||
'moving_range' ||
|
||||
'presence_range' ||
|
||||
'perceptual_boundary' ||
|
||||
'moving_boundary' =>
|
||||
parsedValue?.toStringAsFixed(1) ?? '0',
|
||||
'moving_rigger_time' => parsedValue?.toStringAsFixed(2) ?? '0',
|
||||
'moving_static_time' ||
|
||||
'none_body_time' =>
|
||||
parsedValue?.toStringAsFixed(2) ?? '0',
|
||||
_ => '${parsedValue?.toStringAsFixed(0) ?? 0}',
|
||||
};
|
||||
}
|
||||
}
|
@ -5,7 +5,6 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo
|
||||
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routines/helper/duration_format_helper.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/ac/ac_function.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/base_switch_function.dart';
|
||||
import 'package:syncrow_web/pages/routines/models/gang_switches/one_gang_switch/one_gang_switch.dart';
|
||||
@ -25,23 +24,21 @@ class OneGangSwitchHelper {
|
||||
required String uniqueCustomId,
|
||||
required bool removeComparetors,
|
||||
}) async {
|
||||
List<BaseSwitchFunction> oneGangFunctions =
|
||||
functions.whereType<BaseSwitchFunction>().toList();
|
||||
List<BaseSwitchFunction> oneGangFunctions = functions.whereType<BaseSwitchFunction>().toList();
|
||||
|
||||
return showDialog<Map<String, dynamic>?>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (_) => FunctionBloc()
|
||||
..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
||||
create: (_) => FunctionBloc()..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
||||
child: AlertDialog(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
||||
builder: (context, state) {
|
||||
final selectedFunction = state.selectedFunction;
|
||||
final selectedOperationName = state.selectedOperationName;
|
||||
final selectedFunctionData = state.addedFunctions
|
||||
.firstWhere((f) => f.functionCode == selectedFunction,
|
||||
final selectedFunctionData =
|
||||
state.addedFunctions.firstWhere((f) => f.functionCode == selectedFunction,
|
||||
orElse: () => DeviceFunctionData(
|
||||
entityId: '',
|
||||
functionCode: selectedFunction ?? '',
|
||||
@ -88,12 +85,9 @@ class OneGangSwitchHelper {
|
||||
color: ColorsManager.textGray,
|
||||
),
|
||||
onTap: () {
|
||||
context
|
||||
.read<FunctionBloc>()
|
||||
.add(SelectFunction(
|
||||
context.read<FunctionBloc>().add(SelectFunction(
|
||||
functionCode: function.code,
|
||||
operationName:
|
||||
function.operationName,
|
||||
operationName: function.operationName,
|
||||
));
|
||||
},
|
||||
);
|
||||
@ -226,11 +220,11 @@ class OneGangSwitchHelper {
|
||||
selectedFunctionData,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
_buildCountDownDisplay(context, initialValue, device, operationName,
|
||||
selectedFunctionData, selectCode),
|
||||
_buildCountDownDisplay(
|
||||
context, initialValue, device, operationName, selectedFunctionData, selectCode),
|
||||
const SizedBox(height: 20),
|
||||
_buildCountDownSlider(context, initialValue, device, operationName,
|
||||
selectedFunctionData, selectCode),
|
||||
_buildCountDownSlider(
|
||||
context, initialValue, device, operationName, selectedFunctionData, selectCode),
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -271,8 +265,7 @@ class OneGangSwitchHelper {
|
||||
minHeight: 40.0,
|
||||
minWidth: 40.0,
|
||||
),
|
||||
isSelected:
|
||||
conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||
isSelected: conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||
children: conditions.map((c) => Text(c)).toList(),
|
||||
);
|
||||
}
|
||||
@ -320,8 +313,7 @@ class OneGangSwitchHelper {
|
||||
value: (initialValue ?? 0).toDouble(),
|
||||
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
||||
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
||||
divisions: (((operationalValues.maxValue ?? 0) -
|
||||
(operationalValues.minValue ?? 0)) /
|
||||
divisions: (((operationalValues.maxValue ?? 0) - (operationalValues.minValue ?? 0)) /
|
||||
(operationalValues.stepValue ?? 1))
|
||||
.round(),
|
||||
onChanged: (value) {
|
||||
@ -373,13 +365,9 @@ class OneGangSwitchHelper {
|
||||
style: context.textTheme.bodyMedium,
|
||||
),
|
||||
trailing: Icon(
|
||||
isSelected
|
||||
? Icons.radio_button_checked
|
||||
: Icons.radio_button_unchecked,
|
||||
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
|
||||
size: 24,
|
||||
color: isSelected
|
||||
? ColorsManager.primaryColorWithOpacity
|
||||
: ColorsManager.textGray,
|
||||
color: isSelected ? ColorsManager.primaryColorWithOpacity : ColorsManager.textGray,
|
||||
),
|
||||
onTap: () {
|
||||
if (!isSelected) {
|
||||
@ -391,8 +379,7 @@ class OneGangSwitchHelper {
|
||||
operationName: operationName,
|
||||
value: value.value,
|
||||
condition: selectedFunctionData?.condition,
|
||||
valueDescription:
|
||||
selectedFunctionData?.valueDescription,
|
||||
valueDescription: selectedFunctionData?.valueDescription,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
@ -28,9 +27,12 @@ class _TimeWheelPickerState extends State<TimeWheelPicker> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_hoursController = FixedExtentScrollController(initialItem: widget.initialHours);
|
||||
_minutesController = FixedExtentScrollController(initialItem: widget.initialMinutes);
|
||||
_secondsController = FixedExtentScrollController(initialItem: widget.initialSeconds);
|
||||
_hoursController =
|
||||
FixedExtentScrollController(initialItem: widget.initialHours);
|
||||
_minutesController =
|
||||
FixedExtentScrollController(initialItem: widget.initialMinutes);
|
||||
_secondsController =
|
||||
FixedExtentScrollController(initialItem: widget.initialSeconds);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -47,6 +49,8 @@ class _TimeWheelPickerState extends State<TimeWheelPicker> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_hoursController.dispose();
|
||||
@ -63,24 +67,26 @@ class _TimeWheelPickerState extends State<TimeWheelPicker> {
|
||||
_buildPickerColumn(
|
||||
label: 'h',
|
||||
controller: _hoursController,
|
||||
itemCount: 24,
|
||||
onChanged: (value) => _handleTimeChange(
|
||||
itemCount: 3,
|
||||
onChanged: (value) {
|
||||
_handleTimeChange(
|
||||
value,
|
||||
_minutesController.selectedItem,
|
||||
_secondsController.selectedItem,
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
const SizedBox(width: 5),
|
||||
_buildPickerColumn(
|
||||
label: 'm',
|
||||
controller: _minutesController,
|
||||
itemCount: 60,
|
||||
onChanged: (value) => _handleTimeChange(
|
||||
onChanged: (value) {
|
||||
_handleTimeChange(
|
||||
_hoursController.selectedItem,
|
||||
value,
|
||||
_secondsController.selectedItem,
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
const SizedBox(width: 5),
|
||||
_buildPickerColumn(
|
||||
label: 's',
|
||||
@ -97,6 +103,19 @@ class _TimeWheelPickerState extends State<TimeWheelPicker> {
|
||||
}
|
||||
|
||||
void _handleTimeChange(int hours, int minutes, int seconds) {
|
||||
int total = hours * 3600 + minutes * 60 + seconds;
|
||||
if (total > 10000) {
|
||||
hours = 2;
|
||||
minutes = 46;
|
||||
seconds = 40;
|
||||
total = 10000;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_hoursController.jumpToItem(hours);
|
||||
_minutesController.jumpToItem(minutes);
|
||||
_secondsController.jumpToItem(seconds);
|
||||
});
|
||||
}
|
||||
|
||||
widget.onTimeChanged(hours, minutes, seconds);
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||
@ -107,6 +109,11 @@ class _LoadedSpaceViewState extends State<LoadedSpaceView> {
|
||||
selectedSpaceUuid: widget.selectedSpace?.uuid ??
|
||||
widget.selectedCommunity?.uuid ??
|
||||
'',
|
||||
onCreateCommunity: (name, description) {
|
||||
context.read<SpaceManagementBloc>().add(
|
||||
CreateCommunityEvent(name, description, context),
|
||||
);
|
||||
},
|
||||
),
|
||||
CommunityStructureArea(
|
||||
selectedCommunity: widget.selectedCommunity,
|
||||
|
@ -0,0 +1,34 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
class SidebarAddCommunityButton extends StatelessWidget {
|
||||
const SidebarAddCommunityButton({
|
||||
required this.onTap,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final void Function() onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox.square(
|
||||
dimension: 30,
|
||||
child: IconButton(
|
||||
style: IconButton.styleFrom(
|
||||
iconSize: 20,
|
||||
backgroundColor: ColorsManager.circleImageBackground,
|
||||
shape: const CircleBorder(
|
||||
side: BorderSide(
|
||||
color: ColorsManager.lightGrayBorderColor,
|
||||
width: 3,
|
||||
),
|
||||
),
|
||||
),
|
||||
onPressed: onTap,
|
||||
icon: SvgPicture.asset(Assets.addIcon),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/sidebar_add_community_button.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
|
||||
class SidebarHeader extends StatelessWidget {
|
||||
const SidebarHeader({
|
||||
required this.onAddCommunity,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final void Function() onAddCommunity;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: subSectionContainerDecoration,
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Communities',
|
||||
style: context.textTheme.titleMedium?.copyWith(
|
||||
color: ColorsManager.blackColor,
|
||||
),
|
||||
),
|
||||
SidebarAddCommunityButton(
|
||||
onTap: onAddCommunity,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,80 +1,78 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:syncrow_web/common/widgets/search_bar.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/community_tile.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/sidebar_header.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/space_tile_widget.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/create_community/view/create_community_dialog.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/structure_selector/bloc/center_body_bloc.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/structure_selector/bloc/center_body_event.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
|
||||
class SidebarWidget extends StatefulWidget {
|
||||
final List<CommunityModel> communities;
|
||||
final String? selectedSpaceUuid;
|
||||
final void Function(String name, String description) onCreateCommunity;
|
||||
|
||||
const SidebarWidget({
|
||||
super.key,
|
||||
required this.communities,
|
||||
required this.onCreateCommunity,
|
||||
this.selectedSpaceUuid,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
_SidebarWidgetState createState() => _SidebarWidgetState();
|
||||
State<SidebarWidget> createState() => _SidebarWidgetState();
|
||||
}
|
||||
|
||||
class _SidebarWidgetState extends State<SidebarWidget> {
|
||||
String _searchQuery = ''; // Track search query
|
||||
String _searchQuery = '';
|
||||
String? _selectedSpaceUuid;
|
||||
String? _selectedId;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_selectedId = widget.selectedSpaceUuid;
|
||||
super.initState();
|
||||
_selectedId = widget.selectedSpaceUuid; // Initialize with the passed selected space UUID
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant SidebarWidget oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.selectedSpaceUuid != oldWidget.selectedSpaceUuid) {
|
||||
setState(() {
|
||||
_selectedId = widget.selectedSpaceUuid;
|
||||
});
|
||||
setState(() => _selectedId = widget.selectedSpaceUuid);
|
||||
}
|
||||
super.didUpdateWidget(oldWidget);
|
||||
}
|
||||
|
||||
// Function to filter communities based on the search query
|
||||
List<CommunityModel> _filterCommunities() {
|
||||
List<CommunityModel> _filteredCommunities() {
|
||||
if (_searchQuery.isEmpty) {
|
||||
// Reset the selected community and space UUIDs if there's no query
|
||||
_selectedSpaceUuid = null;
|
||||
return widget.communities;
|
||||
}
|
||||
|
||||
// Filter communities and expand only those that match the query
|
||||
return widget.communities.where((community) {
|
||||
final containsQueryInCommunity =
|
||||
community.name.toLowerCase().contains(_searchQuery.toLowerCase());
|
||||
final containsQueryInSpaces =
|
||||
community.spaces.any((space) => _containsQuery(space, _searchQuery.toLowerCase()));
|
||||
final containsQueryInSpaces = community.spaces.any((space) =>
|
||||
_containsQuery(space: space, query: _searchQuery.toLowerCase()));
|
||||
|
||||
return containsQueryInCommunity || containsQueryInSpaces;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
// Helper function to determine if any space or its children match the search query
|
||||
bool _containsQuery(SpaceModel space, String query) {
|
||||
bool _containsQuery({
|
||||
required SpaceModel space,
|
||||
required String query,
|
||||
}) {
|
||||
final matchesSpace = space.name.toLowerCase().contains(query);
|
||||
final matchesChildren =
|
||||
space.children.any((child) => _containsQuery(child, query)); // Recursive check for children
|
||||
final matchesChildren = space.children.any(
|
||||
(child) => _containsQuery(space: child, query: query),
|
||||
);
|
||||
|
||||
// If the space or any of its children match the query, expand this space
|
||||
if (matchesSpace || matchesChildren) {
|
||||
_selectedSpaceUuid = space.uuid;
|
||||
}
|
||||
@ -83,79 +81,32 @@ class _SidebarWidgetState extends State<SidebarWidget> {
|
||||
}
|
||||
|
||||
bool _isSpaceOrChildSelected(SpaceModel space) {
|
||||
// Return true if the current space or any of its child spaces is selected
|
||||
if (_selectedSpaceUuid == space.uuid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Recursively check if any child spaces match the query
|
||||
for (var child in space.children) {
|
||||
if (_isSpaceOrChildSelected(child)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
final isSpaceSelected = _selectedSpaceUuid == space.uuid;
|
||||
final anySubSpaceIsSelected = space.children.any(_isSpaceOrChildSelected);
|
||||
return isSpaceSelected || anySubSpaceIsSelected;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final filteredCommunities = _filterCommunities();
|
||||
final filteredCommunities = _filteredCommunities();
|
||||
|
||||
return Container(
|
||||
width: 300,
|
||||
decoration: subSectionContainerDecoration,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min, // Ensures the Column only takes necessary height
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Communities title with the add button
|
||||
Container(
|
||||
decoration: subSectionContainerDecoration,
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('Communities',
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
color: ColorsManager.blackColor,
|
||||
)),
|
||||
GestureDetector(
|
||||
onTap: () => _navigateToBlank(context),
|
||||
child: Container(
|
||||
width: 30,
|
||||
height: 30,
|
||||
decoration: const BoxDecoration(
|
||||
color: ColorsManager.whiteColors,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
Assets.roundedAddIcon,
|
||||
width: 24,
|
||||
height: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Search bar
|
||||
SidebarHeader(onAddCommunity: _onAddCommunity),
|
||||
CustomSearchBar(
|
||||
onSearchChanged: (query) {
|
||||
setState(() {
|
||||
_searchQuery = query;
|
||||
});
|
||||
},
|
||||
onSearchChanged: (query) => setState(() => _searchQuery = query),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Community list
|
||||
Expanded(
|
||||
child: ListView(
|
||||
children: filteredCommunities.map((community) {
|
||||
return _buildCommunityTile(context, community);
|
||||
}).toList(),
|
||||
children: filteredCommunities
|
||||
.map((community) => _buildCommunityTile(context, community))
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -163,18 +114,7 @@ class _SidebarWidgetState extends State<SidebarWidget> {
|
||||
);
|
||||
}
|
||||
|
||||
void _navigateToBlank(BuildContext context) {
|
||||
setState(() {
|
||||
_selectedId = '';
|
||||
});
|
||||
context.read<SpaceManagementBloc>().add(
|
||||
NewCommunityEvent(communities: widget.communities),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCommunityTile(BuildContext context, CommunityModel community) {
|
||||
bool hasChildren = community.spaces.isNotEmpty;
|
||||
|
||||
return CommunityTile(
|
||||
title: community.name,
|
||||
key: ValueKey(community.uuid),
|
||||
@ -183,7 +123,7 @@ class _SidebarWidgetState extends State<SidebarWidget> {
|
||||
onItemSelected: () {
|
||||
setState(() {
|
||||
_selectedId = community.uuid;
|
||||
_selectedSpaceUuid = null; // Update the selected community
|
||||
_selectedSpaceUuid = null;
|
||||
});
|
||||
|
||||
context.read<CenterBodyBloc>().add(CommunitySelectedEvent());
|
||||
@ -192,31 +132,32 @@ class _SidebarWidgetState extends State<SidebarWidget> {
|
||||
SelectCommunityEvent(selectedCommunity: community),
|
||||
);
|
||||
},
|
||||
onExpansionChanged: (String title, bool expanded) {
|
||||
_handleExpansionChange(community.uuid, expanded);
|
||||
},
|
||||
children: hasChildren
|
||||
? community.spaces
|
||||
.where((space) => (space.status != SpaceStatus.deleted ||
|
||||
space.status != SpaceStatus.parentDeleted))
|
||||
.map((space) => _buildSpaceTile(space, community))
|
||||
.toList()
|
||||
: null,
|
||||
onExpansionChanged: (title, expanded) {},
|
||||
children: community.spaces
|
||||
.where((space) {
|
||||
final isDeleted = space.status != SpaceStatus.deleted;
|
||||
final isParentDeleted = space.status != SpaceStatus.parentDeleted;
|
||||
return (isDeleted || isParentDeleted);
|
||||
})
|
||||
.map((space) => _buildSpaceTile(space: space, community: community))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSpaceTile(SpaceModel space, CommunityModel community, {int depth = 1}) {
|
||||
bool isExpandedSpace = _isSpaceOrChildSelected(space);
|
||||
Widget _buildSpaceTile({
|
||||
required SpaceModel space,
|
||||
required CommunityModel community,
|
||||
}) {
|
||||
final spaceIsExpanded = _isSpaceOrChildSelected(space);
|
||||
final isSelected = _selectedId == space.uuid;
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(left: depth * 16.0),
|
||||
padding: const EdgeInsetsDirectional.only(start: 16.0),
|
||||
child: SpaceTile(
|
||||
title: space.name,
|
||||
key: ValueKey(space.uuid),
|
||||
isSelected: _selectedId == space.uuid,
|
||||
initiallyExpanded: isExpandedSpace,
|
||||
onExpansionChanged: (bool expanded) {
|
||||
_handleExpansionChange(space.uuid ?? '', expanded);
|
||||
},
|
||||
isSelected: isSelected,
|
||||
initiallyExpanded: spaceIsExpanded,
|
||||
onExpansionChanged: (expanded) {},
|
||||
onItemSelected: () {
|
||||
setState(() {
|
||||
_selectedId = space.uuid;
|
||||
@ -227,11 +168,37 @@ class _SidebarWidgetState extends State<SidebarWidget> {
|
||||
SelectSpaceEvent(selectedCommunity: community, selectedSpace: space),
|
||||
);
|
||||
},
|
||||
children: space.children.isNotEmpty
|
||||
? space.children.map((childSpace) => _buildSpaceTile(childSpace, community)).toList()
|
||||
: [], // Recursively render child spaces if available
|
||||
));
|
||||
children: space.children
|
||||
.map(
|
||||
(childSpace) => _buildSpaceTile(
|
||||
space: childSpace,
|
||||
community: community,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _handleExpansionChange(String uuid, bool expanded) {}
|
||||
void _onAddCommunity() => _selectedId?.isNotEmpty ?? true
|
||||
? _clearSelection()
|
||||
: _showCreateCommunityDialog();
|
||||
|
||||
void _clearSelection() {
|
||||
setState(() => _selectedId = '');
|
||||
context.read<SpaceManagementBloc>().add(
|
||||
NewCommunityEvent(communities: widget.communities),
|
||||
);
|
||||
}
|
||||
|
||||
void _showCreateCommunityDialog() {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) => CreateCommunityDialog(
|
||||
isEditMode: false,
|
||||
existingCommunityNames: widget.communities.map((e) => e.name).toList(),
|
||||
onCreateCommunity: widget.onCreateCommunity,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/create_subspace_model/bloc/subspace_model_bloc.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/create_subspace_model/bloc/subspace_model_event.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/create_subspace_model/bloc/subspace_model_state.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/create_subspace_model/widgets/create_subspace_model_chips_box.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/create_subspace_model/widgets/create_subspace_model_footer_buttons.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
|
||||
class CreateSubSpaceModelDialog extends StatelessWidget {
|
||||
final bool isEdit;
|
||||
@ -14,212 +15,68 @@ class CreateSubSpaceModelDialog extends StatelessWidget {
|
||||
final List<SubspaceTemplateModel>? existingSubSpaces;
|
||||
final void Function(List<SubspaceTemplateModel> newSubspaces)? onUpdate;
|
||||
|
||||
const CreateSubSpaceModelDialog(
|
||||
{Key? key,
|
||||
const CreateSubSpaceModelDialog({
|
||||
required this.isEdit,
|
||||
required this.dialogTitle,
|
||||
this.existingSubSpaces,
|
||||
this.onUpdate})
|
||||
: super(key: key);
|
||||
this.onUpdate,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
final textController = TextEditingController();
|
||||
|
||||
return Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: BlocProvider(
|
||||
create: (_) {
|
||||
create: (context) {
|
||||
final bloc = SubSpaceModelBloc();
|
||||
if (existingSubSpaces != null) {
|
||||
for (var subSpace in existingSubSpaces!) {
|
||||
for (final subSpace in existingSubSpaces ?? []) {
|
||||
bloc.add(AddSubSpaceModel(subSpace));
|
||||
}
|
||||
}
|
||||
return bloc;
|
||||
},
|
||||
child: BlocBuilder<SubSpaceModelBloc, SubSpaceModelState>(
|
||||
builder: (context, state) {
|
||||
return Container(
|
||||
builder: (context, state) => Container(
|
||||
color: ColorsManager.whiteColors,
|
||||
child: SizedBox(
|
||||
width: screenWidth * 0.3,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
dialogTitle,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.headlineLarge
|
||||
?.copyWith(color: ColorsManager.blackColor),
|
||||
style: context.textTheme.headlineLarge?.copyWith(
|
||||
color: ColorsManager.blackColor,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Container(
|
||||
width: screenWidth * 0.35,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 10.0, horizontal: 16.0),
|
||||
decoration: BoxDecoration(
|
||||
color: ColorsManager.boxColor,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Wrap(
|
||||
spacing: 8.0,
|
||||
runSpacing: 8.0,
|
||||
children: [
|
||||
...state.subSpaces.asMap().entries.map(
|
||||
(entry) {
|
||||
final index = entry.key;
|
||||
final subSpace = entry.value;
|
||||
|
||||
final lowerName =
|
||||
subSpace.subspaceName.toLowerCase();
|
||||
|
||||
final duplicateIndices = state.subSpaces
|
||||
.asMap()
|
||||
.entries
|
||||
.where((e) =>
|
||||
e.value.subspaceName.toLowerCase() ==
|
||||
lowerName)
|
||||
.map((e) => e.key)
|
||||
.toList();
|
||||
final isDuplicate =
|
||||
duplicateIndices.length > 1 &&
|
||||
duplicateIndices.indexOf(index) != 0;
|
||||
|
||||
return Chip(
|
||||
label: Text(subSpace.subspaceName,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall
|
||||
?.copyWith(
|
||||
color: ColorsManager.spaceColor,
|
||||
)),
|
||||
backgroundColor: ColorsManager.whiteColors,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
side: BorderSide(
|
||||
color: isDuplicate
|
||||
? ColorsManager.red
|
||||
: ColorsManager.transparentColor,
|
||||
width: 0,
|
||||
),
|
||||
),
|
||||
deleteIcon: Container(
|
||||
width: 24,
|
||||
height: 24,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: ColorsManager.lightGrayColor,
|
||||
width: 1.5,
|
||||
),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.close,
|
||||
size: 16,
|
||||
color: ColorsManager.lightGrayColor,
|
||||
),
|
||||
),
|
||||
onDeleted: () => context
|
||||
.read<SubSpaceModelBloc>()
|
||||
.add(RemoveSubSpaceModel(subSpace)),
|
||||
);
|
||||
},
|
||||
),
|
||||
SizedBox(
|
||||
width: 200,
|
||||
child: TextField(
|
||||
controller: textController,
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
hintText: state.subSpaces.isEmpty
|
||||
? 'Please enter the name'
|
||||
: null,
|
||||
hintStyle: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
color: ColorsManager
|
||||
.lightGrayColor)),
|
||||
onSubmitted: (value) {
|
||||
if (value.trim().isNotEmpty) {
|
||||
context.read<SubSpaceModelBloc>().add(
|
||||
AddSubSpaceModel(
|
||||
SubspaceTemplateModel(
|
||||
subspaceName: value.trim(),
|
||||
disabled: false)));
|
||||
textController.clear();
|
||||
}
|
||||
},
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium
|
||||
?.copyWith(
|
||||
color: ColorsManager.blackColor)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
CreateSubspaceModelChipsBox(subSpaces: state.subSpaces),
|
||||
if (state.errorMessage.isNotEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16.0),
|
||||
child: Text(state.errorMessage,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall
|
||||
?.copyWith(
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: Text(
|
||||
state.errorMessage,
|
||||
style: context.textTheme.bodySmall?.copyWith(
|
||||
color: ColorsManager.red,
|
||||
)),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CancelButton(
|
||||
label: 'Cancel',
|
||||
onPressed: () async {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: DefaultButton(
|
||||
onPressed: (state.errorMessage.isNotEmpty)
|
||||
? null
|
||||
: () async {
|
||||
final subSpaces = context
|
||||
.read<SubSpaceModelBloc>()
|
||||
.state
|
||||
.subSpaces;
|
||||
Navigator.of(context).pop();
|
||||
if (onUpdate != null) {
|
||||
onUpdate!(subSpaces);
|
||||
}
|
||||
},
|
||||
backgroundColor: ColorsManager.secondaryColor,
|
||||
borderRadius: 10,
|
||||
foregroundColor: state.errorMessage.isNotEmpty
|
||||
? ColorsManager.whiteColorsWithOpacity
|
||||
: ColorsManager.whiteColors,
|
||||
child: const Text('OK'),
|
||||
),
|
||||
CreateSubspaceModelFooterButtons(
|
||||
onUpdate: onUpdate,
|
||||
errorMessage: state.errorMessage,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
));
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,64 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/create_subspace_model/widgets/subspace_chip.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/create_subspace_model/widgets/subspaces_textfield.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class CreateSubspaceModelChipsBox extends StatelessWidget {
|
||||
const CreateSubspaceModelChipsBox({
|
||||
required this.subSpaces,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final List<SubspaceTemplateModel> subSpaces;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
|
||||
return Container(
|
||||
width: screenWidth * 0.35,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 10,
|
||||
horizontal: 16,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: ColorsManager.boxColor,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
alignment: WrapAlignment.start,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
...subSpaces.asMap().entries.map(
|
||||
(entry) {
|
||||
final index = entry.key;
|
||||
final subSpace = entry.value;
|
||||
|
||||
final lowerName = subSpace.subspaceName.toLowerCase();
|
||||
|
||||
final duplicateIndices = subSpaces
|
||||
.asMap()
|
||||
.entries
|
||||
.where((e) => e.value.subspaceName.toLowerCase() == lowerName)
|
||||
.map((e) => e.key)
|
||||
.toList();
|
||||
final isDuplicate = duplicateIndices.length > 1 &&
|
||||
duplicateIndices.indexOf(index) != 0;
|
||||
|
||||
return SubspaceChip(
|
||||
subSpace: subSpace,
|
||||
isDuplicate: isDuplicate,
|
||||
);
|
||||
},
|
||||
),
|
||||
SubspacesTextfield(
|
||||
hintText: subSpaces.isEmpty ? 'Please enter the name' : null,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/create_subspace_model/bloc/subspace_model_bloc.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class CreateSubspaceModelFooterButtons extends StatelessWidget {
|
||||
const CreateSubspaceModelFooterButtons({
|
||||
required this.onUpdate,
|
||||
required this.errorMessage,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final void Function(List<SubspaceTemplateModel> newSubspaces)? onUpdate;
|
||||
final String errorMessage;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CancelButton(
|
||||
label: 'Cancel',
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: DefaultButton(
|
||||
onPressed: errorMessage.isEmpty
|
||||
? () {
|
||||
Navigator.of(context).pop();
|
||||
if (onUpdate != null) {
|
||||
final subSpaces =
|
||||
context.read<SubSpaceModelBloc>().state.subSpaces;
|
||||
onUpdate!(subSpaces);
|
||||
}
|
||||
}
|
||||
: null,
|
||||
backgroundColor: ColorsManager.secondaryColor,
|
||||
borderRadius: 10,
|
||||
foregroundColor: errorMessage.isNotEmpty
|
||||
? ColorsManager.whiteColorsWithOpacity
|
||||
: ColorsManager.whiteColors,
|
||||
child: const Text('OK'),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/create_subspace_model/bloc/subspace_model_bloc.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/create_subspace_model/bloc/subspace_model_event.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
|
||||
class SubspaceChip extends StatelessWidget {
|
||||
const SubspaceChip({
|
||||
required this.subSpace,
|
||||
required this.isDuplicate,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final SubspaceTemplateModel subSpace;
|
||||
final bool isDuplicate;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Chip(
|
||||
label: Text(
|
||||
subSpace.subspaceName,
|
||||
style: context.textTheme.bodySmall?.copyWith(
|
||||
color: isDuplicate ? ColorsManager.red : ColorsManager.spaceColor,
|
||||
),
|
||||
),
|
||||
backgroundColor: ColorsManager.whiteColors,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
side: BorderSide(
|
||||
color: isDuplicate ? ColorsManager.red : ColorsManager.transparentColor,
|
||||
width: 0,
|
||||
),
|
||||
),
|
||||
deleteIcon: Container(
|
||||
padding: const EdgeInsetsDirectional.all(1),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: ColorsManager.lightGrayColor,
|
||||
width: 1.5,
|
||||
),
|
||||
),
|
||||
child: const FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
child: Icon(
|
||||
Icons.close,
|
||||
color: ColorsManager.lightGrayColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
onDeleted: () => context.read<SubSpaceModelBloc>().add(
|
||||
RemoveSubSpaceModel(subSpace),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/create_subspace_model/bloc/subspace_model_bloc.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/create_subspace_model/bloc/subspace_model_event.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
|
||||
class SubspacesTextfield extends StatefulWidget {
|
||||
const SubspacesTextfield({
|
||||
required this.hintText,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final String? hintText;
|
||||
|
||||
@override
|
||||
State<SubspacesTextfield> createState() => _SubspacesTextfieldState();
|
||||
}
|
||||
|
||||
class _SubspacesTextfieldState extends State<SubspacesTextfield> {
|
||||
late final TextEditingController _controller;
|
||||
@override
|
||||
void initState() {
|
||||
_controller = TextEditingController();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
width: 100,
|
||||
child: TextField(
|
||||
controller: _controller,
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
hintText: widget.hintText,
|
||||
hintStyle: context.textTheme.bodySmall?.copyWith(
|
||||
color: ColorsManager.lightGrayColor,
|
||||
),
|
||||
),
|
||||
onSubmitted: (value) {
|
||||
final trimmedValue = value.trim();
|
||||
if (trimmedValue.isNotEmpty) {
|
||||
context.read<SubSpaceModelBloc>().add(
|
||||
AddSubSpaceModel(
|
||||
SubspaceTemplateModel(
|
||||
subspaceName: trimmedValue,
|
||||
disabled: false,
|
||||
),
|
||||
),
|
||||
);
|
||||
_controller.clear();
|
||||
}
|
||||
},
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
color: ColorsManager.blackColor,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -321,13 +321,14 @@ class DevicesManagementApi {
|
||||
Future<bool> factoryReset(FactoryResetModel factoryReset, String uuid) async {
|
||||
try {
|
||||
final response = await HTTPService().post(
|
||||
path: ApiEndpoints.factoryReset.replaceAll('{deviceUuid}', uuid),
|
||||
path: ApiEndpoints.factoryReset,
|
||||
body: factoryReset.toMap(),
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
return json['success'] ?? false;
|
||||
},
|
||||
);
|
||||
|
||||
return response;
|
||||
} catch (e) {
|
||||
debugPrint('Error fetching $e');
|
||||
|
@ -13,8 +13,7 @@ class Assets {
|
||||
static const String rightLine = "assets/images/right_line.png";
|
||||
static const String google = "assets/images/google.svg";
|
||||
static const String facebook = "assets/images/facebook.svg";
|
||||
static const String invisiblePassword =
|
||||
"assets/images/Password_invisible.svg";
|
||||
static const String invisiblePassword = "assets/images/Password_invisible.svg";
|
||||
static const String visiblePassword = "assets/images/password_visible.svg";
|
||||
static const String accessIcon = "assets/images/access_icon.svg";
|
||||
static const String spaseManagementIcon =
|
||||
@ -31,8 +30,7 @@ class Assets {
|
||||
static const String emptyTable = "assets/images/empty_table.svg";
|
||||
|
||||
// General assets
|
||||
static const String motionlessDetection =
|
||||
"assets/icons/motionless_detection.svg";
|
||||
static const String motionlessDetection = "assets/icons/motionless_detection.svg";
|
||||
static const String acHeating = "assets/icons/ac_heating.svg";
|
||||
static const String acPowerOff = "assets/icons/ac_power_off.svg";
|
||||
static const String acFanMiddle = "assets/icons/ac_fan_middle.svg";
|
||||
@ -69,22 +67,19 @@ class Assets {
|
||||
"assets/icons/automation_functions/temp_password_unlock.svg";
|
||||
static const String doorlockNormalOpen =
|
||||
"assets/icons/automation_functions/doorlock_normal_open.svg";
|
||||
static const String doorbell =
|
||||
"assets/icons/automation_functions/doorbell.svg";
|
||||
static const String doorbell = "assets/icons/automation_functions/doorbell.svg";
|
||||
static const String remoteUnlockViaApp =
|
||||
"assets/icons/automation_functions/remote_unlock_via_app.svg";
|
||||
static const String doubleLock =
|
||||
"assets/icons/automation_functions/double_lock.svg";
|
||||
static const String selfTestResult =
|
||||
"assets/icons/automation_functions/self_test_result.svg";
|
||||
static const String lockAlarm =
|
||||
"assets/icons/automation_functions/lock_alarm.svg";
|
||||
static const String lockAlarm = "assets/icons/automation_functions/lock_alarm.svg";
|
||||
static const String presenceState =
|
||||
"assets/icons/automation_functions/presence_state.svg";
|
||||
static const String currentTemp =
|
||||
"assets/icons/automation_functions/current_temp.svg";
|
||||
static const String presence =
|
||||
"assets/icons/automation_functions/presence.svg";
|
||||
static const String presence = "assets/icons/automation_functions/presence.svg";
|
||||
static const String residualElectricity =
|
||||
"assets/icons/automation_functions/residual_electricity.svg";
|
||||
static const String hijackAlarm =
|
||||
@ -101,15 +96,12 @@ class Assets {
|
||||
|
||||
// Presence Sensor Assets
|
||||
static const String sensorMotionIcon = "assets/icons/sensor_motion_ic.svg";
|
||||
static const String sensorPresenceIcon =
|
||||
"assets/icons/sensor_presence_ic.svg";
|
||||
static const String sensorPresenceIcon = "assets/icons/sensor_presence_ic.svg";
|
||||
static const String sensorVacantIcon = "assets/icons/sensor_vacant_ic.svg";
|
||||
static const String illuminanceRecordIcon =
|
||||
"assets/icons/illuminance_record_ic.svg";
|
||||
static const String presenceRecordIcon =
|
||||
"assets/icons/presence_record_ic.svg";
|
||||
static const String helpDescriptionIcon =
|
||||
"assets/icons/help_description_ic.svg";
|
||||
static const String presenceRecordIcon = "assets/icons/presence_record_ic.svg";
|
||||
static const String helpDescriptionIcon = "assets/icons/help_description_ic.svg";
|
||||
|
||||
static const String lightPulp = "assets/icons/light_pulb.svg";
|
||||
static const String acDevice = "assets/icons/ac_device.svg";
|
||||
@ -159,12 +151,10 @@ class Assets {
|
||||
static const String unit = 'assets/icons/unit_icon.svg';
|
||||
static const String villa = 'assets/icons/villa_icon.svg';
|
||||
static const String iconEdit = 'assets/icons/icon_edit_icon.svg';
|
||||
static const String textFieldSearch =
|
||||
'assets/icons/textfield_search_icon.svg';
|
||||
static const String textFieldSearch = 'assets/icons/textfield_search_icon.svg';
|
||||
static const String roundedAddIcon = 'assets/icons/rounded_add_icon.svg';
|
||||
static const String addIcon = 'assets/icons/add_icon.svg';
|
||||
static const String smartThermostatIcon =
|
||||
'assets/icons/smart_thermostat_icon.svg';
|
||||
static const String smartThermostatIcon = 'assets/icons/smart_thermostat_icon.svg';
|
||||
static const String smartLightIcon = 'assets/icons/smart_light_icon.svg';
|
||||
static const String presenceSensor = 'assets/icons/presence_sensor.svg';
|
||||
static const String Gang3SwitchIcon = 'assets/icons/3_Gang_switch_icon.svg';
|
||||
@ -212,8 +202,7 @@ class Assets {
|
||||
//assets/icons/water_leak_normal.svg
|
||||
static const String waterLeakNormal = 'assets/icons/water_leak_normal.svg';
|
||||
//assets/icons/water_leak_detected.svg
|
||||
static const String waterLeakDetected =
|
||||
'assets/icons/water_leak_detected.svg';
|
||||
static const String waterLeakDetected = 'assets/icons/water_leak_detected.svg';
|
||||
|
||||
//assets/icons/automation_records.svg
|
||||
static const String automationRecords = 'assets/icons/automation_records.svg';
|
||||
@ -284,16 +273,13 @@ class Assets {
|
||||
"assets/icons/functions_icons/sensitivity.svg";
|
||||
static const String assetsSensitivityOperationIcon =
|
||||
"assets/icons/functions_icons/sesitivity_operation_icon.svg";
|
||||
static const String assetsAcPower =
|
||||
"assets/icons/functions_icons/ac_power.svg";
|
||||
static const String assetsAcPower = "assets/icons/functions_icons/ac_power.svg";
|
||||
static const String assetsAcPowerOFF =
|
||||
"assets/icons/functions_icons/ac_power_off.svg";
|
||||
static const String assetsChildLock =
|
||||
"assets/icons/functions_icons/child_lock.svg";
|
||||
static const String assetsFreezing =
|
||||
"assets/icons/functions_icons/freezing.svg";
|
||||
static const String assetsFanSpeed =
|
||||
"assets/icons/functions_icons/fan_speed.svg";
|
||||
static const String assetsFreezing = "assets/icons/functions_icons/freezing.svg";
|
||||
static const String assetsFanSpeed = "assets/icons/functions_icons/fan_speed.svg";
|
||||
static const String assetsAcCooling =
|
||||
"assets/icons/functions_icons/ac_cooling.svg";
|
||||
static const String assetsAcHeating =
|
||||
@ -302,8 +288,7 @@ class Assets {
|
||||
"assets/icons/functions_icons/celsius_degrees.svg";
|
||||
static const String assetsTempreture =
|
||||
"assets/icons/functions_icons/tempreture.svg";
|
||||
static const String assetsAcFanLow =
|
||||
"assets/icons/functions_icons/ac_fan_low.svg";
|
||||
static const String assetsAcFanLow = "assets/icons/functions_icons/ac_fan_low.svg";
|
||||
static const String assetsAcFanMiddle =
|
||||
"assets/icons/functions_icons/ac_fan_middle.svg";
|
||||
static const String assetsAcFanHigh =
|
||||
@ -322,8 +307,7 @@ class Assets {
|
||||
"assets/icons/functions_icons/far_detection.svg";
|
||||
static const String assetsFarDetectionFunction =
|
||||
"assets/icons/functions_icons/far_detection_function.svg";
|
||||
static const String assetsIndicator =
|
||||
"assets/icons/functions_icons/indicator.svg";
|
||||
static const String assetsIndicator = "assets/icons/functions_icons/indicator.svg";
|
||||
static const String assetsMotionDetection =
|
||||
"assets/icons/functions_icons/motion_detection.svg";
|
||||
static const String assetsMotionlessDetection =
|
||||
@ -336,8 +320,7 @@ class Assets {
|
||||
"assets/icons/functions_icons/master_state.svg";
|
||||
static const String assetsSwitchAlarmSound =
|
||||
"assets/icons/functions_icons/switch_alarm_sound.svg";
|
||||
static const String assetsResetOff =
|
||||
"assets/icons/functions_icons/reset_off.svg";
|
||||
static const String assetsResetOff = "assets/icons/functions_icons/reset_off.svg";
|
||||
|
||||
// Assets for automation_functions
|
||||
static const String assetsCardUnlock =
|
||||
@ -381,14 +364,12 @@ class Assets {
|
||||
static const String activeUser = 'assets/icons/active_user.svg';
|
||||
static const String deActiveUser = 'assets/icons/deactive_user.svg';
|
||||
static const String invitedIcon = 'assets/icons/invited_icon.svg';
|
||||
static const String rectangleCheckBox =
|
||||
'assets/icons/rectangle_check_box.png';
|
||||
static const String rectangleCheckBox = 'assets/icons/rectangle_check_box.png';
|
||||
static const String CheckBoxChecked = 'assets/icons/box_checked.png';
|
||||
static const String emptyBox = 'assets/icons/empty_box.png';
|
||||
static const String completeProcessIcon =
|
||||
'assets/icons/compleate_process_icon.svg';
|
||||
static const String currentProcessIcon =
|
||||
'assets/icons/current_process_icon.svg';
|
||||
static const String currentProcessIcon = 'assets/icons/current_process_icon.svg';
|
||||
static const String uncomplete_ProcessIcon =
|
||||
'assets/icons/uncompleate_process_icon.svg';
|
||||
static const String wrongProcessIcon = 'assets/icons/wrong_process_icon.svg';
|
||||
@ -409,11 +390,9 @@ class Assets {
|
||||
static const String successIcon = 'assets/icons/success_icon.svg';
|
||||
static const String spaceLocationIcon = 'assets/icons/spaseLocationIcon.svg';
|
||||
static const String scenesPlayIcon = 'assets/icons/scenesPlayIcon.png';
|
||||
static const String scenesPlayIconCheck =
|
||||
'assets/icons/scenesPlayIconCheck.png';
|
||||
static const String scenesPlayIconCheck = 'assets/icons/scenesPlayIconCheck.png';
|
||||
static const String presenceStateIcon = 'assets/icons/presence_state.svg';
|
||||
static const String currentDistanceIcon =
|
||||
'assets/icons/current_distance_icon.svg';
|
||||
static const String currentDistanceIcon = 'assets/icons/current_distance_icon.svg';
|
||||
|
||||
static const String farDetectionIcon = 'assets/icons/far_detection_icon.svg';
|
||||
static const String motionDetectionSensitivityIcon =
|
||||
@ -423,7 +402,8 @@ class Assets {
|
||||
'assets/icons/motionless_detection_sensitivity_icon.svg';
|
||||
|
||||
static const String IndicatorIcon = 'assets/icons/Indicator_icon.svg';
|
||||
static const String motionDetectionSensitivityValueIcon = 'assets/icons/motion_detection_sensitivity_value_icon.svg';
|
||||
static const String motionDetectionSensitivityValueIcon =
|
||||
'assets/icons/motion_detection_sensitivity_value_icon.svg';
|
||||
static const String presenceTimeIcon = 'assets/icons/presence_time_icon.svg';
|
||||
static const String IlluminanceIcon = 'assets/icons/Illuminance_icon.svg';
|
||||
static const String gear = 'assets/icons/gear.svg';
|
||||
@ -445,7 +425,8 @@ class Assets {
|
||||
static const String motionMeter = 'assets/icons/motion_meter.svg';
|
||||
static const String spatialStaticValue = 'assets/icons/spatial_static_value.svg';
|
||||
static const String spatialMotionValue = 'assets/icons/spatial_motion_value.svg';
|
||||
static const String presenceJudgementThrshold = 'assets/icons/presence_judgement_threshold.svg';
|
||||
static const String presenceJudgementThrshold =
|
||||
'assets/icons/presence_judgement_threshold.svg';
|
||||
static const String spaceType = 'assets/icons/space_type.svg';
|
||||
static const String sportsPara = 'assets/icons/sports_para.svg';
|
||||
static const String sensitivityFeature1 = 'assets/icons/sensitivity_feature_1.svg';
|
||||
@ -457,4 +438,5 @@ class Assets {
|
||||
static const String sensitivityFeature7 = 'assets/icons/sensitivity_feature_7.svg';
|
||||
static const String sensitivityFeature8 = 'assets/icons/sensitivity_feature_8.svg';
|
||||
static const String sensitivityFeature9 = 'assets/icons/sensitivity_feature_9.svg';
|
||||
static const String deviceTagIcon = 'assets/icons/device_tag_ic.svg';
|
||||
}
|
||||
|
Reference in New Issue
Block a user