mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 07:07:19 +00:00
@ -88,32 +88,31 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||
);
|
||||
}),
|
||||
rightBody: const NavigateHomeGridView(),
|
||||
scaffoldBody: CreateNewRoutineView(),
|
||||
// BlocBuilder<SwitchTabsBloc, SwitchTabsState>(
|
||||
// builder: (context, state) {
|
||||
// if (state is SelectedTabState && state.selectedTab) {
|
||||
// return const RoutinesView();
|
||||
// }
|
||||
// if (state is ShowCreateRoutineState && state.showCreateRoutine) {
|
||||
// return const CreateNewRoutineView();
|
||||
// }
|
||||
scaffoldBody: BlocBuilder<SwitchTabsBloc, SwitchTabsState>(
|
||||
builder: (context, state) {
|
||||
if (state is SelectedTabState && state.selectedTab) {
|
||||
return const RoutinesView();
|
||||
}
|
||||
if (state is ShowCreateRoutineState && state.showCreateRoutine) {
|
||||
return const CreateNewRoutineView();
|
||||
}
|
||||
|
||||
// return BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
|
||||
// builder: (context, deviceState) {
|
||||
// if (deviceState is DeviceManagementLoading) {
|
||||
// return const Center(child: CircularProgressIndicator());
|
||||
// } else if (deviceState is DeviceManagementLoaded ||
|
||||
// deviceState is DeviceManagementFiltered) {
|
||||
// final devices = (deviceState as dynamic).devices ??
|
||||
// (deviceState as DeviceManagementFiltered).filteredDevices;
|
||||
return BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
|
||||
builder: (context, deviceState) {
|
||||
if (deviceState is DeviceManagementLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
} else if (deviceState is DeviceManagementLoaded ||
|
||||
deviceState is DeviceManagementFiltered) {
|
||||
final devices = (deviceState as dynamic).devices ??
|
||||
(deviceState as DeviceManagementFiltered).filteredDevices;
|
||||
|
||||
// return DeviceManagementBody(devices: devices);
|
||||
// } else {
|
||||
// return const Center(child: Text('Error fetching Devices'));
|
||||
// }
|
||||
// },
|
||||
// );
|
||||
// }),
|
||||
return DeviceManagementBody(devices: devices);
|
||||
} else {
|
||||
return const Center(child: Text('Error fetching Devices'));
|
||||
}
|
||||
},
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -2,10 +2,7 @@ import 'dart:async';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_event.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_state.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_automation_model.dart';
|
||||
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
||||
import 'package:syncrow_web/utils/navigation_service.dart';
|
||||
|
||||
class EffectPeriodBloc extends Bloc<EffectPeriodEvent, EffectPeriodState> {
|
||||
final daysMap = {
|
||||
@ -52,10 +49,6 @@ class EffectPeriodBloc extends Bloc<EffectPeriodEvent, EffectPeriodState> {
|
||||
break;
|
||||
}
|
||||
|
||||
BlocProvider.of<RoutineBloc>(NavigationService.navigatorKey.currentContext!).add(
|
||||
EffectiveTimePeriodEvent(
|
||||
EffectiveTime(start: startTime, end: endTime, loops: state.selectedDaysBinary)));
|
||||
|
||||
emit(state.copyWith(
|
||||
selectedPeriod: event.period, customStartTime: startTime, customEndTime: endTime));
|
||||
}
|
||||
@ -70,12 +63,6 @@ class EffectPeriodBloc extends Bloc<EffectPeriodEvent, EffectPeriodState> {
|
||||
}
|
||||
final newDaysBinary = daysList.join();
|
||||
emit(state.copyWith(selectedDaysBinary: newDaysBinary));
|
||||
|
||||
BlocProvider.of<RoutineBloc>(NavigationService.navigatorKey.currentContext!).add(
|
||||
EffectiveTimePeriodEvent(EffectiveTime(
|
||||
start: state.customStartTime ?? '00:00',
|
||||
end: state.customEndTime ?? '23:59',
|
||||
loops: newDaysBinary)));
|
||||
}
|
||||
|
||||
void _onSetCustomTime(SetCustomTime event, Emitter<EffectPeriodState> emit) {
|
||||
@ -96,10 +83,6 @@ class EffectPeriodBloc extends Bloc<EffectPeriodEvent, EffectPeriodState> {
|
||||
|
||||
emit(
|
||||
state.copyWith(customStartTime: startTime, customEndTime: endTime, selectedPeriod: period));
|
||||
|
||||
BlocProvider.of<RoutineBloc>(NavigationService.navigatorKey.currentContext!).add(
|
||||
EffectiveTimePeriodEvent(
|
||||
EffectiveTime(start: startTime, end: endTime, loops: state.selectedDaysBinary)));
|
||||
}
|
||||
|
||||
void _onResetEffectivePeriod(ResetEffectivePeriod event, Emitter<EffectPeriodState> emit) {
|
||||
@ -108,9 +91,6 @@ class EffectPeriodBloc extends Bloc<EffectPeriodEvent, EffectPeriodState> {
|
||||
customStartTime: '00:00',
|
||||
customEndTime: '23:59',
|
||||
selectedDaysBinary: '1111111'));
|
||||
|
||||
BlocProvider.of<RoutineBloc>(NavigationService.navigatorKey.currentContext!).add(
|
||||
EffectiveTimePeriodEvent(EffectiveTime(start: '00:00', end: '23:59', loops: '1111111')));
|
||||
}
|
||||
|
||||
void _onResetDays(ResetDays event, Emitter<EffectPeriodState> emit) {
|
||||
|
@ -15,9 +15,6 @@ part 'routine_state.dart';
|
||||
const spaceId = '25c96044-fadf-44bb-93c7-3c079e527ce6';
|
||||
|
||||
class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
// bool isAutomation = false;
|
||||
// bool isTabToRun = false;
|
||||
|
||||
RoutineBloc() : super(const RoutineState()) {
|
||||
on<AddToIfContainer>(_onAddToIfContainer);
|
||||
on<AddToThenContainer>(_onAddToThenContainer);
|
||||
@ -32,29 +29,37 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
on<EffectiveTimePeriodEvent>(_onEffectiveTimeEvent);
|
||||
on<CreateAutomationEvent>(_onCreateAutomation);
|
||||
on<SetRoutineName>(_onSetRoutineName);
|
||||
on<ResetRoutineState>(_onResetRoutineState);
|
||||
// on<RemoveFunction>(_onRemoveFunction);
|
||||
// on<ClearFunctions>(_onClearFunctions);
|
||||
}
|
||||
|
||||
void _onAddToIfContainer(AddToIfContainer event, Emitter<RoutineState> emit) {
|
||||
final updatedIfItems = List<Map<String, dynamic>>.from(state.ifItems)
|
||||
..add(event.item);
|
||||
if (event.isTabToRun) {
|
||||
emit(state.copyWith(
|
||||
ifItems: updatedIfItems, isTabToRun: true, isAutomation: false));
|
||||
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']);
|
||||
// Replace the map if the index is valid
|
||||
if (index != -1) {
|
||||
updatedIfItems[index] = event.item;
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
ifItems: updatedIfItems, isTabToRun: false, isAutomation: true));
|
||||
updatedIfItems.add(event.item);
|
||||
}
|
||||
|
||||
if (event.isTabToRun) {
|
||||
emit(state.copyWith(ifItems: updatedIfItems, isTabToRun: true, isAutomation: false));
|
||||
} else {
|
||||
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;
|
||||
@ -65,21 +70,38 @@ 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;
|
||||
|
||||
final currentSelectedFunctions =
|
||||
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
|
||||
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)) {
|
||||
currentSelectedFunctions[event.uniqueCustomId] =
|
||||
List.from(currentSelectedFunctions[event.uniqueCustomId]!)
|
||||
..addAll(event.functions);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
@ -88,8 +110,7 @@ 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));
|
||||
|
||||
try {
|
||||
@ -108,16 +129,24 @@ 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));
|
||||
|
||||
try {
|
||||
final automations = await SceneApi.getAutomationByUnitId(event.unitId);
|
||||
emit(state.copyWith(
|
||||
automations: automations,
|
||||
isLoading: false,
|
||||
));
|
||||
if (automations.isNotEmpty) {
|
||||
emit(state.copyWith(
|
||||
automations: automations,
|
||||
isLoading: false,
|
||||
));
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
loadAutomationErrorMessage: 'Failed to load automations',
|
||||
errorMessage: '',
|
||||
loadScenesErrorMessage: '',
|
||||
));
|
||||
}
|
||||
} catch (e) {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
@ -128,15 +157,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));
|
||||
}
|
||||
|
||||
@ -145,8 +173,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
return actions.first['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)) {
|
||||
@ -159,50 +186,54 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
|
||||
emit(state.copyWith(isLoading: true));
|
||||
|
||||
final actions = state.thenItems
|
||||
.map((item) {
|
||||
final functions =
|
||||
state.selectedFunctions[item['uniqueCustomId']] ?? [];
|
||||
if (functions.isEmpty) return null;
|
||||
|
||||
final function = functions.first;
|
||||
if (item['deviceId'] == 'delay') {
|
||||
return CreateSceneAction(
|
||||
entityId: function.entityId,
|
||||
actionExecutor: 'delay',
|
||||
executorProperty: CreateSceneExecutorProperty(
|
||||
functionCode: '',
|
||||
functionValue: '',
|
||||
delaySeconds: function.value,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final actions = state.thenItems.expand((item) {
|
||||
final functions = state.selectedFunctions[item['uniqueCustomId']] ?? [];
|
||||
return functions.map((function) {
|
||||
if (function.functionCode == 'automation') {
|
||||
return CreateSceneAction(
|
||||
entityId: function.entityId,
|
||||
actionExecutor: 'device_issue',
|
||||
actionExecutor: function.value,
|
||||
executorProperty: null,
|
||||
);
|
||||
}
|
||||
|
||||
if (item['deviceId'] == 'delay') {
|
||||
return CreateSceneAction(
|
||||
entityId: function.entityId,
|
||||
actionExecutor: 'delay',
|
||||
executorProperty: CreateSceneExecutorProperty(
|
||||
functionCode: function.functionCode.toString(),
|
||||
functionValue: function.value,
|
||||
delaySeconds: 0,
|
||||
functionCode: '',
|
||||
functionValue: '',
|
||||
delaySeconds: int.tryParse(function.value.toString()) ?? 0,
|
||||
),
|
||||
);
|
||||
})
|
||||
.whereType<CreateSceneAction>()
|
||||
.toList();
|
||||
}
|
||||
|
||||
return CreateSceneAction(
|
||||
entityId: function.entityId,
|
||||
actionExecutor: 'device_issue',
|
||||
executorProperty: CreateSceneExecutorProperty(
|
||||
functionCode: function.functionCode,
|
||||
functionValue: function.value,
|
||||
delaySeconds: 0,
|
||||
),
|
||||
);
|
||||
});
|
||||
}).toList();
|
||||
|
||||
final createSceneModel = CreateSceneModel(
|
||||
spaceUuid: spaceId,
|
||||
iconId: state.selectedIcon ?? '',
|
||||
showInDevice: true,
|
||||
sceneName: state.routineName ?? '',
|
||||
sceneName: state.routineName!,
|
||||
decisionExpr: 'and',
|
||||
actions: actions,
|
||||
);
|
||||
|
||||
final result = await SceneApi.createScene(createSceneModel);
|
||||
if (result['success']) {
|
||||
emit(const RoutineState());
|
||||
emit(_resetState());
|
||||
add(const LoadScenes(spaceId));
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
@ -212,13 +243,12 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
} catch (e) {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: e.toString(),
|
||||
errorMessage: 'Something went wrong',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onCreateAutomation(
|
||||
CreateAutomationEvent event, Emitter<RoutineState> emit) async {
|
||||
Future<void> _onCreateAutomation(CreateAutomationEvent event, Emitter<RoutineState> emit) async {
|
||||
try {
|
||||
if (state.routineName == null || state.routineName!.isEmpty) {
|
||||
emit(state.copyWith(
|
||||
@ -229,26 +259,24 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
|
||||
emit(state.copyWith(isLoading: true));
|
||||
|
||||
final conditions = state.ifItems
|
||||
.map((item) {
|
||||
final functions =
|
||||
state.selectedFunctions[item['uniqueCustomId']] ?? [];
|
||||
if (functions.isEmpty) return null;
|
||||
|
||||
final function = functions.first;
|
||||
return CreateCondition(
|
||||
code: state.ifItems.indexOf(item) + 1,
|
||||
entityId: function.entityId,
|
||||
entityType: 'device_report',
|
||||
expr: ConditionExpr(
|
||||
statusCode: function.functionCode,
|
||||
comparator: function.condition ?? '==',
|
||||
statusValue: function.value,
|
||||
),
|
||||
);
|
||||
})
|
||||
.whereType<CreateCondition>()
|
||||
.toList();
|
||||
final conditions = state.ifItems.expand((item) {
|
||||
final functions = state.selectedFunctions[item['uniqueCustomId']] ?? [];
|
||||
return functions.map((function) {
|
||||
return Condition(
|
||||
code: state.selectedFunctions[item['uniqueCustomId']]!.indexOf(
|
||||
function,
|
||||
) +
|
||||
1,
|
||||
entityId: function.entityId,
|
||||
entityType: 'device_report',
|
||||
expr: ConditionExpr(
|
||||
statusCode: function.functionCode,
|
||||
comparator: function.condition ?? '==',
|
||||
statusValue: function.value,
|
||||
),
|
||||
);
|
||||
});
|
||||
}).toList();
|
||||
|
||||
if (conditions.isEmpty) {
|
||||
emit(state.copyWith(
|
||||
@ -258,61 +286,54 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
return;
|
||||
}
|
||||
|
||||
final actions = state.thenItems.expand((item) {
|
||||
final functions = state.selectedFunctions[item['uniqueCustomId']] ?? [];
|
||||
return functions.map((function) {
|
||||
if (function.functionCode == 'automation') {
|
||||
return AutomationAction(
|
||||
entityId: function.entityId,
|
||||
actionExecutor: function.value,
|
||||
);
|
||||
}
|
||||
|
||||
if (item['deviceId'] == 'delay') {
|
||||
return AutomationAction(
|
||||
entityId: function.entityId,
|
||||
actionExecutor: 'delay',
|
||||
executorProperty: ExecutorProperty(
|
||||
delaySeconds: int.tryParse(function.value.toString()) ?? 0,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return AutomationAction(
|
||||
entityId: function.entityId,
|
||||
actionExecutor: 'device_issue',
|
||||
executorProperty: ExecutorProperty(
|
||||
functionCode: function.functionCode,
|
||||
functionValue: function.value,
|
||||
),
|
||||
);
|
||||
});
|
||||
}).toList();
|
||||
|
||||
final createAutomationModel = CreateAutomationModel(
|
||||
unitUuid: spaceId,
|
||||
spaceUuid: spaceId,
|
||||
automationName: state.routineName!,
|
||||
decisionExpr: state.selectedAutomationOperator,
|
||||
effectiveTime: state.effectiveTime ??
|
||||
EffectiveTime(
|
||||
start: '00:00',
|
||||
end: '23:59',
|
||||
loops: '1111111',
|
||||
),
|
||||
effectiveTime: EffectiveTime(
|
||||
start: state.effectiveTime?.start ?? '00:00',
|
||||
end: state.effectiveTime?.end ?? '23:59',
|
||||
loops: state.effectiveTime?.loops ?? '1111111',
|
||||
),
|
||||
conditions: conditions,
|
||||
actions: state.thenItems
|
||||
.map((item) {
|
||||
final functions =
|
||||
state.selectedFunctions[item['uniqueCustomId']] ?? [];
|
||||
if (functions.isEmpty) return null;
|
||||
|
||||
final function = functions.first;
|
||||
if (function.functionCode == 'automation') {
|
||||
return CreateSceneAction(
|
||||
entityId: function.entityId,
|
||||
actionExecutor: function.value,
|
||||
executorProperty: null,
|
||||
);
|
||||
}
|
||||
|
||||
if (item['deviceId'] == 'delay') {
|
||||
return CreateSceneAction(
|
||||
entityId: function.entityId,
|
||||
actionExecutor: 'delay',
|
||||
executorProperty: CreateSceneExecutorProperty(
|
||||
functionCode: '',
|
||||
functionValue: '',
|
||||
delaySeconds: function.value,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return CreateSceneAction(
|
||||
entityId: function.entityId,
|
||||
actionExecutor: 'device_issue',
|
||||
executorProperty: CreateSceneExecutorProperty(
|
||||
functionCode: function.functionCode,
|
||||
functionValue: function.value,
|
||||
delaySeconds: 0,
|
||||
),
|
||||
);
|
||||
})
|
||||
.whereType<CreateSceneAction>()
|
||||
.toList(),
|
||||
actions: actions,
|
||||
);
|
||||
|
||||
final result = await SceneApi.createAutomation(createAutomationModel);
|
||||
if (result['success']) {
|
||||
emit(const RoutineState());
|
||||
emit(_resetState());
|
||||
add(const LoadAutomation(spaceId));
|
||||
} else {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
@ -322,21 +343,26 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
||||
} catch (e) {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: e.toString(),
|
||||
errorMessage: 'Something went wrong',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
thenItems.removeAt(event.index);
|
||||
emit(state.copyWith(thenItems: thenItems));
|
||||
selectedFunctions.remove(event.key);
|
||||
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);
|
||||
|
||||
ifItems.removeAt(event.index);
|
||||
emit(state.copyWith(ifItems: ifItems));
|
||||
selectedFunctions.remove(event.key);
|
||||
emit(state.copyWith(ifItems: ifItems, selectedFunctions: selectedFunctions));
|
||||
}
|
||||
}
|
||||
|
||||
@ -347,13 +373,36 @@ 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));
|
||||
}
|
||||
|
||||
RoutineState _resetState() {
|
||||
return const RoutineState(
|
||||
ifItems: [],
|
||||
thenItems: [],
|
||||
selectedFunctions: {},
|
||||
scenes: [],
|
||||
automations: [],
|
||||
isLoading: false,
|
||||
errorMessage: null,
|
||||
loadScenesErrorMessage: null,
|
||||
loadAutomationErrorMessage: null,
|
||||
searchText: '',
|
||||
selectedIcon: null,
|
||||
isTabToRun: false,
|
||||
isAutomation: false,
|
||||
selectedAutomationOperator: 'AND',
|
||||
effectiveTime: null,
|
||||
routineName: null,
|
||||
);
|
||||
}
|
||||
|
||||
FutureOr<void> _onResetRoutineState(ResetRoutineState event, Emitter<RoutineState> emit) {
|
||||
emit(_resetState());
|
||||
}
|
||||
}
|
||||
|
@ -82,9 +82,11 @@ class CreateSceneEvent extends RoutineEvent {
|
||||
class RemoveDragCard extends RoutineEvent {
|
||||
final int index;
|
||||
final bool isFromThen;
|
||||
const RemoveDragCard({required this.index, required this.isFromThen});
|
||||
final String key;
|
||||
const RemoveDragCard(
|
||||
{required this.index, required this.isFromThen, required this.key});
|
||||
@override
|
||||
List<Object> get props => [index];
|
||||
List<Object> get props => [index, isFromThen, key];
|
||||
}
|
||||
|
||||
class ChangeAutomationOperator extends RoutineEvent {
|
||||
@ -121,4 +123,7 @@ class SetRoutineName extends RoutineEvent {
|
||||
@override
|
||||
List<Object> get props => [name];
|
||||
}
|
||||
|
||||
class ResetRoutineState extends RoutineEvent {}
|
||||
|
||||
class ClearFunctions extends RoutineEvent {}
|
||||
|
@ -142,9 +142,16 @@ class SaveRoutineHelper {
|
||||
DialogFooter(
|
||||
onCancel: () => Navigator.pop(context),
|
||||
onConfirm: () {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(const CreateSceneEvent());
|
||||
if (state.isAutomation) {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(const CreateAutomationEvent());
|
||||
} else {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(const CreateSceneEvent());
|
||||
}
|
||||
|
||||
Navigator.pop(context);
|
||||
},
|
||||
isConfirmEnabled: true,
|
||||
|
@ -1,18 +1,187 @@
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_scene_model.dart';
|
||||
|
||||
// class CreateAutomationModel {
|
||||
// String unitUuid;
|
||||
// String automationName;
|
||||
// String decisionExpr;
|
||||
// EffectiveTime effectiveTime;
|
||||
// List<CreateCondition> conditions;
|
||||
// List<CreateSceneAction> actions;
|
||||
|
||||
// CreateAutomationModel({
|
||||
// required this.unitUuid,
|
||||
// required this.automationName,
|
||||
// required this.decisionExpr,
|
||||
// required this.effectiveTime,
|
||||
// required this.conditions,
|
||||
// required this.actions,
|
||||
// });
|
||||
|
||||
// CreateAutomationModel copyWith({
|
||||
// String? unitUuid,
|
||||
// String? automationName,
|
||||
// String? decisionExpr,
|
||||
// EffectiveTime? effectiveTime,
|
||||
// List<CreateCondition>? conditions,
|
||||
// List<CreateSceneAction>? actions,
|
||||
// }) {
|
||||
// return CreateAutomationModel(
|
||||
// unitUuid: unitUuid ?? this.unitUuid,
|
||||
// automationName: automationName ?? this.automationName,
|
||||
// decisionExpr: decisionExpr ?? this.decisionExpr,
|
||||
// effectiveTime: effectiveTime ?? this.effectiveTime,
|
||||
// conditions: conditions ?? this.conditions,
|
||||
// actions: actions ?? this.actions,
|
||||
// );
|
||||
// }
|
||||
|
||||
// Map<String, dynamic> toMap([String? automationId]) {
|
||||
// return {
|
||||
// if (automationId == null) 'spaceUuid': unitUuid,
|
||||
// 'automationName': automationName,
|
||||
// 'decisionExpr': decisionExpr,
|
||||
// 'effectiveTime': effectiveTime.toMap(),
|
||||
// 'conditions': conditions.map((x) => x.toMap()).toList(),
|
||||
// 'actions': actions.map((x) => x.toMap()).toList(),
|
||||
// };
|
||||
// }
|
||||
|
||||
// factory CreateAutomationModel.fromMap(Map<String, dynamic> map) {
|
||||
// return CreateAutomationModel(
|
||||
// unitUuid: map['spaceUuid'] ?? '',
|
||||
// automationName: map['automationName'] ?? '',
|
||||
// decisionExpr: map['decisionExpr'] ?? '',
|
||||
// effectiveTime: EffectiveTime.fromMap(map['effectiveTime']),
|
||||
// conditions: List<CreateCondition>.from(
|
||||
// map['conditions']?.map((x) => CreateCondition.fromMap(x))),
|
||||
// actions: List<CreateSceneAction>.from(
|
||||
// map['actions']?.map((x) => CreateSceneAction.fromMap(x))),
|
||||
// );
|
||||
// }
|
||||
|
||||
// String toJson([String? automationId]) => json.encode(toMap(automationId));
|
||||
|
||||
// factory CreateAutomationModel.fromJson(String source) =>
|
||||
// CreateAutomationModel.fromMap(json.decode(source));
|
||||
|
||||
// @override
|
||||
// String toString() {
|
||||
// return 'CreateAutomationModel(unitUuid: $unitUuid, automationName: $automationName, decisionExpr: $decisionExpr, effectiveTime: $effectiveTime, conditions: $conditions, actions: $actions)';
|
||||
// }
|
||||
// }
|
||||
|
||||
// class EffectiveTime {
|
||||
// String start;
|
||||
// String end;
|
||||
// String loops;
|
||||
|
||||
// EffectiveTime({
|
||||
// required this.start,
|
||||
// required this.end,
|
||||
// required this.loops,
|
||||
// });
|
||||
|
||||
// Map<String, dynamic> toMap() {
|
||||
// return {
|
||||
// 'start': start,
|
||||
// 'end': end,
|
||||
// 'loops': loops,
|
||||
// };
|
||||
// }
|
||||
|
||||
// factory EffectiveTime.fromMap(Map<String, dynamic> map) {
|
||||
// return EffectiveTime(
|
||||
// start: map['start'] ?? '',
|
||||
// end: map['end'] ?? '',
|
||||
// loops: map['loops'] ?? '',
|
||||
// );
|
||||
// }
|
||||
|
||||
// @override
|
||||
// String toString() => 'EffectiveTime(start: $start, end: $end, loops: $loops)';
|
||||
// }
|
||||
|
||||
// class CreateCondition {
|
||||
// int code;
|
||||
// String entityId;
|
||||
// String entityType;
|
||||
// ConditionExpr expr;
|
||||
|
||||
// CreateCondition({
|
||||
// required this.code,
|
||||
// required this.entityId,
|
||||
// required this.entityType,
|
||||
// required this.expr,
|
||||
// });
|
||||
|
||||
// Map<String, dynamic> toMap() {
|
||||
// return {
|
||||
// 'code': code,
|
||||
// 'entityId': entityId,
|
||||
// 'entityType': entityType,
|
||||
// 'expr': expr.toMap(),
|
||||
// };
|
||||
// }
|
||||
|
||||
// factory CreateCondition.fromMap(Map<String, dynamic> map) {
|
||||
// return CreateCondition(
|
||||
// code: map['code'] ?? 0,
|
||||
// entityId: map['entityId'] ?? '',
|
||||
// entityType: map['entityType'] ?? '',
|
||||
// expr: ConditionExpr.fromMap(map['expr']),
|
||||
// );
|
||||
// }
|
||||
|
||||
// @override
|
||||
// String toString() =>
|
||||
// 'CreateCondition(code: $code, entityId: $entityId, entityType: $entityType, expr: $expr)';
|
||||
// }
|
||||
|
||||
// class ConditionExpr {
|
||||
// String statusCode;
|
||||
// String comparator;
|
||||
// dynamic statusValue;
|
||||
|
||||
// ConditionExpr({
|
||||
// required this.statusCode,
|
||||
// required this.comparator,
|
||||
// required this.statusValue,
|
||||
// });
|
||||
|
||||
// Map<String, dynamic> toMap() {
|
||||
// return {
|
||||
// 'statusCode': statusCode,
|
||||
// 'comparator': comparator,
|
||||
// 'statusValue': statusValue,
|
||||
// };
|
||||
// }
|
||||
|
||||
// factory ConditionExpr.fromMap(Map<String, dynamic> map) {
|
||||
// return ConditionExpr(
|
||||
// statusCode: map['statusCode'] ?? '',
|
||||
// comparator: map['comparator'] ?? '',
|
||||
// statusValue: map['statusValue'],
|
||||
// );
|
||||
// }
|
||||
|
||||
// @override
|
||||
// String toString() =>
|
||||
// 'ConditionExpr(statusCode: $statusCode, comparator: $comparator, statusValue: $statusValue)';
|
||||
// }
|
||||
import 'dart:convert';
|
||||
|
||||
class CreateAutomationModel {
|
||||
String unitUuid;
|
||||
String spaceUuid;
|
||||
String automationName;
|
||||
String decisionExpr;
|
||||
EffectiveTime effectiveTime;
|
||||
List<CreateCondition> conditions;
|
||||
List<CreateSceneAction> actions;
|
||||
List<Condition> conditions;
|
||||
List<AutomationAction> actions;
|
||||
|
||||
CreateAutomationModel({
|
||||
required this.unitUuid,
|
||||
required this.spaceUuid,
|
||||
required this.automationName,
|
||||
required this.decisionExpr,
|
||||
required this.effectiveTime,
|
||||
@ -20,27 +189,9 @@ class CreateAutomationModel {
|
||||
required this.actions,
|
||||
});
|
||||
|
||||
CreateAutomationModel copyWith({
|
||||
String? unitUuid,
|
||||
String? automationName,
|
||||
String? decisionExpr,
|
||||
EffectiveTime? effectiveTime,
|
||||
List<CreateCondition>? conditions,
|
||||
List<CreateSceneAction>? actions,
|
||||
}) {
|
||||
return CreateAutomationModel(
|
||||
unitUuid: unitUuid ?? this.unitUuid,
|
||||
automationName: automationName ?? this.automationName,
|
||||
decisionExpr: decisionExpr ?? this.decisionExpr,
|
||||
effectiveTime: effectiveTime ?? this.effectiveTime,
|
||||
conditions: conditions ?? this.conditions,
|
||||
actions: actions ?? this.actions,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap([String? automationId]) {
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
if (automationId == null) 'spaceUuid': unitUuid,
|
||||
'spaceUuid': spaceUuid,
|
||||
'automationName': automationName,
|
||||
'decisionExpr': decisionExpr,
|
||||
'effectiveTime': effectiveTime.toMap(),
|
||||
@ -51,26 +202,21 @@ class CreateAutomationModel {
|
||||
|
||||
factory CreateAutomationModel.fromMap(Map<String, dynamic> map) {
|
||||
return CreateAutomationModel(
|
||||
unitUuid: map['spaceUuid'] ?? '',
|
||||
spaceUuid: map['spaceUuid'] ?? '',
|
||||
automationName: map['automationName'] ?? '',
|
||||
decisionExpr: map['decisionExpr'] ?? '',
|
||||
effectiveTime: EffectiveTime.fromMap(map['effectiveTime']),
|
||||
conditions: List<CreateCondition>.from(
|
||||
map['conditions']?.map((x) => CreateCondition.fromMap(x))),
|
||||
actions: List<CreateSceneAction>.from(
|
||||
map['actions']?.map((x) => CreateSceneAction.fromMap(x))),
|
||||
conditions: List<Condition>.from(
|
||||
map['conditions']?.map((x) => Condition.fromMap(x)) ?? []),
|
||||
actions: List<AutomationAction>.from(
|
||||
map['actions']?.map((x) => AutomationAction.fromMap(x)) ?? []),
|
||||
);
|
||||
}
|
||||
|
||||
String toJson([String? automationId]) => json.encode(toMap(automationId));
|
||||
String toJson() => json.encode(toMap());
|
||||
|
||||
factory CreateAutomationModel.fromJson(String source) =>
|
||||
CreateAutomationModel.fromMap(json.decode(source));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CreateAutomationModel(unitUuid: $unitUuid, automationName: $automationName, decisionExpr: $decisionExpr, effectiveTime: $effectiveTime, conditions: $conditions, actions: $actions)';
|
||||
}
|
||||
}
|
||||
|
||||
class EffectiveTime {
|
||||
@ -99,18 +245,15 @@ class EffectiveTime {
|
||||
loops: map['loops'] ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => 'EffectiveTime(start: $start, end: $end, loops: $loops)';
|
||||
}
|
||||
|
||||
class CreateCondition {
|
||||
class Condition {
|
||||
int code;
|
||||
String entityId;
|
||||
String entityType;
|
||||
ConditionExpr expr;
|
||||
|
||||
CreateCondition({
|
||||
Condition({
|
||||
required this.code,
|
||||
required this.entityId,
|
||||
required this.entityType,
|
||||
@ -126,18 +269,14 @@ class CreateCondition {
|
||||
};
|
||||
}
|
||||
|
||||
factory CreateCondition.fromMap(Map<String, dynamic> map) {
|
||||
return CreateCondition(
|
||||
code: map['code'] ?? 0,
|
||||
factory Condition.fromMap(Map<String, dynamic> map) {
|
||||
return Condition(
|
||||
code: map['code']?.toInt() ?? 0,
|
||||
entityId: map['entityId'] ?? '',
|
||||
entityType: map['entityType'] ?? '',
|
||||
expr: ConditionExpr.fromMap(map['expr']),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'CreateCondition(code: $code, entityId: $entityId, entityType: $entityType, expr: $expr)';
|
||||
}
|
||||
|
||||
class ConditionExpr {
|
||||
@ -166,8 +305,62 @@ class ConditionExpr {
|
||||
statusValue: map['statusValue'],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'ConditionExpr(statusCode: $statusCode, comparator: $comparator, statusValue: $statusValue)';
|
||||
}
|
||||
|
||||
class AutomationAction {
|
||||
String entityId;
|
||||
String actionExecutor;
|
||||
ExecutorProperty? executorProperty;
|
||||
|
||||
AutomationAction({
|
||||
required this.entityId,
|
||||
required this.actionExecutor,
|
||||
this.executorProperty,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'entityId': entityId,
|
||||
'actionExecutor': actionExecutor,
|
||||
'executorProperty': executorProperty?.toMap(),
|
||||
};
|
||||
}
|
||||
|
||||
factory AutomationAction.fromMap(Map<String, dynamic> map) {
|
||||
return AutomationAction(
|
||||
entityId: map['entityId'] ?? '',
|
||||
actionExecutor: map['actionExecutor'] ?? '',
|
||||
executorProperty: map['executorProperty'] != null
|
||||
? ExecutorProperty.fromMap(map['executorProperty'])
|
||||
: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ExecutorProperty {
|
||||
String? functionCode;
|
||||
dynamic functionValue;
|
||||
int? delaySeconds;
|
||||
|
||||
ExecutorProperty({
|
||||
this.functionCode,
|
||||
this.functionValue,
|
||||
this.delaySeconds,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
if (functionCode != null) 'functionCode': functionCode,
|
||||
if (functionValue != null) 'functionValue': functionValue,
|
||||
if (delaySeconds != null) 'delaySeconds': delaySeconds,
|
||||
};
|
||||
}
|
||||
|
||||
factory ExecutorProperty.fromMap(Map<String, dynamic> map) {
|
||||
return ExecutorProperty(
|
||||
functionCode: map['functionCode'],
|
||||
functionValue: map['functionValue'],
|
||||
delaySeconds: map['delaySeconds']?.toInt(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/effictive_period_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/period_option.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/repeat_days.dart';
|
||||
@ -11,39 +9,36 @@ class EffectivePeriodView extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (_) => EffectPeriodBloc(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: ListView(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Spacer(),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Effective Period',
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
color: ColorsManager.textPrimaryColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14),
|
||||
),
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: ListView(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Spacer(),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Effective Period',
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
color: ColorsManager.textPrimaryColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14),
|
||||
),
|
||||
const Spacer(),
|
||||
],
|
||||
),
|
||||
const Divider(
|
||||
color: ColorsManager.backgroundColor,
|
||||
),
|
||||
const PeriodOptions(
|
||||
showCustomTimePicker: EffectPeriodHelper.showCustomTimePicker,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const RepeatDays(),
|
||||
const SizedBox(height: 24),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
],
|
||||
),
|
||||
const Divider(
|
||||
color: ColorsManager.backgroundColor,
|
||||
),
|
||||
const PeriodOptions(
|
||||
showCustomTimePicker: EffectPeriodHelper.showCustomTimePicker,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const RepeatDays(),
|
||||
const SizedBox(height: 24),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -26,9 +26,7 @@ class IfContainer extends StatelessWidget {
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text('IF',
|
||||
style: TextStyle(
|
||||
fontSize: 18, fontWeight: FontWeight.bold)),
|
||||
const Text('IF', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||
if (state.isAutomation)
|
||||
AutomationOperatorSelector(
|
||||
selectedOperator: state.selectedAutomationOperator),
|
||||
@ -52,20 +50,38 @@ class IfContainer extends StatelessWidget {
|
||||
runSpacing: 8,
|
||||
children: List.generate(
|
||||
state.ifItems.length,
|
||||
(index) => DraggableCard(
|
||||
imagePath:
|
||||
state.ifItems[index]['imagePath'] ?? '',
|
||||
title: state.ifItems[index]['title'] ?? '',
|
||||
deviceData: state.ifItems[index],
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 4, vertical: 8),
|
||||
isFromThen: false,
|
||||
isFromIf: true,
|
||||
onRemove: () {
|
||||
context.read<RoutineBloc>().add(
|
||||
RemoveDragCard(
|
||||
index: index, isFromThen: false));
|
||||
(index) => GestureDetector(
|
||||
onTap: () async {
|
||||
if (!state.isTabToRun) {
|
||||
final result = await DeviceDialogHelper.showDeviceDialog(
|
||||
context, state.ifItems[index]);
|
||||
|
||||
if (result != null) {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToIfContainer(state.ifItems[index], false));
|
||||
} else if (!['AC', '1G', '2G', '3G']
|
||||
.contains(state.ifItems[index]['productType'])) {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToIfContainer(state.ifItems[index], false));
|
||||
}
|
||||
}
|
||||
},
|
||||
child: DraggableCard(
|
||||
imagePath: state.ifItems[index]['imagePath'] ?? '',
|
||||
title: state.ifItems[index]['title'] ?? '',
|
||||
deviceData: state.ifItems[index],
|
||||
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']));
|
||||
},
|
||||
),
|
||||
)),
|
||||
),
|
||||
],
|
||||
@ -81,22 +97,14 @@ class IfContainer extends StatelessWidget {
|
||||
|
||||
if (!state.isTabToRun) {
|
||||
if (mutableData['deviceId'] == 'tab_to_run') {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToIfContainer(mutableData, true));
|
||||
context.read<RoutineBloc>().add(AddToIfContainer(mutableData, true));
|
||||
} else {
|
||||
final result = await DeviceDialogHelper.showDeviceDialog(
|
||||
context, mutableData);
|
||||
final result = await DeviceDialogHelper.showDeviceDialog(context, mutableData);
|
||||
|
||||
if (result != null) {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToIfContainer(mutableData, false));
|
||||
} else if (!['AC', '1G', '2G', '3G']
|
||||
.contains(mutableData['productType'])) {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToIfContainer(mutableData, false));
|
||||
context.read<RoutineBloc>().add(AddToIfContainer(mutableData, false));
|
||||
} else if (!['AC', '1G', '2G', '3G'].contains(mutableData['productType'])) {
|
||||
context.read<RoutineBloc>().add(AddToIfContainer(mutableData, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -136,15 +144,12 @@ class AutomationOperatorSelector extends StatelessWidget {
|
||||
child: Text(
|
||||
'Any condition is met',
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
color: selectedOperator == 'or'
|
||||
? ColorsManager.whiteColors
|
||||
: ColorsManager.blackColor,
|
||||
color:
|
||||
selectedOperator == 'or' ? ColorsManager.whiteColors : ColorsManager.blackColor,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(const ChangeAutomationOperator(operator: 'or'));
|
||||
context.read<RoutineBloc>().add(const ChangeAutomationOperator(operator: 'or'));
|
||||
},
|
||||
),
|
||||
Container(
|
||||
@ -170,9 +175,7 @@ class AutomationOperatorSelector extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(const ChangeAutomationOperator(operator: 'and'));
|
||||
context.read<RoutineBloc>().add(const ChangeAutomationOperator(operator: 'and'));
|
||||
},
|
||||
),
|
||||
],
|
||||
|
@ -21,12 +21,9 @@ class PeriodOptions extends StatelessWidget {
|
||||
builder: (context, state) {
|
||||
return Column(
|
||||
children: [
|
||||
_buildRadioOption(
|
||||
context, EnumEffectivePeriodOptions.allDay, '24 Hours'),
|
||||
_buildRadioOption(context, EnumEffectivePeriodOptions.daytime,
|
||||
'Sunrise to Sunset'),
|
||||
_buildRadioOption(
|
||||
context, EnumEffectivePeriodOptions.night, 'Sunset to Sunrise'),
|
||||
_buildRadioOption(context, EnumEffectivePeriodOptions.allDay, '24 Hours'),
|
||||
_buildRadioOption(context, EnumEffectivePeriodOptions.daytime, 'Sunrise to Sunset'),
|
||||
_buildRadioOption(context, EnumEffectivePeriodOptions.night, 'Sunset to Sunrise'),
|
||||
ListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
onTap: () => showCustomTimePicker(context),
|
||||
@ -37,8 +34,7 @@ class PeriodOptions extends StatelessWidget {
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14),
|
||||
),
|
||||
subtitle: state.customStartTime != null &&
|
||||
state.customEndTime != null
|
||||
subtitle: state.customStartTime != null && state.customEndTime != null
|
||||
? Text(
|
||||
'${"${state.customStartTime}"} - ${"${state.customEndTime}"}',
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
@ -83,9 +79,7 @@ class PeriodOptions extends StatelessWidget {
|
||||
subtitle: Text(
|
||||
subtitle,
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
color: ColorsManager.textPrimaryColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 10),
|
||||
color: ColorsManager.textPrimaryColor, fontWeight: FontWeight.w400, fontSize: 10),
|
||||
),
|
||||
trailing: Radio<EnumEffectivePeriodOptions>(
|
||||
value: value,
|
||||
|
@ -74,7 +74,7 @@ class _AutomationDialogState extends State<AutomationDialog> {
|
||||
DeviceFunctionData(
|
||||
entityId: widget.automationId,
|
||||
functionCode: 'automation',
|
||||
value: _isEnabled,
|
||||
value: _isEnabled ? 'rule_enable' : 'rule_disable',
|
||||
operationName: 'Automation',
|
||||
),
|
||||
],
|
||||
|
@ -0,0 +1,62 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/custom_table.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/switch_tabs/switch_tabs_bloc.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
|
||||
class DiscardDialog {
|
||||
static void show(BuildContext context) {
|
||||
context.customAlertDialog(
|
||||
alertBody: Container(
|
||||
height: 150,
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
'If you close, you will lose all the changes you have made.',
|
||||
textAlign: TextAlign.center,
|
||||
style: context.textTheme.bodyMedium!.copyWith(
|
||||
color: ColorsManager.red,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Text(
|
||||
'Are you sure you wish to close?',
|
||||
style: context.textTheme.bodyMedium!.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
color: ColorsManager.grayColor,
|
||||
),
|
||||
)
|
||||
],
|
||||
)),
|
||||
title: 'Discard',
|
||||
titleStyle: context.textTheme.titleLarge!.copyWith(
|
||||
color: ColorsManager.red,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
onDismissText: "Don’t Close",
|
||||
onConfirmText: "Close",
|
||||
onDismissColor: ColorsManager.grayColor,
|
||||
onConfirmColor: ColorsManager.red.withOpacity(0.8),
|
||||
onDismiss: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
onConfirm: () {
|
||||
context.read<RoutineBloc>().add(ResetRoutineState());
|
||||
Navigator.pop(context);
|
||||
BlocProvider.of<SwitchTabsBloc>(context).add(
|
||||
const CreateNewRoutineViewEvent(false),
|
||||
);
|
||||
BlocProvider.of<SwitchTabsBloc>(context).add(
|
||||
const TriggerSwitchTabsEvent(true),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
@ -1,9 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/effective_period/effect_period_state.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/setting_bloc/setting_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/setting_bloc/setting_event.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/setting_bloc/setting_state.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_automation_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/models/icon_model.dart';
|
||||
import 'package:syncrow_web/pages/routiens/view/effective_period_view.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
||||
@ -19,444 +22,392 @@ class SettingHelper {
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
final isAutomation = context.read<RoutineBloc>().state.isAutomation;
|
||||
return BlocProvider(
|
||||
create: (_) =>
|
||||
SettingBloc()..add(InitialEvent(selectedIcon: iconId ?? '')),
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider(
|
||||
create: (_) => EffectPeriodBloc(),
|
||||
),
|
||||
BlocProvider(
|
||||
create: (_) => SettingBloc()..add(InitialEvent(selectedIcon: iconId ?? ''))),
|
||||
],
|
||||
child: AlertDialog(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
content: BlocBuilder<SettingBloc, SettingState>(
|
||||
builder: (context, state) {
|
||||
String selectedIcon = '';
|
||||
List<IconModel> list = [];
|
||||
if (state is TabToRunSettingLoaded) {
|
||||
selectedIcon = state.selectedIcon;
|
||||
list = state.iconList;
|
||||
}
|
||||
return Container(
|
||||
width: context.read<SettingBloc>().isExpanded ? 800 : 400,
|
||||
height: context.read<SettingBloc>().isExpanded && isAutomation
|
||||
? 500
|
||||
: 300,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
padding: const EdgeInsets.only(top: 20),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const DialogHeader('Settings'),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 400,
|
||||
child: isAutomation
|
||||
? Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 10,
|
||||
left: 10,
|
||||
right: 10,
|
||||
bottom: 10),
|
||||
child: Column(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {},
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Validity',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager
|
||||
.textPrimaryColor,
|
||||
fontWeight:
|
||||
FontWeight
|
||||
.w400,
|
||||
fontSize: 14),
|
||||
),
|
||||
const Icon(
|
||||
Icons
|
||||
.arrow_forward_ios_outlined,
|
||||
color: ColorsManager
|
||||
.textGray,
|
||||
size: 15,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
const Divider(
|
||||
color: ColorsManager.graysColor,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
BlocProvider.of<SettingBloc>(
|
||||
context)
|
||||
.add(FetchIcons(
|
||||
expanded: !context
|
||||
.read<
|
||||
SettingBloc>()
|
||||
.isExpanded));
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Effective Period',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager
|
||||
.textPrimaryColor,
|
||||
fontWeight:
|
||||
FontWeight
|
||||
.w400,
|
||||
fontSize: 14),
|
||||
),
|
||||
const Icon(
|
||||
Icons
|
||||
.arrow_forward_ios_outlined,
|
||||
color: ColorsManager
|
||||
.textGray,
|
||||
size: 15,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
const Divider(
|
||||
color: ColorsManager.graysColor,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Executed by',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager
|
||||
.textPrimaryColor,
|
||||
fontWeight:
|
||||
FontWeight.w400,
|
||||
fontSize: 14),
|
||||
),
|
||||
Text('Cloud',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color:
|
||||
ColorsManager
|
||||
.textGray,
|
||||
fontWeight:
|
||||
FontWeight
|
||||
.w400,
|
||||
fontSize: 14)),
|
||||
],
|
||||
),
|
||||
],
|
||||
)),
|
||||
],
|
||||
)
|
||||
: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 10,
|
||||
left: 10,
|
||||
right: 10,
|
||||
bottom: 10),
|
||||
child: Column(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
BlocProvider.of<SettingBloc>(
|
||||
context)
|
||||
.add(FetchIcons(
|
||||
expanded: !context
|
||||
.read<
|
||||
SettingBloc>()
|
||||
.isExpanded));
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Icons',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager
|
||||
.textPrimaryColor,
|
||||
fontWeight:
|
||||
FontWeight
|
||||
.w400,
|
||||
fontSize: 14),
|
||||
),
|
||||
const Icon(
|
||||
Icons
|
||||
.arrow_forward_ios_outlined,
|
||||
color: ColorsManager
|
||||
.textGray,
|
||||
size: 15,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
const Divider(
|
||||
color: ColorsManager.graysColor,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Show on devices page',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager
|
||||
.textPrimaryColor,
|
||||
fontWeight:
|
||||
FontWeight.w400,
|
||||
fontSize: 14),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.end,
|
||||
children: [
|
||||
Container(
|
||||
height: 30,
|
||||
width: 1,
|
||||
color: ColorsManager
|
||||
.graysColor,
|
||||
),
|
||||
Transform.scale(
|
||||
scale: .8,
|
||||
child: CupertinoSwitch(
|
||||
value: true,
|
||||
onChanged: (value) {},
|
||||
applyTheme: true,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
const Divider(
|
||||
color: ColorsManager.graysColor,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Executed by',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager
|
||||
.textPrimaryColor,
|
||||
fontWeight:
|
||||
FontWeight.w400,
|
||||
fontSize: 14),
|
||||
),
|
||||
Text('Cloud',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color:
|
||||
ColorsManager
|
||||
.textGray,
|
||||
fontWeight:
|
||||
FontWeight
|
||||
.w400,
|
||||
fontSize: 14)),
|
||||
],
|
||||
),
|
||||
],
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (context.read<SettingBloc>().isExpanded &&
|
||||
!isAutomation)
|
||||
SizedBox(
|
||||
width: 400,
|
||||
height: 150,
|
||||
child: state is LoadingState
|
||||
? const Center(
|
||||
child: CircularProgressIndicator())
|
||||
: GridView.builder(
|
||||
gridDelegate:
|
||||
const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 6,
|
||||
crossAxisSpacing: 12,
|
||||
mainAxisSpacing: 12,
|
||||
),
|
||||
shrinkWrap: true,
|
||||
itemCount: list.length,
|
||||
itemBuilder: (context, index) {
|
||||
final iconModel = list[index];
|
||||
return SizedBox(
|
||||
width: 35,
|
||||
height: 35,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
BlocProvider.of<SettingBloc>(
|
||||
context)
|
||||
.add(SelectIcon(
|
||||
iconId: iconModel.uuid,
|
||||
));
|
||||
selectedIcon = iconModel.uuid;
|
||||
},
|
||||
child: SizedBox(
|
||||
child: ClipOval(
|
||||
child: Container(
|
||||
padding:
|
||||
const EdgeInsets.all(1),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: selectedIcon ==
|
||||
iconModel.uuid
|
||||
? ColorsManager
|
||||
.primaryColorWithOpacity
|
||||
: Colors
|
||||
.transparent,
|
||||
width: 2,
|
||||
),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Image.memory(
|
||||
iconModel.iconBytes,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
)),
|
||||
if (context.read<SettingBloc>().isExpanded &&
|
||||
isAutomation)
|
||||
const SizedBox(
|
||||
height: 350,
|
||||
width: 400,
|
||||
child: EffectivePeriodView())
|
||||
],
|
||||
),
|
||||
Container(
|
||||
width: MediaQuery.sizeOf(context).width,
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
content: BlocBuilder<EffectPeriodBloc, EffectPeriodState>(
|
||||
builder: (context, effectPeriodState) {
|
||||
return BlocBuilder<SettingBloc, SettingState>(
|
||||
builder: (context, settingState) {
|
||||
String selectedIcon = '';
|
||||
List<IconModel> list = [];
|
||||
if (settingState is TabToRunSettingLoaded) {
|
||||
selectedIcon = settingState.selectedIcon;
|
||||
list = settingState.iconList;
|
||||
}
|
||||
return Container(
|
||||
width: context.read<SettingBloc>().isExpanded ? 800 : 400,
|
||||
height: context.read<SettingBloc>().isExpanded && isAutomation ? 500 : 300,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
padding: const EdgeInsets.only(top: 20),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const DialogHeader('Settings'),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Container(
|
||||
alignment: AlignmentDirectional.center,
|
||||
child: Text(
|
||||
'Cancel',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager.textGray,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: 1,
|
||||
height: 50,
|
||||
color: ColorsManager.greyColor),
|
||||
Expanded(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop(selectedIcon);
|
||||
},
|
||||
child: Container(
|
||||
alignment: AlignmentDirectional.center,
|
||||
child: Text(
|
||||
'Confirm',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager
|
||||
.primaryColorWithOpacity,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 400,
|
||||
child: isAutomation
|
||||
? Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 10, left: 10, right: 10, bottom: 10),
|
||||
child: Column(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {},
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Validity',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color:
|
||||
ColorsManager.textPrimaryColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14),
|
||||
),
|
||||
const Icon(
|
||||
Icons.arrow_forward_ios_outlined,
|
||||
color: ColorsManager.textGray,
|
||||
size: 15,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
const Divider(
|
||||
color: ColorsManager.graysColor,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
BlocProvider.of<SettingBloc>(context).add(
|
||||
FetchIcons(
|
||||
expanded: !context
|
||||
.read<SettingBloc>()
|
||||
.isExpanded));
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Effective Period',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color:
|
||||
ColorsManager.textPrimaryColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14),
|
||||
),
|
||||
const Icon(
|
||||
Icons.arrow_forward_ios_outlined,
|
||||
color: ColorsManager.textGray,
|
||||
size: 15,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
const Divider(
|
||||
color: ColorsManager.graysColor,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Executed by',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager.textPrimaryColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14),
|
||||
),
|
||||
Text('Cloud',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager.textGray,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14)),
|
||||
],
|
||||
),
|
||||
],
|
||||
)),
|
||||
],
|
||||
)
|
||||
: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 10, left: 10, right: 10, bottom: 10),
|
||||
child: Column(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
BlocProvider.of<SettingBloc>(context).add(
|
||||
FetchIcons(
|
||||
expanded: !context
|
||||
.read<SettingBloc>()
|
||||
.isExpanded));
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Icons',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color:
|
||||
ColorsManager.textPrimaryColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14),
|
||||
),
|
||||
const Icon(
|
||||
Icons.arrow_forward_ios_outlined,
|
||||
color: ColorsManager.textGray,
|
||||
size: 15,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
const Divider(
|
||||
color: ColorsManager.graysColor,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Show on devices page',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager.textPrimaryColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Container(
|
||||
height: 30,
|
||||
width: 1,
|
||||
color: ColorsManager.graysColor,
|
||||
),
|
||||
Transform.scale(
|
||||
scale: .8,
|
||||
child: CupertinoSwitch(
|
||||
value: true,
|
||||
onChanged: (value) {},
|
||||
applyTheme: true,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
const Divider(
|
||||
color: ColorsManager.graysColor,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Executed by',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager.textPrimaryColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14),
|
||||
),
|
||||
Text('Cloud',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: ColorsManager.textGray,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14)),
|
||||
],
|
||||
),
|
||||
],
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (context.read<SettingBloc>().isExpanded && !isAutomation)
|
||||
SizedBox(
|
||||
width: 400,
|
||||
height: 150,
|
||||
child: settingState is LoadingState
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: GridView.builder(
|
||||
gridDelegate:
|
||||
const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 6,
|
||||
crossAxisSpacing: 12,
|
||||
mainAxisSpacing: 12,
|
||||
),
|
||||
shrinkWrap: true,
|
||||
itemCount: list.length,
|
||||
itemBuilder: (context, index) {
|
||||
final iconModel = list[index];
|
||||
return SizedBox(
|
||||
width: 35,
|
||||
height: 35,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
BlocProvider.of<SettingBloc>(context)
|
||||
.add(SelectIcon(
|
||||
iconId: iconModel.uuid,
|
||||
));
|
||||
selectedIcon = iconModel.uuid;
|
||||
},
|
||||
child: SizedBox(
|
||||
child: ClipOval(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(1),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: selectedIcon == iconModel.uuid
|
||||
? ColorsManager
|
||||
.primaryColorWithOpacity
|
||||
: Colors.transparent,
|
||||
width: 2,
|
||||
),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Image.memory(
|
||||
iconModel.iconBytes,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
)),
|
||||
if (context.read<SettingBloc>().isExpanded && isAutomation)
|
||||
const SizedBox(height: 350, width: 400, child: EffectivePeriodView())
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
Container(
|
||||
width: MediaQuery.sizeOf(context).width,
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Container(
|
||||
alignment: AlignmentDirectional.center,
|
||||
child: Text(
|
||||
'Cancel',
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
color: ColorsManager.textGray,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(width: 1, height: 50, color: ColorsManager.greyColor),
|
||||
Expanded(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
if (isAutomation) {
|
||||
BlocProvider.of<RoutineBloc>(context).add(
|
||||
EffectiveTimePeriodEvent(EffectiveTime(
|
||||
start: effectPeriodState.customStartTime!,
|
||||
end: effectPeriodState.customEndTime!,
|
||||
loops: effectPeriodState.selectedDaysBinary)));
|
||||
Navigator.of(context).pop();
|
||||
} else {
|
||||
Navigator.of(context).pop(selectedIcon);
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
alignment: AlignmentDirectional.center,
|
||||
child: Text(
|
||||
'Confirm',
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
color: ColorsManager.primaryColorWithOpacity,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
@ -1,11 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||
import 'package:syncrow_web/pages/common/text_field/custom_text_field.dart';
|
||||
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/routiens/helper/save_routine_helper.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/discard_dialog.dart';
|
||||
import 'package:syncrow_web/pages/routiens/widgets/routine_dialogs/setting_dialog.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 RoutineSearchAndButtons extends StatelessWidget {
|
||||
@ -15,88 +16,260 @@ class RoutineSearchAndButtons extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(
|
||||
builder: (BuildContext context, BoxConstraints constraints) {
|
||||
return Wrap(
|
||||
runSpacing: 16,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
return BlocBuilder<RoutineBloc, RoutineState>(
|
||||
builder: (context, state) {
|
||||
return LayoutBuilder(
|
||||
builder: (BuildContext context, BoxConstraints constraints) {
|
||||
return Wrap(
|
||||
runSpacing: 16,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Wrap(
|
||||
spacing: 12,
|
||||
runSpacing: 12,
|
||||
crossAxisAlignment: WrapCrossAlignment.end,
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: constraints.maxWidth > 700
|
||||
? 450
|
||||
: constraints.maxWidth - 32),
|
||||
child: StatefulTextField(
|
||||
title: 'Routine Name',
|
||||
height: 40,
|
||||
controller: TextEditingController(),
|
||||
hintText: 'Please enter the name',
|
||||
boxDecoration: containerWhiteDecoration,
|
||||
elevation: 0,
|
||||
borderRadius: 15,
|
||||
isRequired: true,
|
||||
width: 450,
|
||||
onChanged: (value) {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(SetRoutineName(value));
|
||||
},
|
||||
),
|
||||
),
|
||||
(constraints.maxWidth <= 1000)
|
||||
? const SizedBox()
|
||||
: SizedBox(
|
||||
height: 40,
|
||||
width: 200,
|
||||
child: Center(
|
||||
child: DefaultButton(
|
||||
onPressed: () async {
|
||||
final result =
|
||||
await SettingHelper.showSettingDialog(
|
||||
context: context,
|
||||
);
|
||||
if (result != null) {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddSelectedIcon(result));
|
||||
}
|
||||
},
|
||||
borderRadius: 15,
|
||||
elevation: 0,
|
||||
borderColor: ColorsManager.greyColor,
|
||||
backgroundColor: ColorsManager.boxColor,
|
||||
child: const Text(
|
||||
'Settings',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: ColorsManager.primaryColor,
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Wrap(
|
||||
spacing: 12,
|
||||
runSpacing: 12,
|
||||
crossAxisAlignment: WrapCrossAlignment.end,
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth:
|
||||
constraints.maxWidth > 700 ? 450 : constraints.maxWidth - 32),
|
||||
// child: StatefulTextField(
|
||||
// title: 'Routine Name',
|
||||
// initialValue: state.routineName ?? '',
|
||||
// height: 40,
|
||||
// // controller: TextEditingController(),
|
||||
// hintText: 'Please enter the name',
|
||||
// boxDecoration: containerWhiteDecoration,
|
||||
// elevation: 0,
|
||||
// borderRadius: 15,
|
||||
// isRequired: true,
|
||||
// width: 450,
|
||||
// onSubmitted: (value) {
|
||||
// // context.read<RoutineBloc>().add(SetRoutineName(value));
|
||||
// },
|
||||
// onChanged: (value) {
|
||||
// context.read<RoutineBloc>().add(SetRoutineName(value));
|
||||
// },
|
||||
// ),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text('* ',
|
||||
style: context.textTheme.bodyMedium!
|
||||
.copyWith(color: ColorsManager.red, fontSize: 13)),
|
||||
Text(
|
||||
'Routine Name',
|
||||
style: context.textTheme.bodyMedium!.copyWith(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: ColorsManager.blackColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Container(
|
||||
width: 450,
|
||||
height: 40,
|
||||
decoration: containerWhiteDecoration,
|
||||
child: TextFormField(
|
||||
style: context.textTheme.bodyMedium!
|
||||
.copyWith(color: ColorsManager.blackColor),
|
||||
initialValue: state.routineName,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Please enter the name',
|
||||
hintStyle: context.textTheme.bodyMedium!
|
||||
.copyWith(fontSize: 12, color: ColorsManager.grayColor),
|
||||
contentPadding:
|
||||
const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||
border: InputBorder.none,
|
||||
),
|
||||
onChanged: (value) {
|
||||
context.read<RoutineBloc>().add(SetRoutineName(value));
|
||||
},
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'This field is required';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
(constraints.maxWidth <= 1000)
|
||||
? const SizedBox()
|
||||
: SizedBox(
|
||||
height: 40,
|
||||
width: 200,
|
||||
child: Center(
|
||||
child: DefaultButton(
|
||||
onPressed: state.isAutomation || state.isTabToRun
|
||||
? () async {
|
||||
final result = await SettingHelper.showSettingDialog(
|
||||
context: context,
|
||||
);
|
||||
if (result != null) {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddSelectedIcon(result));
|
||||
}
|
||||
}
|
||||
: null,
|
||||
borderRadius: 15,
|
||||
elevation: 0,
|
||||
borderColor: ColorsManager.greyColor,
|
||||
backgroundColor: ColorsManager.boxColor,
|
||||
child: const Text(
|
||||
'Settings',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: ColorsManager.primaryColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (constraints.maxWidth > 1000)
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 40,
|
||||
width: 200,
|
||||
child: Center(
|
||||
child: DefaultButton(
|
||||
onPressed: () {
|
||||
DiscardDialog.show(context);
|
||||
},
|
||||
borderRadius: 15,
|
||||
elevation: 0,
|
||||
borderColor: ColorsManager.greyColor,
|
||||
backgroundColor: ColorsManager.boxColor,
|
||||
child: const Text(
|
||||
'Cancel',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: ColorsManager.blackColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
SizedBox(
|
||||
height: 40,
|
||||
width: 200,
|
||||
child: Center(
|
||||
child: DefaultButton(
|
||||
onPressed: () {
|
||||
if (state.routineName == null || state.routineName!.isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: const Text('Please enter the routine name'),
|
||||
duration: const Duration(seconds: 2),
|
||||
backgroundColor: ColorsManager.red,
|
||||
action: SnackBarAction(
|
||||
label: 'Dismiss',
|
||||
onPressed: () {
|
||||
// Optional action on Snackbar
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.ifItems.isEmpty || state.thenItems.isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: const Text('Please add if and then condition'),
|
||||
duration: const Duration(seconds: 2),
|
||||
backgroundColor: ColorsManager.red,
|
||||
action: SnackBarAction(
|
||||
label: 'Dismiss',
|
||||
onPressed: () {
|
||||
// Optional action on Snackbar
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
SaveRoutineHelper.showSaveRoutineDialog(context);
|
||||
},
|
||||
borderRadius: 15,
|
||||
elevation: 0,
|
||||
backgroundColor: ColorsManager.primaryColor,
|
||||
child: const Text(
|
||||
'Save',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: ColorsManager.whiteColors,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
if (constraints.maxWidth > 1000)
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
if (constraints.maxWidth <= 1000)
|
||||
Wrap(
|
||||
runSpacing: 12,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 40,
|
||||
width: 200,
|
||||
child: Center(
|
||||
child: DefaultButton(
|
||||
onPressed: () {},
|
||||
onPressed: state.isAutomation || state.isTabToRun
|
||||
? () async {
|
||||
final result = await SettingHelper.showSettingDialog(
|
||||
context: context,
|
||||
);
|
||||
if (result != null) {
|
||||
context.read<RoutineBloc>().add(AddSelectedIcon(result));
|
||||
}
|
||||
}
|
||||
: null,
|
||||
borderRadius: 15,
|
||||
elevation: 0,
|
||||
borderColor: ColorsManager.greyColor,
|
||||
backgroundColor: ColorsManager.boxColor,
|
||||
child: const Text(
|
||||
'Settings',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: ColorsManager.primaryColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
SizedBox(
|
||||
height: 40,
|
||||
width: 200,
|
||||
child: Center(
|
||||
child: DefaultButton(
|
||||
onPressed: () {
|
||||
DiscardDialog.show(context);
|
||||
},
|
||||
borderRadius: 15,
|
||||
elevation: 0,
|
||||
borderColor: ColorsManager.greyColor,
|
||||
@ -119,6 +292,39 @@ class RoutineSearchAndButtons extends StatelessWidget {
|
||||
child: Center(
|
||||
child: DefaultButton(
|
||||
onPressed: () {
|
||||
if (state.routineName == null || state.routineName!.isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: const Text('Please enter the routine name'),
|
||||
duration: const Duration(seconds: 2),
|
||||
backgroundColor: ColorsManager.red,
|
||||
action: SnackBarAction(
|
||||
label: 'Dismiss',
|
||||
onPressed: () {
|
||||
// Optional action on Snackbar
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.ifItems.isEmpty || state.thenItems.isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: const Text('Please add if and then condition'),
|
||||
duration: const Duration(seconds: 2),
|
||||
backgroundColor: ColorsManager.red,
|
||||
action: SnackBarAction(
|
||||
label: 'Dismiss',
|
||||
onPressed: () {
|
||||
// Optional action on Snackbar
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
SaveRoutineHelper.showSaveRoutineDialog(context);
|
||||
},
|
||||
borderRadius: 15,
|
||||
@ -138,78 +344,8 @@ class RoutineSearchAndButtons extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
if (constraints.maxWidth <= 1000)
|
||||
Wrap(
|
||||
runSpacing: 12,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 40,
|
||||
width: 200,
|
||||
child: Center(
|
||||
child: DefaultButton(
|
||||
onPressed: () {},
|
||||
borderRadius: 15,
|
||||
elevation: 0,
|
||||
borderColor: ColorsManager.greyColor,
|
||||
backgroundColor: ColorsManager.boxColor,
|
||||
child: const Text(
|
||||
'Settings',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: ColorsManager.primaryColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
SizedBox(
|
||||
height: 40,
|
||||
width: 200,
|
||||
child: Center(
|
||||
child: DefaultButton(
|
||||
onPressed: () {},
|
||||
borderRadius: 15,
|
||||
elevation: 0,
|
||||
borderColor: ColorsManager.greyColor,
|
||||
backgroundColor: ColorsManager.boxColor,
|
||||
child: const Text(
|
||||
'Cancel',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: ColorsManager.blackColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
SizedBox(
|
||||
height: 40,
|
||||
width: 200,
|
||||
child: Center(
|
||||
child: DefaultButton(
|
||||
onPressed: () {},
|
||||
borderRadius: 15,
|
||||
elevation: 0,
|
||||
backgroundColor: ColorsManager.primaryColor,
|
||||
child: const Text(
|
||||
'Save',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: ColorsManager.whiteColors,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@ -26,7 +26,7 @@ class _ScenesAndAutomationsState extends State<ScenesAndAutomations> {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<RoutineBloc, RoutineState>(
|
||||
builder: (context, state) {
|
||||
if (state.scenes.isNotEmpty || state.automations.isNotEmpty) {
|
||||
if (!state.isLoading) {
|
||||
var scenes = [...state.scenes, ...state.automations];
|
||||
return Wrap(
|
||||
spacing: 10,
|
||||
|
@ -26,9 +26,7 @@ class ThenContainer extends StatelessWidget {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text('THEN',
|
||||
style: TextStyle(
|
||||
fontSize: 18, fontWeight: FontWeight.bold)),
|
||||
const Text('THEN', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 16),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
@ -37,16 +35,12 @@ class ThenContainer extends StatelessWidget {
|
||||
state.thenItems.length,
|
||||
(index) => GestureDetector(
|
||||
onTap: () async {
|
||||
if (state.thenItems[index]['deviceId'] ==
|
||||
'delay') {
|
||||
final result = await DelayHelper
|
||||
.showDelayPickerDialog(
|
||||
context, state.thenItems[index]);
|
||||
if (state.thenItems[index]['deviceId'] == 'delay') {
|
||||
final result = await DelayHelper.showDelayPickerDialog(
|
||||
context, state.thenItems[index]);
|
||||
|
||||
if (result != null) {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToThenContainer({
|
||||
context.read<RoutineBloc>().add(AddToThenContainer({
|
||||
...state.thenItems[index],
|
||||
'imagePath': Assets.delay,
|
||||
'title': 'Delay',
|
||||
@ -55,37 +49,32 @@ class ThenContainer extends StatelessWidget {
|
||||
return;
|
||||
}
|
||||
|
||||
final result = await DeviceDialogHelper
|
||||
.showDeviceDialog(
|
||||
context, state.thenItems[index]);
|
||||
final result = await DeviceDialogHelper.showDeviceDialog(
|
||||
context, state.thenItems[index]);
|
||||
|
||||
if (result != null) {
|
||||
context.read<RoutineBloc>().add(
|
||||
AddToThenContainer(
|
||||
state.thenItems[index]));
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToThenContainer(state.thenItems[index]));
|
||||
} else if (!['AC', '1G', '2G', '3G']
|
||||
.contains(state.thenItems[index]
|
||||
['productType'])) {
|
||||
context.read<RoutineBloc>().add(
|
||||
AddToThenContainer(
|
||||
state.thenItems[index]));
|
||||
.contains(state.thenItems[index]['productType'])) {
|
||||
context
|
||||
.read<RoutineBloc>()
|
||||
.add(AddToThenContainer(state.thenItems[index]));
|
||||
}
|
||||
},
|
||||
child: DraggableCard(
|
||||
imagePath: state.thenItems[index]
|
||||
['imagePath'] ??
|
||||
'',
|
||||
title:
|
||||
state.thenItems[index]['title'] ?? '',
|
||||
imagePath: state.thenItems[index]['imagePath'] ?? '',
|
||||
title: state.thenItems[index]['title'] ?? '',
|
||||
deviceData: state.thenItems[index],
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 4, vertical: 8),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 8),
|
||||
isFromThen: true,
|
||||
isFromIf: false,
|
||||
onRemove: () {
|
||||
context.read<RoutineBloc>().add(
|
||||
RemoveDragCard(
|
||||
index: index, isFromThen: true));
|
||||
context.read<RoutineBloc>().add(RemoveDragCard(
|
||||
index: index,
|
||||
isFromThen: true,
|
||||
key: state.thenItems[index]['uniqueCustomId']));
|
||||
},
|
||||
),
|
||||
))),
|
||||
@ -140,8 +129,7 @@ class ThenContainer extends StatelessWidget {
|
||||
}
|
||||
|
||||
if (mutableData['deviceId'] == 'delay') {
|
||||
final result =
|
||||
await DelayHelper.showDelayPickerDialog(context, mutableData);
|
||||
final result = await DelayHelper.showDelayPickerDialog(context, mutableData);
|
||||
|
||||
if (result != null) {
|
||||
context.read<RoutineBloc>().add(AddToThenContainer({
|
||||
@ -153,13 +141,11 @@ class ThenContainer extends StatelessWidget {
|
||||
return;
|
||||
}
|
||||
|
||||
final result =
|
||||
await DeviceDialogHelper.showDeviceDialog(context, mutableData);
|
||||
final result = await DeviceDialogHelper.showDeviceDialog(context, mutableData);
|
||||
|
||||
if (result != null) {
|
||||
context.read<RoutineBloc>().add(AddToThenContainer(mutableData));
|
||||
} else if (!['AC', '1G', '2G', '3G']
|
||||
.contains(mutableData['productType'])) {
|
||||
} else if (!['AC', '1G', '2G', '3G'].contains(mutableData['productType'])) {
|
||||
context.read<RoutineBloc>().add(AddToThenContainer(mutableData));
|
||||
}
|
||||
},
|
||||
|
@ -29,11 +29,13 @@ class SceneApi {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// create automation
|
||||
static Future<Map<String, dynamic>> createAutomation(
|
||||
CreateAutomationModel createAutomationModel) async {
|
||||
try {
|
||||
debugPrint("automation body ${createAutomationModel.toMap()}");
|
||||
final response = await _httpService.post(
|
||||
path: ApiEndpoints.createAutomation,
|
||||
body: createAutomationModel.toMap(),
|
||||
@ -42,8 +44,10 @@ class SceneApi {
|
||||
return json;
|
||||
},
|
||||
);
|
||||
debugPrint('create automation response: $response');
|
||||
return response;
|
||||
} catch (e) {
|
||||
debugPrint(e.toString());
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,11 @@ extension BuildContextExt on BuildContext {
|
||||
VoidCallback? onDismiss,
|
||||
bool? hideConfirmButton,
|
||||
final double? dialogWidth,
|
||||
TextStyle? titleStyle,
|
||||
String? onDismissText,
|
||||
String? onConfirmText,
|
||||
Color? onDismissColor,
|
||||
Color? onConfirmColor,
|
||||
}) {
|
||||
showDialog(
|
||||
context: this,
|
||||
@ -42,10 +47,11 @@ extension BuildContextExt on BuildContext {
|
||||
/// header widget
|
||||
Text(
|
||||
title,
|
||||
style: context.textTheme.bodyMedium!.copyWith(
|
||||
color: ColorsManager.primaryColorWithOpacity,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
style: titleStyle ??
|
||||
context.textTheme.bodyMedium!.copyWith(
|
||||
color: ColorsManager.primaryColorWithOpacity,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
@ -79,9 +85,10 @@ extension BuildContextExt on BuildContext {
|
||||
},
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Cancel',
|
||||
style: context.textTheme.bodyMedium!
|
||||
.copyWith(color: ColorsManager.greyColor),
|
||||
onDismissText ?? 'Cancel',
|
||||
style: context.textTheme.bodyMedium!.copyWith(
|
||||
color: onDismissColor ??
|
||||
ColorsManager.greyColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -94,9 +101,9 @@ extension BuildContextExt on BuildContext {
|
||||
onTap: onConfirm,
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Confirm',
|
||||
onConfirmText ?? 'Confirm',
|
||||
style: context.textTheme.bodyMedium!.copyWith(
|
||||
color:
|
||||
color: onConfirmColor ??
|
||||
ColorsManager.primaryColorWithOpacity),
|
||||
),
|
||||
),
|
||||
|
Reference in New Issue
Block a user