Bug fixes

This commit is contained in:
Abdullah Alassaf
2024-12-02 03:58:31 +03:00
parent 1aa6b78fb4
commit ff4ce8ed01
14 changed files with 295 additions and 452 deletions

View File

@ -1,28 +0,0 @@
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
part 'switch_tabs_event.dart';
part 'switch_tabs_state.dart';
class SwitchTabsBloc extends Bloc<SwitchTabsEvent, SwitchTabsState> {
SwitchTabsBloc() : super(SwitchTabsInitial()) {
on<TriggerSwitchTabsEvent>(_switchTab);
on<CreateNewRoutineViewEvent>(_newRoutineView);
}
FutureOr<void> _switchTab(
TriggerSwitchTabsEvent event,
Emitter<SwitchTabsState> emit,
) {
emit(SelectedTabState(event.isRoutineView));
}
FutureOr<void> _newRoutineView(
CreateNewRoutineViewEvent event,
Emitter<SwitchTabsState> emit,
) {
emit(ShowCreateRoutineState(event.showCreateNewRoutineView));
}
}

View File

@ -1,21 +0,0 @@
part of 'switch_tabs_bloc.dart';
sealed class SwitchTabsEvent extends Equatable {
const SwitchTabsEvent();
}
class TriggerSwitchTabsEvent extends SwitchTabsEvent {
final bool isRoutineView;
const TriggerSwitchTabsEvent(this.isRoutineView);
@override
List<Object?> get props => [isRoutineView];
}
class CreateNewRoutineViewEvent extends SwitchTabsEvent {
final bool showCreateNewRoutineView;
const CreateNewRoutineViewEvent(this.showCreateNewRoutineView);
@override
List<Object?> get props => [showCreateNewRoutineView];
}

View File

@ -1,26 +0,0 @@
part of 'switch_tabs_bloc.dart';
sealed class SwitchTabsState extends Equatable {
const SwitchTabsState();
}
final class SwitchTabsInitial extends SwitchTabsState {
@override
List<Object> get props => [];
}
class SelectedTabState extends SwitchTabsState {
final bool selectedTab;
const SelectedTabState(this.selectedTab);
@override
List<Object?> get props => [selectedTab];
}
class ShowCreateRoutineState extends SwitchTabsState {
final bool showCreateRoutine;
const ShowCreateRoutineState(this.showCreateRoutine);
@override
List<Object?> get props => [showCreateRoutine];
}

View File

@ -1,9 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_mgmt_bloc/device_managment_bloc.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_mgmt_bloc/device_managment_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/switch_tabs/switch_tabs_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_managment_body.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_managment_body.dart';
import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart'; import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart';
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
import 'package:syncrow_web/pages/routiens/view/create_new_routine_view.dart'; import 'package:syncrow_web/pages/routiens/view/create_new_routine_view.dart';
import 'package:syncrow_web/pages/routiens/view/routines_view.dart'; import 'package:syncrow_web/pages/routiens/view/routines_view.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
@ -18,10 +18,6 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MultiBlocProvider( return MultiBlocProvider(
providers: [ providers: [
BlocProvider(
create: (context) =>
SwitchTabsBloc()..add(const TriggerSwitchTabsEvent(false)),
),
BlocProvider( BlocProvider(
create: (context) => DeviceManagementBloc()..add(FetchDevices()), create: (context) => DeviceManagementBloc()..add(FetchDevices()),
), ),
@ -33,8 +29,7 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
style: Theme.of(context).textTheme.headlineLarge, style: Theme.of(context).textTheme.headlineLarge,
), ),
), ),
centerBody: BlocBuilder<SwitchTabsBloc, SwitchTabsState>( centerBody: BlocBuilder<RoutineBloc, RoutineState>(builder: (context, state) {
builder: (context, state) {
return Row( return Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@ -44,20 +39,14 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
), ),
onPressed: () { onPressed: () {
context context
.read<SwitchTabsBloc>() .read<RoutineBloc>()
.add(const TriggerSwitchTabsEvent(false)); .add(const TriggerSwitchTabsEvent(isRoutineTab: false));
}, },
child: Text( child: Text(
'Devices', 'Devices',
style: context.textTheme.titleMedium?.copyWith( style: context.textTheme.titleMedium?.copyWith(
color: color: !state.routineTab ? ColorsManager.whiteColors : ColorsManager.grayColor,
state is SelectedTabState && state.selectedTab == false fontWeight: !state.routineTab ? FontWeight.w700 : FontWeight.w400,
? ColorsManager.whiteColors
: ColorsManager.grayColor,
fontWeight: (state is SelectedTabState) &&
state.selectedTab == false
? FontWeight.w700
: FontWeight.w400,
), ),
), ),
), ),
@ -66,21 +55,13 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
backgroundColor: null, backgroundColor: null,
), ),
onPressed: () { onPressed: () {
context context.read<RoutineBloc>().add(const TriggerSwitchTabsEvent(isRoutineTab: true));
.read<SwitchTabsBloc>()
.add(const TriggerSwitchTabsEvent(true));
}, },
child: Text( child: Text(
'Routines', 'Routines',
style: context.textTheme.titleMedium?.copyWith( style: context.textTheme.titleMedium?.copyWith(
color: color: state.routineTab ? ColorsManager.whiteColors : ColorsManager.grayColor,
(state is SelectedTabState) && state.selectedTab == true fontWeight: state.routineTab ? FontWeight.w700 : FontWeight.w400,
? ColorsManager.whiteColors
: ColorsManager.grayColor,
fontWeight:
(state is SelectedTabState) && state.selectedTab == true
? FontWeight.w700
: FontWeight.w400,
), ),
), ),
), ),
@ -88,13 +69,12 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
); );
}), }),
rightBody: const NavigateHomeGridView(), rightBody: const NavigateHomeGridView(),
scaffoldBody: BlocBuilder<SwitchTabsBloc, SwitchTabsState>( scaffoldBody: BlocBuilder<RoutineBloc, RoutineState>(builder: (context, state) {
builder: (context, state) { if (state.routineTab) {
if (state is SelectedTabState && state.selectedTab) {
return const RoutinesView(); return const RoutinesView();
} }
if (state is ShowCreateRoutineState && state.showCreateRoutine) { if (state.createRoutineView) {
return CreateNewRoutineView(); return CreateNewRoutineView();
} }
return BlocBuilder<DeviceManagementBloc, DeviceManagementState>( return BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
@ -104,8 +84,7 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
} else if (deviceState is DeviceManagementLoaded) { } else if (deviceState is DeviceManagementLoaded) {
return DeviceManagementBody(devices: deviceState.devices); return DeviceManagementBody(devices: deviceState.devices);
} else if (deviceState is DeviceManagementFiltered) { } else if (deviceState is DeviceManagementFiltered) {
return DeviceManagementBody( return DeviceManagementBody(devices: deviceState.filteredDevices);
devices: deviceState.filteredDevices);
} else { } else {
return const Center(child: Text('Error fetching Devices')); return const Center(child: Text('Error fetching Devices'));
} }

View File

@ -6,6 +6,7 @@ import 'package:syncrow_web/pages/auth/model/user_model.dart';
import 'package:syncrow_web/pages/home/bloc/home_event.dart'; import 'package:syncrow_web/pages/home/bloc/home_event.dart';
import 'package:syncrow_web/pages/home/bloc/home_state.dart'; import 'package:syncrow_web/pages/home/bloc/home_state.dart';
import 'package:syncrow_web/pages/home/home_model/home_item_model.dart'; import 'package:syncrow_web/pages/home/home_model/home_item_model.dart';
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
import 'package:syncrow_web/services/home_api.dart'; import 'package:syncrow_web/services/home_api.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/assets.dart';
@ -41,8 +42,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
Future _fetchUserInfo(FetchUserInfo event, Emitter<HomeState> emit) async { Future _fetchUserInfo(FetchUserInfo event, Emitter<HomeState> emit) async {
try { try {
var uuid = var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
user = await HomeApi().fetchUserInfo(uuid); user = await HomeApi().fetchUserInfo(uuid);
emit(HomeInitial()); emit(HomeInitial());
} catch (e) { } catch (e) {
@ -84,6 +84,8 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
icon: Assets.devicesIcon, icon: Assets.devicesIcon,
active: true, active: true,
onPress: (context) { onPress: (context) {
BlocProvider.of<RoutineBloc>(context)
.add(const TriggerSwitchTabsEvent(isRoutineTab: false));
context.go(RoutesConst.deviceManagementPage); context.go(RoutesConst.deviceManagementPage);
}, },
color: ColorsManager.primaryColor, color: ColorsManager.primaryColor,

View File

@ -13,7 +13,6 @@ import 'package:syncrow_web/pages/routiens/models/routine_model.dart';
import 'package:syncrow_web/services/devices_mang_api.dart'; import 'package:syncrow_web/services/devices_mang_api.dart';
import 'package:syncrow_web/services/routines_api.dart'; import 'package:syncrow_web/services/routines_api.dart';
import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/navigation_service.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
part 'routine_event.dart'; part 'routine_event.dart';
@ -46,14 +45,35 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
on<UpdateScene>(_onUpdateScene); on<UpdateScene>(_onUpdateScene);
on<UpdateAutomation>(_onUpdateAutomation); on<UpdateAutomation>(_onUpdateAutomation);
on<SetAutomationActionExecutor>(_onSetAutomationActionExecutor); on<SetAutomationActionExecutor>(_onSetAutomationActionExecutor);
on<TriggerSwitchTabsEvent>(_triggerSwitchTabsEvent);
on<CreateNewRoutineViewEvent>(_createNewRoutineViewEvent);
}
FutureOr<void> _triggerSwitchTabsEvent(
TriggerSwitchTabsEvent event,
Emitter<RoutineState> emit,
) {
emit(state.copyWith(routineTab: event.isRoutineTab, createRoutineView: false));
add(ResetRoutineState());
if (event.isRoutineTab) {
add(const LoadScenes(spaceId, communityId));
add(const LoadAutomation(spaceId));
}
}
FutureOr<void> _createNewRoutineViewEvent(
CreateNewRoutineViewEvent event,
Emitter<RoutineState> emit,
) {
emit(state.copyWith(createRoutineView: event.createRoutineView));
} }
void _onAddToIfContainer(AddToIfContainer event, Emitter<RoutineState> emit) { void _onAddToIfContainer(AddToIfContainer event, Emitter<RoutineState> emit) {
final updatedIfItems = List<Map<String, dynamic>>.from(state.ifItems); final updatedIfItems = List<Map<String, dynamic>>.from(state.ifItems);
// Find the index of the item in teh current itemsList // Find the index of the item in teh current itemsList
int index = updatedIfItems.indexWhere( int index =
(map) => map['uniqueCustomId'] == event.item['uniqueCustomId']); updatedIfItems.indexWhere((map) => map['uniqueCustomId'] == event.item['uniqueCustomId']);
// Replace the map if the index is valid // Replace the map if the index is valid
if (index != -1) { if (index != -1) {
updatedIfItems[index] = event.item; updatedIfItems[index] = event.item;
@ -62,21 +82,18 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
} }
if (event.isTabToRun) { if (event.isTabToRun) {
emit(state.copyWith( emit(state.copyWith(ifItems: updatedIfItems, isTabToRun: true, isAutomation: false));
ifItems: updatedIfItems, isTabToRun: true, isAutomation: false));
} else { } else {
emit(state.copyWith( emit(state.copyWith(ifItems: updatedIfItems, isTabToRun: false, isAutomation: true));
ifItems: updatedIfItems, isTabToRun: false, isAutomation: true));
} }
} }
void _onAddToThenContainer( void _onAddToThenContainer(AddToThenContainer event, Emitter<RoutineState> emit) {
AddToThenContainer event, Emitter<RoutineState> emit) {
final currentItems = List<Map<String, dynamic>>.from(state.thenItems); final currentItems = List<Map<String, dynamic>>.from(state.thenItems);
// Find the index of the item in teh current itemsList // Find the index of the item in teh current itemsList
int index = currentItems.indexWhere( int index =
(map) => map['uniqueCustomId'] == event.item['uniqueCustomId']); currentItems.indexWhere((map) => map['uniqueCustomId'] == event.item['uniqueCustomId']);
// Replace the map if the index is valid // Replace the map if the index is valid
if (index != -1) { if (index != -1) {
currentItems[index] = event.item; currentItems[index] = event.item;
@ -87,26 +104,22 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
emit(state.copyWith(thenItems: currentItems)); emit(state.copyWith(thenItems: currentItems));
} }
void _onAddFunctionsToRoutine( void _onAddFunctionsToRoutine(AddFunctionToRoutine event, Emitter<RoutineState> emit) {
AddFunctionToRoutine event, Emitter<RoutineState> emit) {
try { try {
if (event.functions.isEmpty) return; if (event.functions.isEmpty) return;
List<DeviceFunctionData> selectedFunction = List<DeviceFunctionData> selectedFunction = List<DeviceFunctionData>.from(event.functions);
List<DeviceFunctionData>.from(event.functions);
Map<String, List<DeviceFunctionData>> currentSelectedFunctions = Map<String, List<DeviceFunctionData>> currentSelectedFunctions =
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions); Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
if (currentSelectedFunctions.containsKey(event.uniqueCustomId)) { if (currentSelectedFunctions.containsKey(event.uniqueCustomId)) {
List<DeviceFunctionData> currentFunctions = List<DeviceFunctionData> currentFunctions =
List<DeviceFunctionData>.from( List<DeviceFunctionData>.from(currentSelectedFunctions[event.uniqueCustomId] ?? []);
currentSelectedFunctions[event.uniqueCustomId] ?? []);
List<String> functionCode = []; List<String> functionCode = [];
for (int i = 0; i < selectedFunction.length; i++) { for (int i = 0; i < selectedFunction.length; i++) {
for (int j = 0; j < currentFunctions.length; j++) { for (int j = 0; j < currentFunctions.length; j++) {
if (selectedFunction[i].functionCode == if (selectedFunction[i].functionCode == currentFunctions[j].functionCode) {
currentFunctions[j].functionCode) {
currentFunctions[j] = selectedFunction[i]; currentFunctions[j] = selectedFunction[i];
if (!functionCode.contains(currentFunctions[j].functionCode)) { if (!functionCode.contains(currentFunctions[j].functionCode)) {
functionCode.add(currentFunctions[j].functionCode); functionCode.add(currentFunctions[j].functionCode);
@ -116,15 +129,13 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
} }
for (int i = 0; i < functionCode.length; i++) { for (int i = 0; i < functionCode.length; i++) {
selectedFunction selectedFunction.removeWhere((code) => code.functionCode == functionCode[i]);
.removeWhere((code) => code.functionCode == functionCode[i]);
} }
currentSelectedFunctions[event.uniqueCustomId] = currentSelectedFunctions[event.uniqueCustomId] = List.from(currentFunctions)
List.from(currentFunctions)..addAll(selectedFunction); ..addAll(selectedFunction);
} else { } else {
currentSelectedFunctions[event.uniqueCustomId] = currentSelectedFunctions[event.uniqueCustomId] = List.from(event.functions);
List.from(event.functions);
} }
emit(state.copyWith(selectedFunctions: currentSelectedFunctions)); emit(state.copyWith(selectedFunctions: currentSelectedFunctions));
@ -133,13 +144,11 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
} }
} }
Future<void> _onLoadScenes( Future<void> _onLoadScenes(LoadScenes event, Emitter<RoutineState> emit) async {
LoadScenes event, Emitter<RoutineState> emit) async {
emit(state.copyWith(isLoading: true, errorMessage: null)); emit(state.copyWith(isLoading: true, errorMessage: null));
try { try {
final scenes = final scenes = await SceneApi.getScenesByUnitId(event.unitId, event.communityId);
await SceneApi.getScenesByUnitId(event.unitId, event.communityId);
emit(state.copyWith( emit(state.copyWith(
scenes: scenes, scenes: scenes,
isLoading: false, isLoading: false,
@ -154,8 +163,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
} }
} }
Future<void> _onLoadAutomation( Future<void> _onLoadAutomation(LoadAutomation event, Emitter<RoutineState> emit) async {
LoadAutomation event, Emitter<RoutineState> emit) async {
emit(state.copyWith(isLoading: true, errorMessage: null)); emit(state.copyWith(isLoading: true, errorMessage: null));
try { try {
@ -183,16 +191,14 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
} }
} }
FutureOr<void> _onSearchRoutines( FutureOr<void> _onSearchRoutines(SearchRoutines event, Emitter<RoutineState> emit) async {
SearchRoutines event, Emitter<RoutineState> emit) async {
emit(state.copyWith(isLoading: true, errorMessage: null)); emit(state.copyWith(isLoading: true, errorMessage: null));
await Future.delayed(const Duration(seconds: 1)); await Future.delayed(const Duration(seconds: 1));
emit(state.copyWith(isLoading: false, errorMessage: null)); emit(state.copyWith(isLoading: false, errorMessage: null));
emit(state.copyWith(searchText: event.query)); emit(state.copyWith(searchText: event.query));
} }
FutureOr<void> _onAddSelectedIcon( FutureOr<void> _onAddSelectedIcon(AddSelectedIcon event, Emitter<RoutineState> emit) {
AddSelectedIcon event, Emitter<RoutineState> emit) {
emit(state.copyWith(selectedIcon: event.icon)); emit(state.copyWith(selectedIcon: event.icon));
} }
@ -206,8 +212,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
return actions.last['deviceId'] == 'delay'; return actions.last['deviceId'] == 'delay';
} }
Future<void> _onCreateScene( Future<void> _onCreateScene(CreateSceneEvent event, Emitter<RoutineState> emit) async {
CreateSceneEvent event, Emitter<RoutineState> emit) async {
try { try {
// Check if first action is delay // Check if first action is delay
if (_isFirstActionDelay(state.thenItems)) { if (_isFirstActionDelay(state.thenItems)) {
@ -267,21 +272,20 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
spaceUuid: spaceId, spaceUuid: spaceId,
iconId: state.selectedIcon ?? '', iconId: state.selectedIcon ?? '',
showInDevice: true, showInDevice: true,
sceneName: state.routineName!, sceneName: state.routineName ?? '',
decisionExpr: 'and', decisionExpr: 'and',
actions: actions, actions: actions,
); );
final result = await SceneApi.createScene(createSceneModel); final result = await SceneApi.createScene(createSceneModel);
if (result['success']) { if (result['success']) {
Navigator.of(NavigationService.navigatorKey.currentContext!).pop();
add(ResetRoutineState()); add(ResetRoutineState());
add(const LoadScenes(spaceId, communityId)); add(const LoadScenes(spaceId, communityId));
add(const LoadAutomation(spaceId)); add(const LoadAutomation(spaceId));
} else { } else {
emit(state.copyWith( emit(state.copyWith(
isLoading: false, isLoading: false,
errorMessage: result['message'], errorMessage: 'Something went wrong',
)); ));
} }
} catch (e) { } catch (e) {
@ -292,8 +296,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
} }
} }
Future<void> _onCreateAutomation( Future<void> _onCreateAutomation(CreateAutomationEvent event, Emitter<RoutineState> emit) async {
CreateAutomationEvent event, Emitter<RoutineState> emit) async {
try { try {
if (state.routineName == null || state.routineName!.isEmpty) { if (state.routineName == null || state.routineName!.isEmpty) {
emit(state.copyWith( emit(state.copyWith(
@ -378,7 +381,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
final createAutomationModel = CreateAutomationModel( final createAutomationModel = CreateAutomationModel(
spaceUuid: spaceId, spaceUuid: spaceId,
automationName: state.routineName!, automationName: state.routineName ?? '',
decisionExpr: state.selectedAutomationOperator, decisionExpr: state.selectedAutomationOperator,
effectiveTime: EffectiveTime( effectiveTime: EffectiveTime(
start: state.effectiveTime?.start ?? '00:00', start: state.effectiveTime?.start ?? '00:00',
@ -391,7 +394,6 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
final result = await SceneApi.createAutomation(createAutomationModel); final result = await SceneApi.createAutomation(createAutomationModel);
if (result['success']) { if (result['success']) {
Navigator.of(NavigationService.navigatorKey.currentContext!).pop();
add(ResetRoutineState()); add(ResetRoutineState());
add(const LoadAutomation(spaceId)); add(const LoadAutomation(spaceId));
add(const LoadScenes(spaceId, communityId)); add(const LoadScenes(spaceId, communityId));
@ -409,21 +411,17 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
} }
} }
FutureOr<void> _onRemoveDragCard( FutureOr<void> _onRemoveDragCard(RemoveDragCard event, Emitter<RoutineState> emit) {
RemoveDragCard event, Emitter<RoutineState> emit) {
if (event.isFromThen) { if (event.isFromThen) {
final thenItems = List<Map<String, dynamic>>.from(state.thenItems); final thenItems = List<Map<String, dynamic>>.from(state.thenItems);
final selectedFunctions = final selectedFunctions = Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
thenItems.removeAt(event.index); thenItems.removeAt(event.index);
selectedFunctions.remove(event.key); selectedFunctions.remove(event.key);
emit(state.copyWith( emit(state.copyWith(thenItems: thenItems, selectedFunctions: selectedFunctions));
thenItems: thenItems, selectedFunctions: selectedFunctions));
} else { } else {
final ifItems = List<Map<String, dynamic>>.from(state.ifItems); final ifItems = List<Map<String, dynamic>>.from(state.ifItems);
final selectedFunctions = final selectedFunctions = Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
ifItems.removeAt(event.index); ifItems.removeAt(event.index);
selectedFunctions.remove(event.key); selectedFunctions.remove(event.key);
@ -434,8 +432,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
isAutomation: false, isAutomation: false,
isTabToRun: false)); isTabToRun: false));
} else { } else {
emit(state.copyWith( emit(state.copyWith(ifItems: ifItems, selectedFunctions: selectedFunctions));
ifItems: ifItems, selectedFunctions: selectedFunctions));
} }
} }
} }
@ -447,21 +444,18 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
)); ));
} }
FutureOr<void> _onEffectiveTimeEvent( FutureOr<void> _onEffectiveTimeEvent(EffectiveTimePeriodEvent event, Emitter<RoutineState> emit) {
EffectiveTimePeriodEvent event, Emitter<RoutineState> emit) {
emit(state.copyWith(effectiveTime: event.effectiveTime)); emit(state.copyWith(effectiveTime: event.effectiveTime));
} }
FutureOr<void> _onSetRoutineName( FutureOr<void> _onSetRoutineName(SetRoutineName event, Emitter<RoutineState> emit) {
SetRoutineName event, Emitter<RoutineState> emit) { emit(state.copyWith(
emit(state.copyWith(routineName: event.name)); routineName: event.name,
));
} }
( (List<Map<String, dynamic>>, List<Map<String, dynamic>>, Map<String, List<DeviceFunctionData>>)
List<Map<String, dynamic>>, _createCardData(
List<Map<String, dynamic>>,
Map<String, List<DeviceFunctionData>>
) _createCardData(
List<RoutineAction> actions, List<RoutineAction> actions,
List<RoutineCondition>? conditions, List<RoutineCondition>? conditions,
Map<String, List<DeviceFunctionData>> currentFunctions, Map<String, List<DeviceFunctionData>> currentFunctions,
@ -494,8 +488,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
'deviceId': condition.entityId, 'deviceId': condition.entityId,
'title': matchingDevice.name ?? condition.entityId, 'title': matchingDevice.name ?? condition.entityId,
'productType': condition.entityType, 'productType': condition.entityType,
'imagePath': 'imagePath': matchingDevice.getDefaultIcon(condition.entityType),
matchingDevice.getDefaultIcon(condition.entityType),
}; };
final functions = matchingDevice.functions; final functions = matchingDevice.functions;
@ -531,11 +524,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
final cardData = { final cardData = {
'entityId': action.entityId, 'entityId': action.entityId,
'uniqueCustomId': const Uuid().v4(), 'uniqueCustomId': const Uuid().v4(),
'deviceId': 'deviceId': action.actionExecutor == 'delay' ? 'delay' : action.entityId,
action.actionExecutor == 'delay' ? 'delay' : action.entityId, 'title': action.actionExecutor == 'delay' ? 'Delay' : (matchingDevice.name ?? 'Device'),
'title': action.actionExecutor == 'delay'
? 'Delay'
: (matchingDevice.name ?? 'Device'),
'productType': action.productType, 'productType': action.productType,
'imagePath': matchingDevice.getDefaultIcon(action.productType), 'imagePath': matchingDevice.getDefaultIcon(action.productType),
}; };
@ -578,8 +568,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
return (thenItems, ifItems, currentFunctions); return (thenItems, ifItems, currentFunctions);
} }
Future<void> _onGetSceneDetails( Future<void> _onGetSceneDetails(GetSceneDetails event, Emitter<RoutineState> emit) async {
GetSceneDetails event, Emitter<RoutineState> emit) async {
try { try {
emit(state.copyWith( emit(state.copyWith(
isLoading: true, isLoading: true,
@ -591,7 +580,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
selectedFunctions: {}, selectedFunctions: {},
ifItems: [], ifItems: [],
thenItems: [], thenItems: [],
errorMessage: null, errorMessage: '',
loadScenesErrorMessage: null, loadScenesErrorMessage: null,
loadAutomationErrorMessage: null, loadAutomationErrorMessage: null,
searchText: '', searchText: '',
@ -627,12 +616,10 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
if (!deviceCards.containsKey(deviceId)) { if (!deviceCards.containsKey(deviceId)) {
deviceCards[deviceId] = { deviceCards[deviceId] = {
'entityId': action.entityId, 'entityId': action.entityId,
'deviceId': 'deviceId': action.actionExecutor == 'delay' ? 'delay' : action.entityId,
action.actionExecutor == 'delay' ? 'delay' : action.entityId, 'uniqueCustomId': action.type == 'automation' || action.actionExecutor == 'delay'
'uniqueCustomId': ? const Uuid().v4()
action.type == 'automation' || action.actionExecutor == 'delay' : action.entityId,
? const Uuid().v4()
: action.entityId,
'title': action.actionExecutor == 'delay' 'title': action.actionExecutor == 'delay'
? 'Delay' ? 'Delay'
: action.type == 'automation' : action.type == 'automation'
@ -667,8 +654,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
), ),
); );
emit(state.copyWith(automationActionExecutor: action.actionExecutor)); emit(state.copyWith(automationActionExecutor: action.actionExecutor));
} else if (action.executorProperty != null && } else if (action.executorProperty != null && action.actionExecutor != 'delay') {
action.actionExecutor != 'delay') {
if (!updatedFunctions.containsKey(uniqueCustomId)) { if (!updatedFunctions.containsKey(uniqueCustomId)) {
updatedFunctions[uniqueCustomId] = []; updatedFunctions[uniqueCustomId] = [];
} }
@ -753,8 +739,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
thenItems: [], thenItems: [],
)); ));
final automationDetails = final automationDetails = await SceneApi.getAutomationDetails(event.automationId);
await SceneApi.getAutomationDetails(event.automationId);
final List<Map<String, dynamic>> thenItems; final List<Map<String, dynamic>> thenItems;
final List<Map<String, dynamic>> ifItems; final List<Map<String, dynamic>> ifItems;
@ -773,16 +758,13 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
final cardData = { final cardData = {
'entityId': condition.entityId, 'entityId': condition.entityId,
'uniqueCustomId': const Uuid().v4(), 'uniqueCustomId': const Uuid().v4(),
'deviceId': condition.expr.statusCode == 'delay' 'deviceId': condition.expr.statusCode == 'delay' ? 'delay' : condition.entityId,
? 'delay'
: condition.entityId,
'title': condition.expr.statusCode == 'delay' 'title': condition.expr.statusCode == 'delay'
? 'Delay' ? 'Delay'
: (matchingDevice?.name ?? 'Device'), : (matchingDevice?.name ?? 'Device'),
'productType': condition.productType, 'productType': condition.productType,
'functions': matchingDevice?.functions ?? [], 'functions': matchingDevice?.functions ?? [],
'imagePath': 'imagePath': matchingDevice?.getDefaultIcon(condition.productType) ?? '',
matchingDevice?.getDefaultIcon(condition.productType) ?? '',
'device': matchingDevice, 'device': matchingDevice,
}; };
@ -819,19 +801,15 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
final cardData = { final cardData = {
'entityId': action.entityId, 'entityId': action.entityId,
'uniqueCustomId': const Uuid().v4(), 'uniqueCustomId': const Uuid().v4(),
'deviceId': 'deviceId': action.actionExecutor == 'delay' ? 'delay' : action.entityId,
action.actionExecutor == 'delay' ? 'delay' : action.entityId, 'title': action.actionExecutor == 'delay' ? 'Delay' : (matchingDevice.name ?? 'Device'),
'title': action.actionExecutor == 'delay'
? 'Delay'
: (matchingDevice.name ?? 'Device'),
'productType': action.productType, 'productType': action.productType,
'functions': matchingDevice.functions, 'functions': matchingDevice.functions,
'imagePath': matchingDevice.getDefaultIcon(action.productType), 'imagePath': matchingDevice.getDefaultIcon(action.productType),
'device': matchingDevice, 'device': matchingDevice,
}; };
if (action.executorProperty != null && if (action.executorProperty != null && action.actionExecutor != 'delay') {
action.actionExecutor != 'delay') {
final functions = matchingDevice.functions; final functions = matchingDevice.functions;
final functionCode = action.executorProperty!.functionCode; final functionCode = action.executorProperty!.functionCode;
for (var function in functions) { for (var function in functions) {
@ -894,26 +872,26 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
} }
} }
FutureOr<void> _onResetRoutineState( FutureOr<void> _onResetRoutineState(ResetRoutineState event, Emitter<RoutineState> emit) {
ResetRoutineState event, Emitter<RoutineState> emit) {
emit(state.copyWith( emit(state.copyWith(
ifItems: [], ifItems: [],
thenItems: [], thenItems: [],
selectedFunctions: {}, selectedFunctions: {},
scenes: [], scenes: [],
automations: [], automations: [],
isLoading: false, isLoading: false,
errorMessage: null, errorMessage: '',
loadScenesErrorMessage: null, loadScenesErrorMessage: null,
loadAutomationErrorMessage: null, loadAutomationErrorMessage: null,
searchText: '', searchText: '',
selectedIcon: null, selectedIcon: null,
isTabToRun: false, isTabToRun: false,
isAutomation: false, isAutomation: false,
selectedAutomationOperator: 'or', selectedAutomationOperator: 'or',
effectiveTime: null, effectiveTime: null,
routineName: null, routineName: '',
)); isUpdate: false,
createRoutineView: false));
} }
FutureOr<void> _deleteScene(DeleteScene event, Emitter<RoutineState> emit) { FutureOr<void> _deleteScene(DeleteScene event, Emitter<RoutineState> emit) {
@ -922,13 +900,13 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
if (state.isTabToRun) { if (state.isTabToRun) {
SceneApi.deleteScene(unitUuid: spaceId, sceneId: state.sceneId ?? ''); SceneApi.deleteScene(unitUuid: spaceId, sceneId: state.sceneId ?? '');
} else { } else {
SceneApi.deleteAutomation( SceneApi.deleteAutomation(unitUuid: spaceId, automationId: state.automationId ?? '');
unitUuid: spaceId, automationId: state.automationId ?? '');
} }
add(const LoadScenes(spaceId, communityId)); add(const LoadScenes(spaceId, communityId));
add(const LoadAutomation(spaceId)); add(const LoadAutomation(spaceId));
add(ResetRoutineState()); add(ResetRoutineState());
emit(state.copyWith(isLoading: false, createRoutineView: false));
} catch (e) { } catch (e) {
emit(state.copyWith( emit(state.copyWith(
isLoading: false, isLoading: false,
@ -951,8 +929,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
// } // }
// } // }
FutureOr<void> _fetchDevices( FutureOr<void> _fetchDevices(FetchDevicesInRoutine event, Emitter<RoutineState> emit) async {
FetchDevicesInRoutine event, Emitter<RoutineState> emit) async {
emit(state.copyWith(isLoading: true)); emit(state.copyWith(isLoading: true));
try { try {
final devices = await DevicesManagementApi().fetchDevices(); final devices = await DevicesManagementApi().fetchDevices();
@ -963,8 +940,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
} }
} }
FutureOr<void> _onUpdateScene( FutureOr<void> _onUpdateScene(UpdateScene event, Emitter<RoutineState> emit) async {
UpdateScene event, Emitter<RoutineState> emit) async {
try { try {
// Check if first action is delay // Check if first action is delay
if (_isFirstActionDelay(state.thenItems)) { if (_isFirstActionDelay(state.thenItems)) {
@ -1030,10 +1006,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
actions: actions, actions: actions,
); );
final result = final result = await SceneApi.updateScene(createSceneModel, state.sceneId ?? '');
await SceneApi.updateScene(createSceneModel, state.sceneId ?? '');
if (result['success']) { if (result['success']) {
Navigator.of(NavigationService.navigatorKey.currentContext!).pop();
add(ResetRoutineState()); add(ResetRoutineState());
add(const LoadScenes(spaceId, communityId)); add(const LoadScenes(spaceId, communityId));
add(const LoadAutomation(spaceId)); add(const LoadAutomation(spaceId));
@ -1051,8 +1025,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
} }
} }
FutureOr<void> _onUpdateAutomation( FutureOr<void> _onUpdateAutomation(UpdateAutomation event, Emitter<RoutineState> emit) async {
UpdateAutomation event, Emitter<RoutineState> emit) async {
if (_isFirstActionDelay(state.thenItems)) { if (_isFirstActionDelay(state.thenItems)) {
emit(state.copyWith( emit(state.copyWith(
errorMessage: 'Cannot have delay as the first action', errorMessage: 'Cannot have delay as the first action',
@ -1064,8 +1037,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
try { try {
final conditions = state.ifItems final conditions = state.ifItems
.map((item) { .map((item) {
final functions = final functions = state.selectedFunctions[item['uniqueCustomId']] ?? [];
state.selectedFunctions[item['uniqueCustomId']] ?? [];
if (functions.isEmpty) return null; if (functions.isEmpty) return null;
final function = functions.first; final function = functions.first;
@ -1085,8 +1057,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
final actions = state.thenItems final actions = state.thenItems
.map((item) { .map((item) {
final functions = final functions = state.selectedFunctions[item['uniqueCustomId']] ?? [];
state.selectedFunctions[item['uniqueCustomId']] ?? [];
if (functions.isEmpty) return null; if (functions.isEmpty) return null;
final function = functions.first; final function = functions.first;
@ -1096,9 +1067,8 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
executorProperty: ExecutorProperty( executorProperty: ExecutorProperty(
functionCode: function.functionCode, functionCode: function.functionCode,
functionValue: function.value, functionValue: function.value,
delaySeconds: function.functionCode == 'delay' delaySeconds:
? (function.value as num).toInt() function.functionCode == 'delay' ? (function.value as num).toInt() : null,
: null,
), ),
); );
}) })
@ -1109,17 +1079,24 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
spaceUuid: spaceId, spaceUuid: spaceId,
automationName: state.routineName ?? '', automationName: state.routineName ?? '',
decisionExpr: state.selectedAutomationOperator, decisionExpr: state.selectedAutomationOperator,
effectiveTime: effectiveTime: state.effectiveTime ?? EffectiveTime(start: '', end: '', loops: ''),
state.effectiveTime ?? EffectiveTime(start: '', end: '', loops: ''),
conditions: conditions, conditions: conditions,
actions: actions, actions: actions,
); );
await SceneApi.updateAutomation( final result =
createAutomationModel, state.automationId ?? ''); await SceneApi.updateAutomation(createAutomationModel, state.automationId ?? '');
add(const LoadAutomation(spaceId)); if (result['success']) {
emit(state.copyWith(isLoading: false)); add(ResetRoutineState());
add(const LoadScenes(spaceId, communityId));
add(const LoadAutomation(spaceId));
} else {
emit(state.copyWith(
isLoading: false,
errorMessage: result['message'],
));
}
} catch (e) { } catch (e) {
emit(state.copyWith( emit(state.copyWith(
isLoading: false, isLoading: false,
@ -1130,7 +1107,6 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
FutureOr<void> _onSetAutomationActionExecutor( FutureOr<void> _onSetAutomationActionExecutor(
SetAutomationActionExecutor event, Emitter<RoutineState> emit) { SetAutomationActionExecutor event, Emitter<RoutineState> emit) {
emit(state.copyWith( emit(state.copyWith(automationActionExecutor: event.automationActionExecutor));
automationActionExecutor: event.automationActionExecutor));
} }
} }

View File

@ -187,6 +187,20 @@ class SetAutomationActionExecutor extends RoutineEvent {
List<Object> get props => [automationActionExecutor]; List<Object> get props => [automationActionExecutor];
} }
class TriggerSwitchTabsEvent extends RoutineEvent {
final bool isRoutineTab;
const TriggerSwitchTabsEvent({required this.isRoutineTab});
@override
List<Object> get props => [isRoutineTab];
}
class CreateNewRoutineViewEvent extends RoutineEvent {
final bool createRoutineView;
const CreateNewRoutineViewEvent({required this.createRoutineView});
@override
List<Object> get props => [createRoutineView];
}
class FetchDevicesInRoutine extends RoutineEvent {} class FetchDevicesInRoutine extends RoutineEvent {}
class ResetRoutineState extends RoutineEvent {} class ResetRoutineState extends RoutineEvent {}

View File

@ -23,31 +23,34 @@ class RoutineState extends Equatable {
final bool? isUpdate; final bool? isUpdate;
final List<AllDevicesModel> devices; final List<AllDevicesModel> devices;
final String? automationActionExecutor; final String? automationActionExecutor;
final bool routineTab;
final bool createRoutineView;
const RoutineState({ const RoutineState(
this.ifItems = const [], {this.ifItems = const [],
this.thenItems = const [], this.thenItems = const [],
this.availableCards = const [], this.availableCards = const [],
this.scenes = const [], this.scenes = const [],
this.automations = const [], this.automations = const [],
this.selectedFunctions = const {}, this.selectedFunctions = const {},
this.isLoading = false, this.isLoading = false,
this.errorMessage, this.errorMessage,
this.routineName, this.routineName,
this.selectedIcon, this.selectedIcon,
this.loadScenesErrorMessage, this.loadScenesErrorMessage,
this.loadAutomationErrorMessage, this.loadAutomationErrorMessage,
this.searchText, this.searchText,
this.isTabToRun = false, this.isTabToRun = false,
this.isAutomation = false, this.isAutomation = false,
this.selectedAutomationOperator = 'or', this.selectedAutomationOperator = 'or',
this.effectiveTime, this.effectiveTime,
this.sceneId, this.sceneId,
this.automationId, this.automationId,
this.isUpdate, this.isUpdate,
this.devices = const [], this.devices = const [],
this.automationActionExecutor, this.automationActionExecutor,
}); this.routineTab = false,
this.createRoutineView = false});
RoutineState copyWith({ RoutineState copyWith({
List<Map<String, dynamic>>? ifItems, List<Map<String, dynamic>>? ifItems,
@ -71,34 +74,34 @@ class RoutineState extends Equatable {
bool? isUpdate, bool? isUpdate,
List<AllDevicesModel>? devices, List<AllDevicesModel>? devices,
String? automationActionExecutor, String? automationActionExecutor,
TextEditingController? nameController,
bool? routineTab,
bool? createRoutineView,
}) { }) {
return RoutineState( return RoutineState(
ifItems: ifItems ?? this.ifItems, ifItems: ifItems ?? this.ifItems,
thenItems: thenItems ?? this.thenItems, thenItems: thenItems ?? this.thenItems,
scenes: scenes ?? this.scenes, scenes: scenes ?? this.scenes,
automations: automations ?? this.automations, automations: automations ?? this.automations,
selectedFunctions: selectedFunctions ?? this.selectedFunctions, selectedFunctions: selectedFunctions ?? this.selectedFunctions,
isLoading: isLoading ?? this.isLoading, isLoading: isLoading ?? this.isLoading,
errorMessage: errorMessage ?? this.errorMessage, errorMessage: errorMessage ?? this.errorMessage,
routineName: routineName ?? this.routineName, routineName: routineName ?? this.routineName,
selectedIcon: selectedIcon ?? this.selectedIcon, selectedIcon: selectedIcon ?? this.selectedIcon,
loadScenesErrorMessage: loadScenesErrorMessage: loadScenesErrorMessage ?? this.loadScenesErrorMessage,
loadScenesErrorMessage ?? this.loadScenesErrorMessage, loadAutomationErrorMessage: loadAutomationErrorMessage ?? this.loadAutomationErrorMessage,
loadAutomationErrorMessage: searchText: searchText ?? this.searchText,
loadAutomationErrorMessage ?? this.loadAutomationErrorMessage, isTabToRun: isTabToRun ?? this.isTabToRun,
searchText: searchText ?? this.searchText, isAutomation: isAutomation ?? this.isAutomation,
isTabToRun: isTabToRun ?? this.isTabToRun, selectedAutomationOperator: selectedAutomationOperator ?? this.selectedAutomationOperator,
isAutomation: isAutomation ?? this.isAutomation, effectiveTime: effectiveTime ?? this.effectiveTime,
selectedAutomationOperator: sceneId: sceneId ?? this.sceneId,
selectedAutomationOperator ?? this.selectedAutomationOperator, automationId: automationId ?? this.automationId,
effectiveTime: effectiveTime ?? this.effectiveTime, isUpdate: isUpdate ?? this.isUpdate,
sceneId: sceneId ?? this.sceneId, devices: devices ?? this.devices,
automationId: automationId ?? this.automationId, automationActionExecutor: automationActionExecutor ?? this.automationActionExecutor,
isUpdate: isUpdate ?? this.isUpdate, routineTab: routineTab ?? this.routineTab,
devices: devices ?? this.devices, createRoutineView: createRoutineView ?? this.createRoutineView);
automationActionExecutor:
automationActionExecutor ?? this.automationActionExecutor,
);
} }
@override @override
@ -124,5 +127,7 @@ class RoutineState extends Equatable {
isUpdate, isUpdate,
devices, devices,
automationActionExecutor, automationActionExecutor,
routineTab,
createRoutineView
]; ];
} }

View File

@ -8,8 +8,8 @@ import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/assets.dart';
class SaveRoutineHelper { class SaveRoutineHelper {
static Future<bool?> showSaveRoutineDialog(BuildContext context) async { static Future<void> showSaveRoutineDialog(BuildContext context) async {
return showDialog<bool?>( return showDialog<void>(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return BlocBuilder<RoutineBloc, RoutineState>( return BlocBuilder<RoutineBloc, RoutineState>(
@ -54,27 +54,23 @@ class SaveRoutineHelper {
), ),
if (state.isAutomation) if (state.isAutomation)
...state.ifItems.map((item) { ...state.ifItems.map((item) {
final functions = state.selectedFunctions[ final functions =
item['uniqueCustomId']] ?? state.selectedFunctions[item['uniqueCustomId']] ?? [];
[];
return ListTile( return ListTile(
leading: SvgPicture.asset( leading: SvgPicture.asset(
item['imagePath'], item['imagePath'],
width: 22, width: 22,
height: 22, height: 22,
), ),
title: Text(item['title'], title:
style: const TextStyle(fontSize: 14)), Text(item['title'], style: const TextStyle(fontSize: 14)),
subtitle: Wrap( subtitle: Wrap(
children: functions children: functions
.map((f) => Text( .map((f) => Text(
'${f.operationName}: ${f.value}, ', '${f.operationName}: ${f.value}, ',
style: const TextStyle( style: const TextStyle(
color: ColorsManager color: ColorsManager.grayColor, fontSize: 8),
.grayColor, overflow: TextOverflow.ellipsis,
fontSize: 8),
overflow:
TextOverflow.ellipsis,
maxLines: 3, maxLines: 3,
)) ))
.toList(), .toList(),
@ -99,25 +95,22 @@ class SaveRoutineHelper {
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
...state.thenItems.map((item) { ...state.thenItems.map((item) {
final functions = state.selectedFunctions[ final functions =
item['uniqueCustomId']] ?? state.selectedFunctions[item['uniqueCustomId']] ?? [];
[];
return ListTile( return ListTile(
leading: SvgPicture.asset( leading: SvgPicture.asset(
item['imagePath'], item['imagePath'],
width: 22, width: 22,
height: 22, height: 22,
), ),
title: Text(item['title'], title:
style: const TextStyle(fontSize: 14)), Text(item['title'], style: const TextStyle(fontSize: 14)),
subtitle: Wrap( subtitle: Wrap(
children: functions children: functions
.map((f) => Text( .map((f) => Text(
'${f.operationName}: ${f.value}, ', '${f.operationName}: ${f.value}, ',
style: const TextStyle( style: const TextStyle(
color: color: ColorsManager.grayColor, fontSize: 8),
ColorsManager.grayColor,
fontSize: 8),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 3, maxLines: 3,
)) ))
@ -131,7 +124,7 @@ class SaveRoutineHelper {
], ],
), ),
), ),
if (state.errorMessage != null) if (state.errorMessage != null || state.errorMessage!.isNotEmpty)
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Text( child: Text(
@ -140,32 +133,24 @@ class SaveRoutineHelper {
), ),
), ),
DialogFooter( DialogFooter(
onCancel: () => Navigator.pop(context, false), onCancel: () => Navigator.pop(context),
onConfirm: () { onConfirm: () {
if (state.isAutomation) { if (state.isAutomation) {
if (state.automationId != null) { if (state.automationId != null) {
context context.read<RoutineBloc>().add(const UpdateAutomation());
.read<RoutineBloc>()
.add(const UpdateAutomation());
} else { } else {
context context.read<RoutineBloc>().add(const CreateAutomationEvent());
.read<RoutineBloc>()
.add(const CreateAutomationEvent());
} }
} else { } else {
if (state.sceneId != null) { if (state.sceneId != null) {
context context.read<RoutineBloc>().add(const UpdateScene());
.read<RoutineBloc>()
.add(const UpdateScene());
} else { } else {
context context.read<RoutineBloc>().add(const CreateSceneEvent());
.read<RoutineBloc>()
.add(const CreateSceneEvent());
} }
} }
if (context.read<RoutineBloc>().state.errorMessage == if (context.read<RoutineBloc>().state.errorMessage == null ||
null) { context.read<RoutineBloc>().state.errorMessage!.isEmpty) {
Navigator.pop(context, true); Navigator.pop(context);
} }
}, },
isConfirmEnabled: true, isConfirmEnabled: true,

View File

@ -1,6 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/switch_tabs/switch_tabs_bloc.dart';
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart'; import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
import 'package:syncrow_web/pages/routiens/view/create_new_routine_view.dart'; import 'package:syncrow_web/pages/routiens/view/create_new_routine_view.dart';
import 'package:syncrow_web/pages/routiens/widgets/main_routine_view/fetch_routine_scenes_automation.dart'; import 'package:syncrow_web/pages/routiens/widgets/main_routine_view/fetch_routine_scenes_automation.dart';
@ -23,12 +22,10 @@ class _RoutinesViewState extends State<RoutinesView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<SwitchTabsBloc, SwitchTabsState>( return BlocBuilder<RoutineBloc, RoutineState>(
builder: (context, state) { builder: (context, state) {
if (state is ShowCreateRoutineState && state.showCreateRoutine) { if (state.createRoutineView) {
return const CreateNewRoutineView( return const CreateNewRoutineView();
);
} }
return Padding( return Padding(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
@ -49,12 +46,12 @@ class _RoutinesViewState extends State<RoutinesView> {
), ),
RoutineViewCard( RoutineViewCard(
onTap: () { onTap: () {
BlocProvider.of<SwitchTabsBloc>(context).add(
const CreateNewRoutineViewEvent(true),
);
context.read<RoutineBloc>().add( context.read<RoutineBloc>().add(
(ResetRoutineState()), (ResetRoutineState()),
); );
BlocProvider.of<RoutineBloc>(context).add(
const CreateNewRoutineViewEvent(createRoutineView: true),
);
}, },
icon: Icons.add, icon: Icons.add,
textString: '', textString: '',

View File

@ -33,31 +33,24 @@ class DeleteSceneWidget extends StatelessWidget {
alignment: AlignmentDirectional.center, alignment: AlignmentDirectional.center,
child: Text( child: Text(
'Cancel', 'Cancel',
style: Theme.of(context) style: Theme.of(context).textTheme.bodyMedium!.copyWith(
.textTheme
.bodyMedium!
.copyWith(
color: ColorsManager.textGray, color: ColorsManager.textGray,
), ),
), ),
), ),
), ),
Container( Container(width: 1, height: 50, color: ColorsManager.greyColor),
width: 1, height: 50, color: ColorsManager.greyColor),
InkWell( InkWell(
onTap: () { onTap: () {
context.read<RoutineBloc>().add(const DeleteScene()); context.read<RoutineBloc>().add(const DeleteScene());
Navigator.of(context).pop(); Navigator.of(context).pop();
Navigator.of(context).pop(true); Navigator.of(context).pop();
}, },
child: Container( child: Container(
alignment: AlignmentDirectional.center, alignment: AlignmentDirectional.center,
child: Text( child: Text(
'Confirm', 'Confirm',
style: Theme.of(context) style: Theme.of(context).textTheme.bodyMedium!.copyWith(
.textTheme
.bodyMedium!
.copyWith(
color: ColorsManager.primaryColorWithOpacity, color: ColorsManager.primaryColorWithOpacity,
), ),
), ),

View File

@ -1,6 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/switch_tabs/switch_tabs_bloc.dart';
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart'; import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
import 'package:syncrow_web/pages/routiens/widgets/main_routine_view/routine_view_card.dart'; import 'package:syncrow_web/pages/routiens/widgets/main_routine_view/routine_view_card.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
@ -69,8 +68,8 @@ class _FetchRoutineScenesState extends State<FetchRoutineScenesAutomation>
), ),
child: RoutineViewCard( child: RoutineViewCard(
onTap: () { onTap: () {
BlocProvider.of<SwitchTabsBloc>(context).add( BlocProvider.of<RoutineBloc>(context).add(
const CreateNewRoutineViewEvent(true), const CreateNewRoutineViewEvent(createRoutineView: true),
); );
context.read<RoutineBloc>().add( context.read<RoutineBloc>().add(
GetSceneDetails( GetSceneDetails(
@ -118,8 +117,8 @@ class _FetchRoutineScenesState extends State<FetchRoutineScenesAutomation>
), ),
child: RoutineViewCard( child: RoutineViewCard(
onTap: () { onTap: () {
BlocProvider.of<SwitchTabsBloc>(context).add( BlocProvider.of<RoutineBloc>(context).add(
const CreateNewRoutineViewEvent(true), const CreateNewRoutineViewEvent(createRoutineView: true),
); );
context.read<RoutineBloc>().add( context.read<RoutineBloc>().add(
GetAutomationDetails( GetAutomationDetails(

View File

@ -1,6 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/switch_tabs/switch_tabs_bloc.dart';
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_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/color_manager.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/extension/build_context_x.dart';
@ -49,11 +48,11 @@ class DiscardDialog {
onConfirm: () { onConfirm: () {
context.read<RoutineBloc>().add(ResetRoutineState()); context.read<RoutineBloc>().add(ResetRoutineState());
Navigator.pop(context); Navigator.pop(context);
BlocProvider.of<SwitchTabsBloc>(context).add( BlocProvider.of<RoutineBloc>(context).add(
const CreateNewRoutineViewEvent(false), const CreateNewRoutineViewEvent(createRoutineView: false),
); );
BlocProvider.of<SwitchTabsBloc>(context).add( BlocProvider.of<RoutineBloc>(context).add(
const TriggerSwitchTabsEvent(true), const TriggerSwitchTabsEvent(isRoutineTab: true),
); );
}); });
} }

View File

@ -1,7 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/buttons/default_button.dart'; import 'package:syncrow_web/pages/common/buttons/default_button.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/switch_tabs/switch_tabs_bloc.dart';
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.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/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/discard_dialog.dart';
@ -16,8 +15,7 @@ class RoutineSearchAndButtons extends StatefulWidget {
}); });
@override @override
State<RoutineSearchAndButtons> createState() => State<RoutineSearchAndButtons> createState() => _RoutineSearchAndButtonsState();
_RoutineSearchAndButtonsState();
} }
class _RoutineSearchAndButtonsState extends State<RoutineSearchAndButtons> { class _RoutineSearchAndButtonsState extends State<RoutineSearchAndButtons> {
@ -37,15 +35,9 @@ class _RoutineSearchAndButtonsState extends State<RoutineSearchAndButtons> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocConsumer<RoutineBloc, RoutineState>( return BlocBuilder<RoutineBloc, RoutineState>(
listenWhen: (previous, current) =>
previous.routineName != current.routineName,
listener: (context, state) {
if (state.routineName != _nameController.text) {
_nameController.text = state.routineName ?? '';
}
},
builder: (context, state) { builder: (context, state) {
_nameController.text = state.routineName ?? '';
return LayoutBuilder( return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) { builder: (BuildContext context, BoxConstraints constraints) {
return Wrap( return Wrap(
@ -62,9 +54,8 @@ class _RoutineSearchAndButtonsState extends State<RoutineSearchAndButtons> {
children: [ children: [
ConstrainedBox( ConstrainedBox(
constraints: BoxConstraints( constraints: BoxConstraints(
maxWidth: constraints.maxWidth > 700 maxWidth:
? 450 constraints.maxWidth > 700 ? 450 : constraints.maxWidth - 32),
: constraints.maxWidth - 32),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -73,13 +64,10 @@ class _RoutineSearchAndButtonsState extends State<RoutineSearchAndButtons> {
children: [ children: [
Text('* ', Text('* ',
style: context.textTheme.bodyMedium! style: context.textTheme.bodyMedium!
.copyWith( .copyWith(color: ColorsManager.red, fontSize: 13)),
color: ColorsManager.red,
fontSize: 13)),
Text( Text(
'Routine Name', 'Routine Name',
style: context.textTheme.bodyMedium! style: context.textTheme.bodyMedium!.copyWith(
.copyWith(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: ColorsManager.blackColor, color: ColorsManager.blackColor,
@ -93,24 +81,20 @@ class _RoutineSearchAndButtonsState extends State<RoutineSearchAndButtons> {
decoration: containerWhiteDecoration, decoration: containerWhiteDecoration,
child: TextFormField( child: TextFormField(
style: context.textTheme.bodyMedium! style: context.textTheme.bodyMedium!
.copyWith( .copyWith(color: ColorsManager.blackColor),
color: ColorsManager.blackColor),
controller: _nameController, controller: _nameController,
decoration: InputDecoration( decoration: InputDecoration(
hintText: 'Please enter the name', hintText: 'Please enter the name',
hintStyle: context.textTheme.bodyMedium! hintStyle: context.textTheme.bodyMedium!
.copyWith( .copyWith(fontSize: 12, color: ColorsManager.grayColor),
fontSize: 12,
color: ColorsManager.grayColor),
contentPadding: contentPadding:
const EdgeInsets.symmetric( const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
horizontal: 12, vertical: 10),
border: InputBorder.none, border: InputBorder.none,
), ),
onChanged: (value) { onTapOutside: (_) {
context context
.read<RoutineBloc>() .read<RoutineBloc>()
.add(SetRoutineName(value)); .add(SetRoutineName(_nameController.text));
}, },
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
@ -130,18 +114,16 @@ class _RoutineSearchAndButtonsState extends State<RoutineSearchAndButtons> {
width: 200, width: 200,
child: Center( child: Center(
child: DefaultButton( child: DefaultButton(
onPressed: state.isAutomation || onPressed: state.isAutomation || state.isTabToRun
state.isTabToRun
? () async { ? () async {
final result = await SettingHelper final result = await SettingHelper.showSettingDialog(
.showSettingDialog(
context: context, context: context,
iconId: iconId: state.selectedIcon ?? '',
state.selectedIcon ?? '',
); );
if (result != null) { if (result != null) {
context.read<RoutineBloc>().add( context
AddSelectedIcon(result)); .read<RoutineBloc>()
.add(AddSelectedIcon(result));
} }
} }
: null, : null,
@ -197,12 +179,10 @@ class _RoutineSearchAndButtonsState extends State<RoutineSearchAndButtons> {
child: Center( child: Center(
child: DefaultButton( child: DefaultButton(
onPressed: () async { onPressed: () async {
if (state.routineName == null || if (state.routineName == null || state.routineName!.isEmpty) {
state.routineName!.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: const Text( content: const Text('Please enter the routine name'),
'Please enter the routine name'),
duration: const Duration(seconds: 2), duration: const Duration(seconds: 2),
backgroundColor: ColorsManager.red, backgroundColor: ColorsManager.red,
action: SnackBarAction( action: SnackBarAction(
@ -216,12 +196,10 @@ class _RoutineSearchAndButtonsState extends State<RoutineSearchAndButtons> {
return; return;
} }
if (state.ifItems.isEmpty || if (state.ifItems.isEmpty || state.thenItems.isEmpty) {
state.thenItems.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: const Text( content: const Text('Please add if and then condition'),
'Please add if and then condition'),
duration: const Duration(seconds: 2), duration: const Duration(seconds: 2),
backgroundColor: ColorsManager.red, backgroundColor: ColorsManager.red,
action: SnackBarAction( action: SnackBarAction(
@ -234,18 +212,17 @@ class _RoutineSearchAndButtonsState extends State<RoutineSearchAndButtons> {
); );
return; return;
} }
final result = await SaveRoutineHelper // final result =
.showSaveRoutineDialog(context); // await
if (result != null && result) { SaveRoutineHelper.showSaveRoutineDialog(context);
BlocProvider.of<SwitchTabsBloc>(context) // if (result != null && result) {
.add( // BlocProvider.of<RoutineBloc>(context).add(
const CreateNewRoutineViewEvent(false), // const CreateNewRoutineViewEvent(createRoutineView: false),
); // );
BlocProvider.of<SwitchTabsBloc>(context) // BlocProvider.of<RoutineBloc>(context).add(
.add( // const TriggerSwitchTabsEvent(isRoutineTab: true),
const TriggerSwitchTabsEvent(true), // );
); // }
}
}, },
borderRadius: 15, borderRadius: 15,
elevation: 0, elevation: 0,
@ -276,14 +253,10 @@ class _RoutineSearchAndButtonsState extends State<RoutineSearchAndButtons> {
child: DefaultButton( child: DefaultButton(
onPressed: state.isAutomation || state.isTabToRun onPressed: state.isAutomation || state.isTabToRun
? () async { ? () async {
final result = final result = await SettingHelper.showSettingDialog(
await SettingHelper.showSettingDialog( context: context, iconId: state.selectedIcon ?? '');
context: context,
iconId: state.selectedIcon ?? '');
if (result != null) { if (result != null) {
context context.read<RoutineBloc>().add(AddSelectedIcon(result));
.read<RoutineBloc>()
.add(AddSelectedIcon(result));
} }
} }
: null, : null,
@ -333,12 +306,10 @@ class _RoutineSearchAndButtonsState extends State<RoutineSearchAndButtons> {
child: Center( child: Center(
child: DefaultButton( child: DefaultButton(
onPressed: () async { onPressed: () async {
if (state.routineName == null || if (state.routineName == null || state.routineName!.isEmpty) {
state.routineName!.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: const Text( content: const Text('Please enter the routine name'),
'Please enter the routine name'),
duration: const Duration(seconds: 2), duration: const Duration(seconds: 2),
backgroundColor: ColorsManager.red, backgroundColor: ColorsManager.red,
action: SnackBarAction( action: SnackBarAction(
@ -352,12 +323,10 @@ class _RoutineSearchAndButtonsState extends State<RoutineSearchAndButtons> {
return; return;
} }
if (state.ifItems.isEmpty || if (state.ifItems.isEmpty || state.thenItems.isEmpty) {
state.thenItems.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: const Text( content: const Text('Please add if and then condition'),
'Please add if and then condition'),
duration: const Duration(seconds: 2), duration: const Duration(seconds: 2),
backgroundColor: ColorsManager.red, backgroundColor: ColorsManager.red,
action: SnackBarAction( action: SnackBarAction(
@ -370,17 +339,17 @@ class _RoutineSearchAndButtonsState extends State<RoutineSearchAndButtons> {
); );
return; return;
} }
final result = // final result =
await SaveRoutineHelper.showSaveRoutineDialog( // await
context); SaveRoutineHelper.showSaveRoutineDialog(context);
if (result != null && result) { // if (result != null && result) {
BlocProvider.of<SwitchTabsBloc>(context).add( // BlocProvider.of<RoutineBloc>(context).add(
const CreateNewRoutineViewEvent(false), // const CreateNewRoutineViewEvent(createRoutineView: false),
); // );
BlocProvider.of<SwitchTabsBloc>(context).add( // BlocProvider.of<RoutineBloc>(context).add(
const TriggerSwitchTabsEvent(true), // const TriggerSwitchTabsEvent(isRoutineTab: true),
); // );
} // }
}, },
borderRadius: 15, borderRadius: 15,
elevation: 0, elevation: 0,