mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-16 01:56:24 +00:00
Added routines search field functionlity
This commit is contained in:
@ -32,8 +32,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)..add(event.item);
|
||||||
..add(event.item);
|
|
||||||
if (event.isTabToRun) {
|
if (event.isTabToRun) {
|
||||||
isTabToRun = true;
|
isTabToRun = true;
|
||||||
isAutomation = false;
|
isAutomation = false;
|
||||||
@ -44,15 +43,12 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
emit(state.copyWith(ifItems: updatedIfItems));
|
emit(state.copyWith(ifItems: updatedIfItems));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onAddToThenContainer(
|
void _onAddToThenContainer(AddToThenContainer event, Emitter<RoutineState> emit) {
|
||||||
AddToThenContainer event, Emitter<RoutineState> emit) {
|
final updatedThenItems = List<Map<String, dynamic>>.from(state.thenItems)..add(event.item);
|
||||||
final updatedThenItems = List<Map<String, dynamic>>.from(state.thenItems)
|
|
||||||
..add(event.item);
|
|
||||||
emit(state.copyWith(thenItems: updatedThenItems));
|
emit(state.copyWith(thenItems: updatedThenItems));
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
@ -61,11 +57,9 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
|
|
||||||
if (currentSelectedFunctions.containsKey(event.uniqueCustomId)) {
|
if (currentSelectedFunctions.containsKey(event.uniqueCustomId)) {
|
||||||
currentSelectedFunctions[event.uniqueCustomId] =
|
currentSelectedFunctions[event.uniqueCustomId] =
|
||||||
List.from(currentSelectedFunctions[event.uniqueCustomId]!)
|
List.from(currentSelectedFunctions[event.uniqueCustomId]!)..addAll(event.functions);
|
||||||
..addAll(event.functions);
|
|
||||||
} 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));
|
||||||
@ -74,8 +68,7 @@ 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 {
|
||||||
@ -94,8 +87,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 {
|
||||||
@ -114,13 +106,13 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> _onSearchRoutines(
|
FutureOr<void> _onSearchRoutines(SearchRoutines event, Emitter<RoutineState> emit) async {
|
||||||
SearchRoutines event, Emitter<RoutineState> emit) {
|
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||||
emit(state.copyWith(routineName: event.query));
|
await Future.delayed(const Duration(seconds: 1));
|
||||||
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,8 +121,7 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
return actions.first['deviceId'] == 'delay';
|
return actions.first['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)) {
|
||||||
@ -145,8 +136,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;
|
||||||
@ -201,8 +191,7 @@ 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) {
|
||||||
/// remove element from thenItems at specific index
|
/// remove element from thenItems at specific index
|
||||||
final thenItems = List<Map<String, dynamic>>.from(state.thenItems);
|
final thenItems = List<Map<String, dynamic>>.from(state.thenItems);
|
||||||
|
@ -13,50 +13,49 @@ class RoutineState extends Equatable {
|
|||||||
final String? loadAutomationErrorMessage;
|
final String? loadAutomationErrorMessage;
|
||||||
final String? routineName;
|
final String? routineName;
|
||||||
final String? selectedIcon;
|
final String? selectedIcon;
|
||||||
|
final String? searchText;
|
||||||
|
|
||||||
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});
|
||||||
|
|
||||||
RoutineState copyWith({
|
RoutineState copyWith(
|
||||||
List<Map<String, dynamic>>? ifItems,
|
{List<Map<String, dynamic>>? ifItems,
|
||||||
List<Map<String, dynamic>>? thenItems,
|
List<Map<String, dynamic>>? thenItems,
|
||||||
List<ScenesModel>? scenes,
|
List<ScenesModel>? scenes,
|
||||||
List<ScenesModel>? automations,
|
List<ScenesModel>? automations,
|
||||||
Map<String, List<DeviceFunctionData>>? selectedFunctions,
|
Map<String, List<DeviceFunctionData>>? selectedFunctions,
|
||||||
bool? isLoading,
|
bool? isLoading,
|
||||||
String? errorMessage,
|
String? errorMessage,
|
||||||
String? routineName,
|
String? routineName,
|
||||||
String? selectedIcon,
|
String? selectedIcon,
|
||||||
String? loadAutomationErrorMessage,
|
String? loadAutomationErrorMessage,
|
||||||
String? loadScenesErrorMessage,
|
String? loadScenesErrorMessage,
|
||||||
}) {
|
String? searchText}) {
|
||||||
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,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -72,5 +71,6 @@ class RoutineState extends Equatable {
|
|||||||
selectedIcon,
|
selectedIcon,
|
||||||
loadScenesErrorMessage,
|
loadScenesErrorMessage,
|
||||||
loadAutomationErrorMessage,
|
loadAutomationErrorMessage,
|
||||||
|
searchText
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
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/models/devices_model.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/dragable_card.dart';
|
import 'package:syncrow_web/pages/routiens/widgets/dragable_card.dart';
|
||||||
|
|
||||||
@ -14,7 +15,7 @@ class RoutineDevices extends StatelessWidget {
|
|||||||
child: BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
|
child: BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state is DeviceManagementLoaded) {
|
if (state is DeviceManagementLoaded) {
|
||||||
final deviceList = state.devices
|
List<AllDevicesModel> deviceList = state.devices
|
||||||
.where((device) =>
|
.where((device) =>
|
||||||
device.productType == 'AC' ||
|
device.productType == 'AC' ||
|
||||||
device.productType == '1G' ||
|
device.productType == '1G' ||
|
||||||
@ -30,19 +31,39 @@ class RoutineDevices extends StatelessWidget {
|
|||||||
runSpacing: 10,
|
runSpacing: 10,
|
||||||
children: deviceList.asMap().entries.map((entry) {
|
children: deviceList.asMap().entries.map((entry) {
|
||||||
final device = entry.value;
|
final device = entry.value;
|
||||||
return DraggableCard(
|
if (routineState.searchText != null && routineState.searchText!.isNotEmpty) {
|
||||||
imagePath: device.getDefaultIcon(device.productType),
|
return device.name!
|
||||||
title: device.name ?? '',
|
.toLowerCase()
|
||||||
deviceData: {
|
.contains(routineState.searchText!.toLowerCase())
|
||||||
'device': device,
|
? DraggableCard(
|
||||||
'imagePath': device.getDefaultIcon(device.productType),
|
imagePath: device.getDefaultIcon(device.productType),
|
||||||
'title': device.name ?? '',
|
title: device.name ?? '',
|
||||||
'deviceId': device.uuid,
|
deviceData: {
|
||||||
'productType': device.productType,
|
'device': device,
|
||||||
'functions': device.functions,
|
'imagePath': device.getDefaultIcon(device.productType),
|
||||||
'uniqueCustomId': '',
|
'title': device.name ?? '',
|
||||||
},
|
'deviceId': device.uuid,
|
||||||
);
|
'productType': device.productType,
|
||||||
|
'functions': device.functions,
|
||||||
|
'uniqueCustomId': '',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: Container();
|
||||||
|
} else {
|
||||||
|
return DraggableCard(
|
||||||
|
imagePath: device.getDefaultIcon(device.productType),
|
||||||
|
title: device.name ?? '',
|
||||||
|
deviceData: {
|
||||||
|
'device': device,
|
||||||
|
'imagePath': device.getDefaultIcon(device.productType),
|
||||||
|
'title': device.name ?? '',
|
||||||
|
'deviceId': device.uuid,
|
||||||
|
'productType': device.productType,
|
||||||
|
'functions': device.functions,
|
||||||
|
'uniqueCustomId': '',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}).toList(),
|
}).toList(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -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/main.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/common/text_field/custom_text_field.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/bloc/routine_bloc/routine_bloc.dart';
|
||||||
@ -32,9 +31,7 @@ class RoutineSearchAndButtons extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
ConstrainedBox(
|
ConstrainedBox(
|
||||||
constraints: BoxConstraints(
|
constraints: BoxConstraints(
|
||||||
maxWidth: constraints.maxWidth > 700
|
maxWidth: constraints.maxWidth > 700 ? 450 : constraints.maxWidth - 32),
|
||||||
? 450
|
|
||||||
: constraints.maxWidth - 32),
|
|
||||||
child: StatefulTextField(
|
child: StatefulTextField(
|
||||||
title: 'Routine Name',
|
title: 'Routine Name',
|
||||||
height: 40,
|
height: 40,
|
||||||
@ -46,9 +43,7 @@ class RoutineSearchAndButtons extends StatelessWidget {
|
|||||||
isRequired: true,
|
isRequired: true,
|
||||||
width: 450,
|
width: 450,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
context
|
// context.read<RoutineBloc>().add(SearchRoutines(value));
|
||||||
.read<RoutineBloc>()
|
|
||||||
.add(SearchRoutines(value));
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -60,14 +55,11 @@ class RoutineSearchAndButtons extends StatelessWidget {
|
|||||||
child: Center(
|
child: Center(
|
||||||
child: DefaultButton(
|
child: DefaultButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final result =
|
final result = await SettingHelper.showSettingDialog(
|
||||||
await SettingHelper.showSettingDialog(
|
|
||||||
context: context,
|
context: context,
|
||||||
);
|
);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
context
|
context.read<RoutineBloc>().add(AddSelectedIcon(result));
|
||||||
.read<RoutineBloc>()
|
|
||||||
.add(AddSelectedIcon(result));
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
borderRadius: 15,
|
borderRadius: 15,
|
||||||
|
@ -33,17 +33,33 @@ class _ScenesAndAutomationsState extends State<ScenesAndAutomations> {
|
|||||||
runSpacing: 10,
|
runSpacing: 10,
|
||||||
children: scenes.asMap().entries.map((entry) {
|
children: scenes.asMap().entries.map((entry) {
|
||||||
final scene = entry.value;
|
final scene = entry.value;
|
||||||
return DraggableCard(
|
if (state.searchText != null && state.searchText!.isNotEmpty) {
|
||||||
imagePath: Assets.logo,
|
return scene.name.toLowerCase().contains(state.searchText!.toLowerCase())
|
||||||
title: scene.name,
|
? DraggableCard(
|
||||||
deviceData: {
|
imagePath: Assets.logo,
|
||||||
'deviceId': scene.id,
|
title: scene.name,
|
||||||
'name': scene.name,
|
deviceData: {
|
||||||
'status': scene.status,
|
'deviceId': scene.id,
|
||||||
'type': scene.type,
|
'name': scene.name,
|
||||||
'icon': scene.icon,
|
'status': scene.status,
|
||||||
},
|
'type': scene.type,
|
||||||
);
|
'icon': scene.icon,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: Container();
|
||||||
|
} else {
|
||||||
|
return DraggableCard(
|
||||||
|
imagePath: Assets.logo,
|
||||||
|
title: scene.name,
|
||||||
|
deviceData: {
|
||||||
|
'deviceId': scene.id,
|
||||||
|
'name': scene.name,
|
||||||
|
'status': scene.status,
|
||||||
|
'type': scene.type,
|
||||||
|
'icon': scene.icon,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}).toList(),
|
}).toList(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/common/text_field/custom_text_field.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/widgets/routines_title_widget.dart';
|
import 'package:syncrow_web/pages/routiens/widgets/routines_title_widget.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
|
|
||||||
class ConditionTitleAndSearchBar extends StatelessWidget
|
class ConditionTitleAndSearchBar extends StatelessWidget with HelperResponsiveLayout {
|
||||||
with HelperResponsiveLayout {
|
|
||||||
const ConditionTitleAndSearchBar({
|
const ConditionTitleAndSearchBar({
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
@ -34,7 +35,12 @@ class ConditionTitleAndSearchBar extends StatelessWidget
|
|||||||
borderRadius: BorderRadius.circular(15),
|
borderRadius: BorderRadius.circular(15),
|
||||||
),
|
),
|
||||||
controller: TextEditingController(),
|
controller: TextEditingController(),
|
||||||
onChanged: (value) {},
|
// onSubmitted: (value) {
|
||||||
|
// context.read<RoutineBloc>().add(SearchRoutines(value));
|
||||||
|
// },
|
||||||
|
onChanged: (value) {
|
||||||
|
context.read<RoutineBloc>().add(SearchRoutines(value));
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@ -57,7 +63,12 @@ class ConditionTitleAndSearchBar extends StatelessWidget
|
|||||||
borderRadius: BorderRadius.circular(15),
|
borderRadius: BorderRadius.circular(15),
|
||||||
),
|
),
|
||||||
controller: TextEditingController(),
|
controller: TextEditingController(),
|
||||||
onChanged: (value) {},
|
// onSubmitted: (value) {
|
||||||
|
// context.read<RoutineBloc>().add(SearchRoutines(value));
|
||||||
|
// },
|
||||||
|
onChanged: (value) {
|
||||||
|
context.read<RoutineBloc>().add(SearchRoutines(value));
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user