mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 15:17:31 +00:00
fixes unique id for card drag
This commit is contained in:
@ -105,6 +105,7 @@ class AllDevicesModel {
|
|||||||
this.productName,
|
this.productName,
|
||||||
this.spaces,
|
this.spaces,
|
||||||
});
|
});
|
||||||
|
|
||||||
AllDevicesModel.fromJson(Map<String, dynamic> json) {
|
AllDevicesModel.fromJson(Map<String, dynamic> json) {
|
||||||
room = (json['room'] != null && (json['room'] is Map))
|
room = (json['room'] != null && (json['room'] is Map))
|
||||||
? DevicesModelRoom.fromJson(json['room'])
|
? DevicesModelRoom.fromJson(json['room'])
|
||||||
@ -138,6 +139,7 @@ class AllDevicesModel {
|
|||||||
updateTime = int.tryParse(json['updateTime']?.toString() ?? '');
|
updateTime = int.tryParse(json['updateTime']?.toString() ?? '');
|
||||||
uuid = json['uuid']?.toString();
|
uuid = json['uuid']?.toString();
|
||||||
batteryLevel = int.tryParse(json['battery']?.toString() ?? '');
|
batteryLevel = int.tryParse(json['battery']?.toString() ?? '');
|
||||||
|
|
||||||
productName = json['productName']?.toString();
|
productName = json['productName']?.toString();
|
||||||
if (json['spaces'] != null && json['spaces'] is List) {
|
if (json['spaces'] != null && json['spaces'] is List) {
|
||||||
spaces = (json['spaces'] as List)
|
spaces = (json['spaces'] as List)
|
||||||
|
@ -16,9 +16,9 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
on<AddToThenContainer>(_onAddToThenContainer);
|
on<AddToThenContainer>(_onAddToThenContainer);
|
||||||
on<LoadScenes>(_onLoadScenes);
|
on<LoadScenes>(_onLoadScenes);
|
||||||
on<LoadAutomation>(_onLoadAutomation);
|
on<LoadAutomation>(_onLoadAutomation);
|
||||||
on<AddFunctionToRoutine>(_onAddFunction);
|
on<AddFunctionToRoutine>(_onAddFunctionsToRoutine);
|
||||||
on<RemoveFunction>(_onRemoveFunction);
|
// on<RemoveFunction>(_onRemoveFunction);
|
||||||
on<ClearFunctions>(_onClearFunctions);
|
// on<ClearFunctions>(_onClearFunctions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onAddToIfContainer(AddToIfContainer event, Emitter<RoutineState> emit) {
|
void _onAddToIfContainer(AddToIfContainer event, Emitter<RoutineState> emit) {
|
||||||
@ -38,24 +38,33 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onAddFunction(AddFunctionToRoutine event, Emitter<RoutineState> emit) {
|
void _onAddFunctionsToRoutine(
|
||||||
final functions = List<DeviceFunctionData>.from(state.selectedFunctions);
|
AddFunctionToRoutine event, Emitter<RoutineState> emit) {
|
||||||
functions.add(event.function);
|
debugPrint(event.uniqueCustomId.toString());
|
||||||
debugPrint("******" + functions.toString());
|
debugPrint(event.functions.toString());
|
||||||
emit(state.copyWith(selectedFunctions: functions));
|
final currentSelectedFunctions =
|
||||||
|
Map<String, List<DeviceFunctionData>>.from(state.selectedFunctions);
|
||||||
|
|
||||||
|
if (currentSelectedFunctions.containsKey(event.uniqueCustomId)) {
|
||||||
|
currentSelectedFunctions[event.uniqueCustomId]!.addAll(event.functions);
|
||||||
|
} else {
|
||||||
|
currentSelectedFunctions[event.uniqueCustomId] = event.functions;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit(state.copyWith(selectedFunctions: currentSelectedFunctions));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onRemoveFunction(RemoveFunction event, Emitter<RoutineState> emit) {
|
// void _onRemoveFunction(RemoveFunction event, Emitter<RoutineState> emit) {
|
||||||
final functions = List<DeviceFunctionData>.from(state.selectedFunctions)
|
// final functions = List<DeviceFunctionData>.from(state.selectedFunctions)
|
||||||
..removeWhere((f) =>
|
// ..removeWhere((f) =>
|
||||||
f.functionCode == event.function.functionCode &&
|
// f.functionCode == event.function.functionCode &&
|
||||||
f.value == event.function.value);
|
// f.value == event.function.value);
|
||||||
emit(state.copyWith(selectedFunctions: functions));
|
// emit(state.copyWith(selectedFunctions: functions));
|
||||||
}
|
// }
|
||||||
|
|
||||||
void _onClearFunctions(ClearFunctions event, Emitter<RoutineState> emit) {
|
// void _onClearFunctions(ClearFunctions event, Emitter<RoutineState> emit) {
|
||||||
emit(state.copyWith(selectedFunctions: []));
|
// emit(state.copyWith(selectedFunctions: []));
|
||||||
}
|
// }
|
||||||
|
|
||||||
// bool _isDuplicate(
|
// bool _isDuplicate(
|
||||||
// List<Map<String, dynamic>> items, Map<String, dynamic> newItem) {
|
// List<Map<String, dynamic>> items, Map<String, dynamic> newItem) {
|
||||||
|
@ -44,10 +44,11 @@ class LoadAutomation extends RoutineEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class AddFunctionToRoutine extends RoutineEvent {
|
class AddFunctionToRoutine extends RoutineEvent {
|
||||||
final DeviceFunctionData function;
|
final List<DeviceFunctionData> functions;
|
||||||
const AddFunctionToRoutine(this.function);
|
final String uniqueCustomId;
|
||||||
|
const AddFunctionToRoutine(this.functions, this.uniqueCustomId);
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [function];
|
List<Object> get props => [functions];
|
||||||
}
|
}
|
||||||
|
|
||||||
class RemoveFunction extends RoutineEvent {
|
class RemoveFunction extends RoutineEvent {
|
||||||
|
@ -6,7 +6,7 @@ class RoutineState extends Equatable {
|
|||||||
final List<Map<String, String>> availableCards;
|
final List<Map<String, String>> availableCards;
|
||||||
final List<ScenesModel> scenes;
|
final List<ScenesModel> scenes;
|
||||||
final List<ScenesModel> automations;
|
final List<ScenesModel> automations;
|
||||||
final List<DeviceFunctionData> selectedFunctions;
|
final Map<String, List<DeviceFunctionData>> selectedFunctions;
|
||||||
final bool isLoading;
|
final bool isLoading;
|
||||||
final String? errorMessage;
|
final String? errorMessage;
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ class RoutineState extends Equatable {
|
|||||||
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,
|
||||||
});
|
});
|
||||||
@ -26,7 +26,7 @@ class RoutineState extends Equatable {
|
|||||||
List<Map<String, dynamic>>? thenItems,
|
List<Map<String, dynamic>>? thenItems,
|
||||||
List<ScenesModel>? scenes,
|
List<ScenesModel>? scenes,
|
||||||
List<ScenesModel>? automations,
|
List<ScenesModel>? automations,
|
||||||
List<DeviceFunctionData>? selectedFunctions,
|
Map<String, List<DeviceFunctionData>>? selectedFunctions,
|
||||||
bool? isLoading,
|
bool? isLoading,
|
||||||
String? errorMessage,
|
String? errorMessage,
|
||||||
}) {
|
}) {
|
||||||
|
@ -18,6 +18,7 @@ class ACHelper {
|
|||||||
List<DeviceFunction> functions,
|
List<DeviceFunction> functions,
|
||||||
AllDevicesModel? device,
|
AllDevicesModel? device,
|
||||||
List<DeviceFunctionData>? deviceSelectedFunctions,
|
List<DeviceFunctionData>? deviceSelectedFunctions,
|
||||||
|
String uniqueCustomId,
|
||||||
) async {
|
) async {
|
||||||
List<ACFunction> acFunctions = functions.whereType<ACFunction>().toList();
|
List<ACFunction> acFunctions = functions.whereType<ACFunction>().toList();
|
||||||
|
|
||||||
@ -95,13 +96,14 @@ class ACHelper {
|
|||||||
onConfirm: state.addedFunctions.isNotEmpty
|
onConfirm: state.addedFunctions.isNotEmpty
|
||||||
? () {
|
? () {
|
||||||
/// add the functions to the routine bloc
|
/// add the functions to the routine bloc
|
||||||
for (var function in state.addedFunctions) {
|
// for (var function in state.addedFunctions) {
|
||||||
context.read<RoutineBloc>().add(
|
context.read<RoutineBloc>().add(
|
||||||
AddFunctionToRoutine(
|
AddFunctionToRoutine(
|
||||||
function,
|
state.addedFunctions,
|
||||||
),
|
uniqueCustomId,
|
||||||
);
|
),
|
||||||
}
|
);
|
||||||
|
//}
|
||||||
// Return the device data to be added to the container
|
// Return the device data to be added to the container
|
||||||
Navigator.pop(context, {
|
Navigator.pop(context, {
|
||||||
'deviceId': functions.first.deviceId,
|
'deviceId': functions.first.deviceId,
|
||||||
@ -229,11 +231,23 @@ class ACHelper {
|
|||||||
selectedFunctionData,
|
selectedFunctionData,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildTemperatureDisplay(context, initialValue, device, operationName,
|
_buildTemperatureDisplay(
|
||||||
selectedFunctionData, selectCode),
|
context,
|
||||||
|
initialValue,
|
||||||
|
device,
|
||||||
|
operationName,
|
||||||
|
selectedFunctionData,
|
||||||
|
selectCode,
|
||||||
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildTemperatureSlider(context, initialValue, device, operationName,
|
_buildTemperatureSlider(
|
||||||
selectedFunctionData, selectCode),
|
context,
|
||||||
|
initialValue,
|
||||||
|
device,
|
||||||
|
operationName,
|
||||||
|
selectedFunctionData,
|
||||||
|
selectCode,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -246,6 +260,7 @@ class ACHelper {
|
|||||||
AllDevicesModel? device,
|
AllDevicesModel? device,
|
||||||
String operationName,
|
String operationName,
|
||||||
DeviceFunctionData? selectedFunctionData,
|
DeviceFunctionData? selectedFunctionData,
|
||||||
|
|
||||||
// Function(String) onConditionChanged,
|
// Function(String) onConditionChanged,
|
||||||
) {
|
) {
|
||||||
final conditions = ["<", "==", ">"];
|
final conditions = ["<", "==", ">"];
|
||||||
@ -282,12 +297,13 @@ class ACHelper {
|
|||||||
|
|
||||||
/// Build temperature display for AC functions dialog
|
/// Build temperature display for AC functions dialog
|
||||||
static Widget _buildTemperatureDisplay(
|
static Widget _buildTemperatureDisplay(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
dynamic initialValue,
|
dynamic initialValue,
|
||||||
AllDevicesModel? device,
|
AllDevicesModel? device,
|
||||||
String operationName,
|
String operationName,
|
||||||
DeviceFunctionData? selectedFunctionData,
|
DeviceFunctionData? selectedFunctionData,
|
||||||
String selectCode) {
|
String selectCode,
|
||||||
|
) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@ -342,6 +358,7 @@ class ACHelper {
|
|||||||
required String operationName,
|
required String operationName,
|
||||||
required String selectCode,
|
required String selectCode,
|
||||||
DeviceFunctionData? selectedFunctionData,
|
DeviceFunctionData? selectedFunctionData,
|
||||||
|
|
||||||
// required Function(dynamic) onValueChanged,
|
// required Function(dynamic) onValueChanged,
|
||||||
}) {
|
}) {
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
|
@ -39,24 +39,28 @@ class DeviceDialogHelper {
|
|||||||
List<DeviceFunction> functions,
|
List<DeviceFunction> functions,
|
||||||
) async {
|
) async {
|
||||||
final routineBloc = context.read<RoutineBloc>();
|
final routineBloc = context.read<RoutineBloc>();
|
||||||
final deviceSelectedFunctions = routineBloc.state.selectedFunctions
|
final deviceSelectedFunctions =
|
||||||
.where((f) => f.entityId == data['deviceId'])
|
routineBloc.state.selectedFunctions[data['uniqueCustomId']] ?? [];
|
||||||
.toList();
|
|
||||||
|
|
||||||
switch (productType) {
|
switch (productType) {
|
||||||
case 'AC':
|
case 'AC':
|
||||||
return ACHelper.showACFunctionsDialog(
|
return ACHelper.showACFunctionsDialog(context, functions,
|
||||||
context, functions, data['device'], deviceSelectedFunctions);
|
data['device'], deviceSelectedFunctions, data['uniqueCustomId']);
|
||||||
|
|
||||||
case '1G':
|
case '1G':
|
||||||
return OneGangSwitchHelper.showSwitchFunctionsDialog(
|
return OneGangSwitchHelper.showSwitchFunctionsDialog(context, functions,
|
||||||
context, functions, data['device'], deviceSelectedFunctions);
|
data['device'], deviceSelectedFunctions, data['uniqueCustomId']);
|
||||||
case '2G':
|
case '2G':
|
||||||
return TwoGangSwitchHelper.showSwitchFunctionsDialog(
|
return TwoGangSwitchHelper.showSwitchFunctionsDialog(context, functions,
|
||||||
context, functions);
|
data['device'], deviceSelectedFunctions, data['uniqueCustomId']);
|
||||||
case '3G':
|
case '3G':
|
||||||
return ThreeGangSwitchHelper.showSwitchFunctionsDialog(
|
return ThreeGangSwitchHelper.showSwitchFunctionsDialog(
|
||||||
context, functions);
|
context,
|
||||||
|
functions,
|
||||||
|
data['device'],
|
||||||
|
deviceSelectedFunctions,
|
||||||
|
data['uniqueCustomId'],
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,9 @@ import 'package:flutter_svg/flutter_svg.dart';
|
|||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/bloc/functions_bloc/functions_bloc_bloc.dart';
|
import 'package:syncrow_web/pages/routiens/bloc/functions_bloc/functions_bloc_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/models/ac/ac_function.dart';
|
|
||||||
import 'package:syncrow_web/pages/routiens/models/ac/ac_operational_value.dart';
|
|
||||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/base_switch_function.dart';
|
import 'package:syncrow_web/pages/routiens/models/gang_switches/base_switch_function.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/one_gang_switch/one_gang_switch.dart';
|
import 'package:syncrow_web/pages/routiens/models/gang_switches/switch_operational_value.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
@ -20,8 +18,10 @@ class OneGangSwitchHelper {
|
|||||||
List<DeviceFunction> functions,
|
List<DeviceFunction> functions,
|
||||||
AllDevicesModel? device,
|
AllDevicesModel? device,
|
||||||
List<DeviceFunctionData>? deviceSelectedFunctions,
|
List<DeviceFunctionData>? deviceSelectedFunctions,
|
||||||
|
String uniqueCustomId,
|
||||||
) async {
|
) async {
|
||||||
List<ACFunction> acFunctions = functions.whereType<ACFunction>().toList();
|
List<BaseSwitchFunction> acFunctions =
|
||||||
|
functions.whereType<BaseSwitchFunction>().toList();
|
||||||
|
|
||||||
return showDialog<Map<String, dynamic>?>(
|
return showDialog<Map<String, dynamic>?>(
|
||||||
context: context,
|
context: context,
|
||||||
@ -107,30 +107,6 @@ class OneGangSwitchHelper {
|
|||||||
operationName: selectedOperationName ?? '',
|
operationName: selectedOperationName ?? '',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// ValueListenableBuilder<String?>(
|
|
||||||
// valueListenable: selectedFunctionNotifier,
|
|
||||||
// builder: (context, selectedFunction, _) {
|
|
||||||
// final selectedFn =
|
|
||||||
// switchFunctions.firstWhere(
|
|
||||||
// (f) => f.code == selectedFunction,
|
|
||||||
// );
|
|
||||||
// return Expanded(
|
|
||||||
// child: selectedFn
|
|
||||||
// is OneGangCountdownFunction
|
|
||||||
// ? _buildCountDownSelector(
|
|
||||||
// context,
|
|
||||||
// selectedValueNotifier,
|
|
||||||
// selectedConditionNotifier,
|
|
||||||
// selectedConditionsNotifier,
|
|
||||||
// )
|
|
||||||
// : _buildOperationalValuesList(
|
|
||||||
// context,
|
|
||||||
// selectedFn as BaseSwitchFunction,
|
|
||||||
// selectedValueNotifier,
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -146,13 +122,20 @@ class OneGangSwitchHelper {
|
|||||||
onConfirm: state.addedFunctions.isNotEmpty
|
onConfirm: state.addedFunctions.isNotEmpty
|
||||||
? () {
|
? () {
|
||||||
/// add the functions to the routine bloc
|
/// add the functions to the routine bloc
|
||||||
for (var function in state.addedFunctions) {
|
// for (var function in state.addedFunctions) {
|
||||||
context.read<RoutineBloc>().add(
|
// context.read<RoutineBloc>().add(
|
||||||
AddFunctionToRoutine(
|
// AddFunctionToRoutine(
|
||||||
function,
|
// function,
|
||||||
),
|
// uniqueCustomId,
|
||||||
);
|
// ),
|
||||||
}
|
// );
|
||||||
|
// }
|
||||||
|
context.read<RoutineBloc>().add(
|
||||||
|
AddFunctionToRoutine(
|
||||||
|
state.addedFunctions,
|
||||||
|
uniqueCustomId,
|
||||||
|
),
|
||||||
|
);
|
||||||
// Return the device data to be added to the container
|
// Return the device data to be added to the container
|
||||||
Navigator.pop(context, {
|
Navigator.pop(context, {
|
||||||
'deviceId': functions.first.deviceId,
|
'deviceId': functions.first.deviceId,
|
||||||
@ -175,13 +158,13 @@ class OneGangSwitchHelper {
|
|||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
required String selectedFunction,
|
required String selectedFunction,
|
||||||
required DeviceFunctionData? selectedFunctionData,
|
required DeviceFunctionData? selectedFunctionData,
|
||||||
required List<ACFunction> acFunctions,
|
required List<BaseSwitchFunction> acFunctions,
|
||||||
AllDevicesModel? device,
|
AllDevicesModel? device,
|
||||||
required String operationName,
|
required String operationName,
|
||||||
}) {
|
}) {
|
||||||
if (selectedFunction == 'countdown_1') {
|
if (selectedFunction == 'countdown_1') {
|
||||||
final initialValue = selectedFunctionData?.value ?? 200;
|
final initialValue = selectedFunctionData?.value ?? 200;
|
||||||
return _buildTemperatureSelector(
|
return _buildCountDownSelector(
|
||||||
context: context,
|
context: context,
|
||||||
initialValue: initialValue,
|
initialValue: initialValue,
|
||||||
selectCode: selectedFunction,
|
selectCode: selectedFunction,
|
||||||
@ -207,7 +190,7 @@ class OneGangSwitchHelper {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Widget _buildTemperatureSelector({
|
static Widget _buildCountDownSelector({
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
required dynamic initialValue,
|
required dynamic initialValue,
|
||||||
required String? currentCondition,
|
required String? currentCondition,
|
||||||
@ -228,10 +211,10 @@ class OneGangSwitchHelper {
|
|||||||
selectedFunctionData,
|
selectedFunctionData,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildTemperatureDisplay(context, initialValue, device, operationName,
|
_buildCountDownDisplay(context, initialValue, device, operationName,
|
||||||
selectedFunctionData, selectCode),
|
selectedFunctionData, selectCode),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildTemperatureSlider(context, initialValue, device, operationName,
|
_buildCountDownSlider(context, initialValue, device, operationName,
|
||||||
selectedFunctionData, selectCode),
|
selectedFunctionData, selectCode),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -280,7 +263,7 @@ class OneGangSwitchHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Build temperature display for AC functions dialog
|
/// Build temperature display for AC functions dialog
|
||||||
static Widget _buildTemperatureDisplay(
|
static Widget _buildCountDownDisplay(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
dynamic initialValue,
|
dynamic initialValue,
|
||||||
AllDevicesModel? device,
|
AllDevicesModel? device,
|
||||||
@ -302,7 +285,7 @@ class OneGangSwitchHelper {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Widget _buildTemperatureSlider(
|
static Widget _buildCountDownSlider(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
dynamic initialValue,
|
dynamic initialValue,
|
||||||
AllDevicesModel? device,
|
AllDevicesModel? device,
|
||||||
@ -310,11 +293,22 @@ class OneGangSwitchHelper {
|
|||||||
DeviceFunctionData? selectedFunctionData,
|
DeviceFunctionData? selectedFunctionData,
|
||||||
String selectCode,
|
String selectCode,
|
||||||
) {
|
) {
|
||||||
|
final operationalValues = SwitchOperationalValue(
|
||||||
|
icon: '',
|
||||||
|
description: "sec",
|
||||||
|
value: 0.0,
|
||||||
|
minValue: 0,
|
||||||
|
maxValue: 43200,
|
||||||
|
stepValue: 1,
|
||||||
|
);
|
||||||
return Slider(
|
return Slider(
|
||||||
value: (initialValue ?? 0).toDouble(),
|
value: (initialValue ?? 0).toDouble(),
|
||||||
min: 0,
|
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
||||||
max: 300,
|
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
||||||
divisions: 300,
|
divisions: (((operationalValues.maxValue ?? 0) -
|
||||||
|
(operationalValues.minValue ?? 0)) /
|
||||||
|
(operationalValues.stepValue ?? 1))
|
||||||
|
.round(),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
context.read<FunctionBloc>().add(
|
context.read<FunctionBloc>().add(
|
||||||
AddFunction(
|
AddFunction(
|
||||||
@ -334,13 +328,12 @@ class OneGangSwitchHelper {
|
|||||||
|
|
||||||
static Widget _buildOperationalValuesList({
|
static Widget _buildOperationalValuesList({
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
required List<ACOperationalValue> values,
|
required List<SwitchOperationalValue> values,
|
||||||
required dynamic selectedValue,
|
required dynamic selectedValue,
|
||||||
AllDevicesModel? device,
|
AllDevicesModel? device,
|
||||||
required String operationName,
|
required String operationName,
|
||||||
required String selectCode,
|
required String selectCode,
|
||||||
DeviceFunctionData? selectedFunctionData,
|
DeviceFunctionData? selectedFunctionData,
|
||||||
// required Function(dynamic) onValueChanged,
|
|
||||||
}) {
|
}) {
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
shrinkWrap: false,
|
shrinkWrap: false,
|
||||||
@ -394,102 +387,4 @@ class OneGangSwitchHelper {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// static Widget _buildCountDownSelector(
|
|
||||||
// BuildContext context,
|
|
||||||
// ValueNotifier<dynamic> valueNotifier,
|
|
||||||
// ValueNotifier<String?> conditionNotifier,
|
|
||||||
// ValueNotifier<List<bool>> conditionsNotifier,
|
|
||||||
// ) {
|
|
||||||
// return ValueListenableBuilder<dynamic>(
|
|
||||||
// valueListenable: valueNotifier,
|
|
||||||
// builder: (context, value, _) {
|
|
||||||
// return Column(
|
|
||||||
// mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
// children: [
|
|
||||||
// ValueListenableBuilder<List<bool>>(
|
|
||||||
// valueListenable: conditionsNotifier,
|
|
||||||
// builder: (context, selectedConditions, _) {
|
|
||||||
// return ToggleButtons(
|
|
||||||
// onPressed: (int index) {
|
|
||||||
// final newConditions = List<bool>.filled(3, false);
|
|
||||||
// newConditions[index] = true;
|
|
||||||
// conditionsNotifier.value = newConditions;
|
|
||||||
// conditionNotifier.value = index == 0
|
|
||||||
// ? "<"
|
|
||||||
// : index == 1
|
|
||||||
// ? "=="
|
|
||||||
// : ">";
|
|
||||||
// },
|
|
||||||
// borderRadius: const BorderRadius.all(Radius.circular(8)),
|
|
||||||
// selectedBorderColor: ColorsManager.primaryColorWithOpacity,
|
|
||||||
// selectedColor: Colors.white,
|
|
||||||
// fillColor: ColorsManager.primaryColorWithOpacity,
|
|
||||||
// color: ColorsManager.primaryColorWithOpacity,
|
|
||||||
// constraints: const BoxConstraints(
|
|
||||||
// minHeight: 40.0,
|
|
||||||
// minWidth: 40.0,
|
|
||||||
// ),
|
|
||||||
// isSelected: selectedConditions,
|
|
||||||
// children: const [Text("<"), Text("="), Text(">")],
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
// const SizedBox(height: 20),
|
|
||||||
// Text(
|
|
||||||
// '${value ?? 0} sec',
|
|
||||||
// style: Theme.of(context).textTheme.headlineMedium,
|
|
||||||
// ),
|
|
||||||
// const SizedBox(height: 20),
|
|
||||||
// Slider(
|
|
||||||
// value: (value ?? 0).toDouble(),
|
|
||||||
// min: 0,
|
|
||||||
// max: 300,
|
|
||||||
// divisions: 300,
|
|
||||||
// onChanged: (newValue) {
|
|
||||||
// valueNotifier.value = newValue.toInt();
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// static Widget _buildOperationalValuesList(
|
|
||||||
// BuildContext context,
|
|
||||||
// BaseSwitchFunction function,
|
|
||||||
// ValueNotifier<dynamic> valueNotifier,
|
|
||||||
// ) {
|
|
||||||
// final values = function.getOperationalValues();
|
|
||||||
// return ValueListenableBuilder<dynamic>(
|
|
||||||
// valueListenable: valueNotifier,
|
|
||||||
// builder: (context, selectedValue, _) {
|
|
||||||
// return ListView.builder(
|
|
||||||
// itemCount: values.length,
|
|
||||||
// itemBuilder: (context, index) {
|
|
||||||
// final value = values[index];
|
|
||||||
// return ListTile(
|
|
||||||
// leading: SvgPicture.asset(
|
|
||||||
// value.icon,
|
|
||||||
// width: 24,
|
|
||||||
// height: 24,
|
|
||||||
// ),
|
|
||||||
// title: Text(
|
|
||||||
// value.description,
|
|
||||||
// style: context.textTheme.bodyMedium,
|
|
||||||
// ),
|
|
||||||
// trailing: Radio<dynamic>(
|
|
||||||
// value: value.value,
|
|
||||||
// groupValue: selectedValue,
|
|
||||||
// onChanged: (newValue) {
|
|
||||||
// valueNotifier.value = newValue;
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/routiens/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/base_switch_function.dart';
|
import 'package:syncrow_web/pages/routiens/models/gang_switches/base_switch_function.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/three_gang_switch/three_gang_switch.dart';
|
import 'package:syncrow_web/pages/routiens/models/gang_switches/switch_operational_value.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
@ -10,64 +14,60 @@ import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|||||||
|
|
||||||
class ThreeGangSwitchHelper {
|
class ThreeGangSwitchHelper {
|
||||||
static Future<Map<String, dynamic>?> showSwitchFunctionsDialog(
|
static Future<Map<String, dynamic>?> showSwitchFunctionsDialog(
|
||||||
BuildContext context, List<DeviceFunction<dynamic>> functions) async {
|
BuildContext context,
|
||||||
List<DeviceFunction<dynamic>> switchFunctions = functions
|
List<DeviceFunction> functions,
|
||||||
.where((f) =>
|
AllDevicesModel? device,
|
||||||
f is ThreeGangSwitch1Function ||
|
List<DeviceFunctionData>? deviceSelectedFunctions,
|
||||||
f is ThreeGangSwitch2Function ||
|
String uniqueCustomId,
|
||||||
f is ThreeGangSwitch3Function ||
|
) async {
|
||||||
f is ThreeGangCountdown1Function ||
|
List<BaseSwitchFunction> switchFunctions =
|
||||||
f is ThreeGangCountdown2Function ||
|
functions.whereType<BaseSwitchFunction>().toList();
|
||||||
f is ThreeGangCountdown3Function)
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
final selectedFunctionNotifier = ValueNotifier<String?>(null);
|
return showDialog<Map<String, dynamic>?>(
|
||||||
final selectedValueNotifier = ValueNotifier<dynamic>(null);
|
|
||||||
final selectedConditionNotifier = ValueNotifier<String?>('<');
|
|
||||||
final selectedConditionsNotifier =
|
|
||||||
ValueNotifier<List<bool>>([true, false, false]);
|
|
||||||
|
|
||||||
await showDialog(
|
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return ValueListenableBuilder<String?>(
|
return BlocProvider(
|
||||||
valueListenable: selectedFunctionNotifier,
|
create: (_) => FunctionBloc()
|
||||||
builder: (context, selectedFunction, _) {
|
..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
||||||
return AlertDialog(
|
child: AlertDialog(
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
content: Container(
|
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
||||||
width: selectedFunction != null ? 600 : 300,
|
builder: (context, state) {
|
||||||
height: 450,
|
final selectedFunction = state.selectedFunction;
|
||||||
decoration: BoxDecoration(
|
final selectedOperationName = state.selectedOperationName;
|
||||||
color: Colors.white,
|
final selectedFunctionData = state.addedFunctions
|
||||||
borderRadius: BorderRadius.circular(20),
|
.firstWhere((f) => f.functionCode == selectedFunction,
|
||||||
),
|
orElse: () => DeviceFunctionData(
|
||||||
padding: const EdgeInsets.only(top: 20),
|
entityId: '',
|
||||||
child: Column(
|
functionCode: selectedFunction ?? '',
|
||||||
mainAxisSize: MainAxisSize.min,
|
operationName: '',
|
||||||
children: [
|
value: null,
|
||||||
const DialogHeader('3 Gangs Light Switch Condition'),
|
));
|
||||||
Expanded(
|
return Container(
|
||||||
child: Row(
|
width: selectedFunction != null ? 600 : 360,
|
||||||
children: [
|
height: 450,
|
||||||
// Left side: Function list
|
decoration: BoxDecoration(
|
||||||
Expanded(
|
color: Colors.white,
|
||||||
child: ListView.separated(
|
borderRadius: BorderRadius.circular(20),
|
||||||
itemCount: switchFunctions.length,
|
),
|
||||||
separatorBuilder: (_, __) => const Divider(
|
padding: const EdgeInsets.only(top: 20),
|
||||||
color: ColorsManager.dividerColor,
|
child: Column(
|
||||||
),
|
mainAxisSize: MainAxisSize.min,
|
||||||
itemBuilder: (context, index) {
|
children: [
|
||||||
final function = switchFunctions[index];
|
const DialogHeader('3 Gangs Light Switch Condition'),
|
||||||
return ValueListenableBuilder<String?>(
|
Expanded(
|
||||||
valueListenable: selectedFunctionNotifier,
|
child: Row(
|
||||||
builder: (context, selectedFunction, _) {
|
children: [
|
||||||
final isSelected =
|
// Left side: Function list
|
||||||
selectedFunction == function.code;
|
Expanded(
|
||||||
|
child: ListView.separated(
|
||||||
|
itemCount: switchFunctions.length,
|
||||||
|
separatorBuilder: (_, __) => const Divider(
|
||||||
|
color: ColorsManager.dividerColor,
|
||||||
|
),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final function = switchFunctions[index];
|
||||||
return ListTile(
|
return ListTile(
|
||||||
tileColor: isSelected
|
|
||||||
? Colors.grey.shade100
|
|
||||||
: null,
|
|
||||||
leading: SvgPicture.asset(
|
leading: SvgPicture.asset(
|
||||||
function.icon,
|
function.icon,
|
||||||
width: 24,
|
width: 24,
|
||||||
@ -83,196 +83,307 @@ class ThreeGangSwitchHelper {
|
|||||||
color: ColorsManager.textGray,
|
color: ColorsManager.textGray,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
selectedFunctionNotifier.value =
|
context
|
||||||
function.code;
|
.read<FunctionBloc>()
|
||||||
selectedValueNotifier.value = function
|
.add(SelectFunction(
|
||||||
is ThreeGangCountdown1Function ||
|
functionCode: function.code,
|
||||||
function
|
operationName:
|
||||||
is ThreeGangCountdown2Function ||
|
function.operationName,
|
||||||
function
|
));
|
||||||
is ThreeGangCountdown3Function
|
|
||||||
? 0
|
|
||||||
: null;
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
),
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// Right side: Value selector
|
|
||||||
if (selectedFunction != null)
|
|
||||||
Expanded(
|
|
||||||
child: ValueListenableBuilder<dynamic>(
|
|
||||||
valueListenable: selectedValueNotifier,
|
|
||||||
builder: (context, selectedValue, _) {
|
|
||||||
final selectedFn = switchFunctions.firstWhere(
|
|
||||||
(f) => f.code == selectedFunction,
|
|
||||||
);
|
|
||||||
return selectedFn
|
|
||||||
is ThreeGangCountdown1Function ||
|
|
||||||
selectedFn
|
|
||||||
is ThreeGangCountdown2Function ||
|
|
||||||
selectedFn
|
|
||||||
is ThreeGangCountdown3Function
|
|
||||||
? _buildCountDownSelector(
|
|
||||||
context,
|
|
||||||
selectedValueNotifier,
|
|
||||||
selectedConditionNotifier,
|
|
||||||
selectedConditionsNotifier,
|
|
||||||
)
|
|
||||||
: _buildOperationalValuesList(
|
|
||||||
context,
|
|
||||||
selectedFn as BaseSwitchFunction,
|
|
||||||
selectedValueNotifier,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
// Right side: Value selector
|
||||||
],
|
if (selectedFunction != null)
|
||||||
),
|
Expanded(
|
||||||
|
child: _buildValueSelector(
|
||||||
|
context: context,
|
||||||
|
selectedFunction: selectedFunction,
|
||||||
|
selectedFunctionData: selectedFunctionData,
|
||||||
|
switchFunctions: switchFunctions,
|
||||||
|
device: device,
|
||||||
|
operationName: selectedOperationName ?? '',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 1,
|
||||||
|
width: double.infinity,
|
||||||
|
color: ColorsManager.greyColor,
|
||||||
|
),
|
||||||
|
DialogFooter(
|
||||||
|
onCancel: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
onConfirm: state.addedFunctions.isNotEmpty
|
||||||
|
? () {
|
||||||
|
/// add the functions to the routine bloc
|
||||||
|
// for (var function in state.addedFunctions) {
|
||||||
|
// context.read<RoutineBloc>().add(
|
||||||
|
// AddFunctionToRoutine(
|
||||||
|
// function,
|
||||||
|
// uniqueCustomId,
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
context.read<RoutineBloc>().add(
|
||||||
|
AddFunctionToRoutine(
|
||||||
|
state.addedFunctions,
|
||||||
|
uniqueCustomId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
// Return the device data to be added to the container
|
||||||
|
Navigator.pop(context, {
|
||||||
|
'deviceId': functions.first.deviceId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
isConfirmEnabled: selectedFunction != null,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
DialogFooter(
|
);
|
||||||
onCancel: () => Navigator.pop(context),
|
},
|
||||||
onConfirm: selectedFunctionNotifier.value != null &&
|
|
||||||
selectedValueNotifier.value != null
|
|
||||||
? () {
|
|
||||||
final selectedFn = switchFunctions.firstWhere(
|
|
||||||
(f) => f.code == selectedFunctionNotifier.value,
|
|
||||||
);
|
|
||||||
final value = selectedValueNotifier.value;
|
|
||||||
final functionData = DeviceFunctionData(
|
|
||||||
entityId: selectedFn.deviceId,
|
|
||||||
functionCode: selectedFn.code,
|
|
||||||
operationName: selectedFn.operationName,
|
|
||||||
value: value,
|
|
||||||
condition: selectedConditionNotifier.value,
|
|
||||||
valueDescription: selectedFn
|
|
||||||
is ThreeGangCountdown1Function ||
|
|
||||||
selectedFn
|
|
||||||
is ThreeGangCountdown2Function ||
|
|
||||||
selectedFn
|
|
||||||
is ThreeGangCountdown3Function
|
|
||||||
? '${value} sec'
|
|
||||||
: ((selectedFn as BaseSwitchFunction)
|
|
||||||
.getOperationalValues()
|
|
||||||
.firstWhere((v) => v.value == value)
|
|
||||||
.description),
|
|
||||||
);
|
|
||||||
Navigator.pop(
|
|
||||||
context, {selectedFn.code: functionData});
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
isConfirmEnabled: selectedFunctionNotifier.value != null,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
).then((value) {
|
|
||||||
selectedFunctionNotifier.dispose();
|
|
||||||
selectedValueNotifier.dispose();
|
|
||||||
selectedConditionNotifier.dispose();
|
|
||||||
selectedConditionsNotifier.dispose();
|
|
||||||
return value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static Widget _buildCountDownSelector(
|
|
||||||
BuildContext context,
|
|
||||||
ValueNotifier<dynamic> valueNotifier,
|
|
||||||
ValueNotifier<String?> conditionNotifier,
|
|
||||||
ValueNotifier<List<bool>> conditionsNotifier,
|
|
||||||
) {
|
|
||||||
return ValueListenableBuilder<dynamic>(
|
|
||||||
valueListenable: valueNotifier,
|
|
||||||
builder: (context, value, _) {
|
|
||||||
return Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
ValueListenableBuilder<List<bool>>(
|
|
||||||
valueListenable: conditionsNotifier,
|
|
||||||
builder: (context, selectedConditions, _) {
|
|
||||||
return ToggleButtons(
|
|
||||||
onPressed: (int index) {
|
|
||||||
final newConditions = List<bool>.filled(3, false);
|
|
||||||
newConditions[index] = true;
|
|
||||||
conditionsNotifier.value = newConditions;
|
|
||||||
conditionNotifier.value = index == 0
|
|
||||||
? "<"
|
|
||||||
: index == 1
|
|
||||||
? "=="
|
|
||||||
: ">";
|
|
||||||
},
|
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
|
||||||
selectedBorderColor: ColorsManager.primaryColorWithOpacity,
|
|
||||||
selectedColor: Colors.white,
|
|
||||||
fillColor: ColorsManager.primaryColorWithOpacity,
|
|
||||||
color: ColorsManager.primaryColorWithOpacity,
|
|
||||||
constraints: const BoxConstraints(
|
|
||||||
minHeight: 40.0,
|
|
||||||
minWidth: 40.0,
|
|
||||||
),
|
|
||||||
isSelected: selectedConditions,
|
|
||||||
children: const [Text("<"), Text("="), Text(">")],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
Text(
|
|
||||||
'${value ?? 0} sec',
|
|
||||||
style: Theme.of(context).textTheme.headlineMedium,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
Slider(
|
|
||||||
value: (value ?? 0).toDouble(),
|
|
||||||
min: 0,
|
|
||||||
max: 300,
|
|
||||||
divisions: 300,
|
|
||||||
onChanged: (newValue) {
|
|
||||||
valueNotifier.value = newValue.toInt();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Widget _buildOperationalValuesList(
|
static Widget _buildValueSelector({
|
||||||
|
required BuildContext context,
|
||||||
|
required String selectedFunction,
|
||||||
|
required DeviceFunctionData? selectedFunctionData,
|
||||||
|
required List<BaseSwitchFunction> switchFunctions,
|
||||||
|
AllDevicesModel? device,
|
||||||
|
required String operationName,
|
||||||
|
}) {
|
||||||
|
if (selectedFunction == 'countdown_1' ||
|
||||||
|
selectedFunction == 'countdown_2' ||
|
||||||
|
selectedFunction == 'countdown_3') {
|
||||||
|
final initialValue = selectedFunctionData?.value ?? 200;
|
||||||
|
return _buildTemperatureSelector(
|
||||||
|
context: context,
|
||||||
|
initialValue: initialValue,
|
||||||
|
selectCode: selectedFunction,
|
||||||
|
currentCondition: selectedFunctionData?.condition,
|
||||||
|
device: device,
|
||||||
|
operationName: operationName,
|
||||||
|
selectedFunctionData: selectedFunctionData,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final selectedFn =
|
||||||
|
switchFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||||
|
final values = selectedFn.getOperationalValues();
|
||||||
|
|
||||||
|
return _buildOperationalValuesList(
|
||||||
|
context: context,
|
||||||
|
values: values,
|
||||||
|
selectedValue: selectedFunctionData?.value,
|
||||||
|
device: device,
|
||||||
|
operationName: operationName,
|
||||||
|
selectCode: selectedFunction,
|
||||||
|
selectedFunctionData: selectedFunctionData,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Widget _buildTemperatureSelector({
|
||||||
|
required BuildContext context,
|
||||||
|
required dynamic initialValue,
|
||||||
|
required String? currentCondition,
|
||||||
|
required String selectCode,
|
||||||
|
AllDevicesModel? device,
|
||||||
|
required String operationName,
|
||||||
|
DeviceFunctionData? selectedFunctionData,
|
||||||
|
}) {
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
_buildConditionToggle(
|
||||||
|
context,
|
||||||
|
currentCondition,
|
||||||
|
selectCode,
|
||||||
|
device,
|
||||||
|
operationName,
|
||||||
|
selectedFunctionData,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
_buildCountDownDisplay(context, initialValue, device, operationName,
|
||||||
|
selectedFunctionData, selectCode),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
_buildCountDownSlider(context, initialValue, device, operationName,
|
||||||
|
selectedFunctionData, selectCode),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build condition toggle for AC functions dialog
|
||||||
|
static Widget _buildConditionToggle(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
BaseSwitchFunction function,
|
String? currentCondition,
|
||||||
ValueNotifier<dynamic> valueNotifier,
|
String selectCode,
|
||||||
|
AllDevicesModel? device,
|
||||||
|
String operationName,
|
||||||
|
DeviceFunctionData? selectedFunctionData,
|
||||||
|
// Function(String) onConditionChanged,
|
||||||
) {
|
) {
|
||||||
final values = function.getOperationalValues();
|
final conditions = ["<", "==", ">"];
|
||||||
return ValueListenableBuilder<dynamic>(
|
|
||||||
valueListenable: valueNotifier,
|
return ToggleButtons(
|
||||||
builder: (context, selectedValue, _) {
|
onPressed: (int index) {
|
||||||
return ListView.builder(
|
context.read<FunctionBloc>().add(
|
||||||
itemCount: values.length,
|
AddFunction(
|
||||||
itemBuilder: (context, index) {
|
functionData: DeviceFunctionData(
|
||||||
final value = values[index];
|
entityId: device?.uuid ?? '',
|
||||||
return ListTile(
|
functionCode: selectCode,
|
||||||
leading: SvgPicture.asset(
|
operationName: operationName,
|
||||||
value.icon,
|
condition: conditions[index],
|
||||||
width: 24,
|
value: selectedFunctionData?.value,
|
||||||
height: 24,
|
valueDescription: selectedFunctionData?.valueDescription,
|
||||||
),
|
),
|
||||||
title: Text(
|
|
||||||
value.description,
|
|
||||||
style: context.textTheme.bodyMedium,
|
|
||||||
),
|
|
||||||
trailing: Radio<dynamic>(
|
|
||||||
value: value.value,
|
|
||||||
groupValue: selectedValue,
|
|
||||||
onChanged: (newValue) {
|
|
||||||
valueNotifier.value = newValue;
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||||
|
selectedBorderColor: ColorsManager.primaryColorWithOpacity,
|
||||||
|
selectedColor: Colors.white,
|
||||||
|
fillColor: ColorsManager.primaryColorWithOpacity,
|
||||||
|
color: ColorsManager.primaryColorWithOpacity,
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
minHeight: 40.0,
|
||||||
|
minWidth: 40.0,
|
||||||
|
),
|
||||||
|
isSelected:
|
||||||
|
conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||||
|
children: conditions.map((c) => Text(c)).toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build temperature display for AC functions dialog
|
||||||
|
static Widget _buildCountDownDisplay(
|
||||||
|
BuildContext context,
|
||||||
|
dynamic initialValue,
|
||||||
|
AllDevicesModel? device,
|
||||||
|
String operationName,
|
||||||
|
DeviceFunctionData? selectedFunctionData,
|
||||||
|
String selectCode) {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: ColorsManager.primaryColorWithOpacity.withOpacity(0.1),
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
'${initialValue ?? 0} sec',
|
||||||
|
style: context.textTheme.headlineMedium!.copyWith(
|
||||||
|
color: ColorsManager.primaryColorWithOpacity,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Widget _buildCountDownSlider(
|
||||||
|
BuildContext context,
|
||||||
|
dynamic initialValue,
|
||||||
|
AllDevicesModel? device,
|
||||||
|
String operationName,
|
||||||
|
DeviceFunctionData? selectedFunctionData,
|
||||||
|
String selectCode,
|
||||||
|
) {
|
||||||
|
final operationalValues = SwitchOperationalValue(
|
||||||
|
icon: '',
|
||||||
|
description: "sec",
|
||||||
|
value: 0.0,
|
||||||
|
minValue: 0,
|
||||||
|
maxValue: 43200,
|
||||||
|
stepValue: 1,
|
||||||
|
);
|
||||||
|
return Slider(
|
||||||
|
value: (initialValue ?? 0).toDouble(),
|
||||||
|
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
||||||
|
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
||||||
|
divisions: (((operationalValues.maxValue ?? 0) -
|
||||||
|
(operationalValues.minValue ?? 0)) /
|
||||||
|
(operationalValues.stepValue ?? 1))
|
||||||
|
.round(),
|
||||||
|
onChanged: (value) {
|
||||||
|
context.read<FunctionBloc>().add(
|
||||||
|
AddFunction(
|
||||||
|
functionData: DeviceFunctionData(
|
||||||
|
entityId: device?.uuid ?? '',
|
||||||
|
functionCode: selectCode,
|
||||||
|
operationName: operationName,
|
||||||
|
value: value,
|
||||||
|
condition: selectedFunctionData?.condition,
|
||||||
|
valueDescription: selectedFunctionData?.valueDescription,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Widget _buildOperationalValuesList({
|
||||||
|
required BuildContext context,
|
||||||
|
required List<SwitchOperationalValue> values,
|
||||||
|
required dynamic selectedValue,
|
||||||
|
AllDevicesModel? device,
|
||||||
|
required String operationName,
|
||||||
|
required String selectCode,
|
||||||
|
DeviceFunctionData? selectedFunctionData,
|
||||||
|
}) {
|
||||||
|
return ListView.builder(
|
||||||
|
shrinkWrap: false,
|
||||||
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
|
itemCount: values.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final value = values[index];
|
||||||
|
final isSelected = selectedValue == value.value;
|
||||||
|
return ListTile(
|
||||||
|
leading: SvgPicture.asset(
|
||||||
|
value.icon,
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
placeholderBuilder: (BuildContext context) => Container(
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
color: Colors.transparent,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
value.description,
|
||||||
|
style: context.textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
trailing: Icon(
|
||||||
|
isSelected
|
||||||
|
? Icons.radio_button_checked
|
||||||
|
: Icons.radio_button_unchecked,
|
||||||
|
size: 24,
|
||||||
|
color: isSelected
|
||||||
|
? ColorsManager.primaryColorWithOpacity
|
||||||
|
: ColorsManager.textGray,
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
if (!isSelected) {
|
||||||
|
context.read<FunctionBloc>().add(
|
||||||
|
AddFunction(
|
||||||
|
functionData: DeviceFunctionData(
|
||||||
|
entityId: device?.uuid ?? '',
|
||||||
|
functionCode: selectCode,
|
||||||
|
operationName: operationName,
|
||||||
|
value: value.value,
|
||||||
|
condition: selectedFunctionData?.condition,
|
||||||
|
valueDescription:
|
||||||
|
selectedFunctionData?.valueDescription,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/routiens/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/routiens/bloc/routine_bloc/routine_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routiens/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/base_switch_function.dart';
|
import 'package:syncrow_web/pages/routiens/models/gang_switches/base_switch_function.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/models/gang_switches/two_gang_switch/two_gang_switch.dart';
|
import 'package:syncrow_web/pages/routiens/models/gang_switches/switch_operational_value.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
import 'package:syncrow_web/pages/routiens/widgets/dialog_footer.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
import 'package:syncrow_web/pages/routiens/widgets/dialog_header.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
@ -10,62 +14,60 @@ import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|||||||
|
|
||||||
class TwoGangSwitchHelper {
|
class TwoGangSwitchHelper {
|
||||||
static Future<Map<String, dynamic>?> showSwitchFunctionsDialog(
|
static Future<Map<String, dynamic>?> showSwitchFunctionsDialog(
|
||||||
BuildContext context, List<DeviceFunction<dynamic>> functions) async {
|
BuildContext context,
|
||||||
List<DeviceFunction<dynamic>> switchFunctions = functions
|
List<DeviceFunction> functions,
|
||||||
.where((f) =>
|
AllDevicesModel? device,
|
||||||
f is TwoGangSwitch1Function ||
|
List<DeviceFunctionData>? deviceSelectedFunctions,
|
||||||
f is TwoGangSwitch2Function ||
|
String uniqueCustomId,
|
||||||
f is TwoGangCountdown1Function ||
|
) async {
|
||||||
f is TwoGangCountdown2Function)
|
List<BaseSwitchFunction> switchFunctions =
|
||||||
.toList();
|
functions.whereType<BaseSwitchFunction>().toList();
|
||||||
|
|
||||||
final selectedFunctionNotifier = ValueNotifier<String?>(null);
|
return showDialog<Map<String, dynamic>?>(
|
||||||
final selectedValueNotifier = ValueNotifier<dynamic>(null);
|
|
||||||
final selectedConditionNotifier = ValueNotifier<String?>('<');
|
|
||||||
final selectedConditionsNotifier =
|
|
||||||
ValueNotifier<List<bool>>([true, false, false]);
|
|
||||||
|
|
||||||
await showDialog(
|
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return ValueListenableBuilder<String?>(
|
return BlocProvider(
|
||||||
valueListenable: selectedFunctionNotifier,
|
create: (_) => FunctionBloc()
|
||||||
builder: (context, selectedFunction, _) {
|
..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
||||||
return AlertDialog(
|
child: AlertDialog(
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
content: Container(
|
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
||||||
width: selectedFunction != null ? 600 : 300,
|
builder: (context, state) {
|
||||||
height: 450,
|
final selectedFunction = state.selectedFunction;
|
||||||
decoration: BoxDecoration(
|
final selectedOperationName = state.selectedOperationName;
|
||||||
color: Colors.white,
|
final selectedFunctionData = state.addedFunctions
|
||||||
borderRadius: BorderRadius.circular(20),
|
.firstWhere((f) => f.functionCode == selectedFunction,
|
||||||
),
|
orElse: () => DeviceFunctionData(
|
||||||
padding: const EdgeInsets.only(top: 20),
|
entityId: '',
|
||||||
child: Column(
|
functionCode: selectedFunction ?? '',
|
||||||
mainAxisSize: MainAxisSize.min,
|
operationName: '',
|
||||||
children: [
|
value: null,
|
||||||
const DialogHeader('2 Gangs Light Switch Condition'),
|
));
|
||||||
Expanded(
|
return Container(
|
||||||
child: Row(
|
width: selectedFunction != null ? 600 : 360,
|
||||||
children: [
|
height: 450,
|
||||||
// Left side: Function list
|
decoration: BoxDecoration(
|
||||||
Expanded(
|
color: Colors.white,
|
||||||
child: ListView.separated(
|
borderRadius: BorderRadius.circular(20),
|
||||||
itemCount: switchFunctions.length,
|
),
|
||||||
separatorBuilder: (_, __) => const Divider(
|
padding: const EdgeInsets.only(top: 20),
|
||||||
color: ColorsManager.dividerColor,
|
child: Column(
|
||||||
),
|
mainAxisSize: MainAxisSize.min,
|
||||||
itemBuilder: (context, index) {
|
children: [
|
||||||
final function = switchFunctions[index];
|
const DialogHeader('2 Gangs Light Switch Condition'),
|
||||||
return ValueListenableBuilder<String?>(
|
Expanded(
|
||||||
valueListenable: selectedFunctionNotifier,
|
child: Row(
|
||||||
builder: (context, selectedFunction, _) {
|
children: [
|
||||||
final isSelected =
|
// Left side: Function list
|
||||||
selectedFunction == function.code;
|
Expanded(
|
||||||
|
child: ListView.separated(
|
||||||
|
itemCount: switchFunctions.length,
|
||||||
|
separatorBuilder: (_, __) => const Divider(
|
||||||
|
color: ColorsManager.dividerColor,
|
||||||
|
),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final function = switchFunctions[index];
|
||||||
return ListTile(
|
return ListTile(
|
||||||
tileColor: isSelected
|
|
||||||
? Colors.grey.shade100
|
|
||||||
: null,
|
|
||||||
leading: SvgPicture.asset(
|
leading: SvgPicture.asset(
|
||||||
function.icon,
|
function.icon,
|
||||||
width: 24,
|
width: 24,
|
||||||
@ -81,191 +83,307 @@ class TwoGangSwitchHelper {
|
|||||||
color: ColorsManager.textGray,
|
color: ColorsManager.textGray,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
selectedFunctionNotifier.value =
|
context
|
||||||
function.code;
|
.read<FunctionBloc>()
|
||||||
selectedValueNotifier.value = function
|
.add(SelectFunction(
|
||||||
is TwoGangCountdown1Function ||
|
functionCode: function.code,
|
||||||
function
|
operationName:
|
||||||
is TwoGangCountdown2Function
|
function.operationName,
|
||||||
? 0
|
));
|
||||||
: null;
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
),
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// Right side: Value selector
|
|
||||||
if (selectedFunction != null)
|
|
||||||
Expanded(
|
|
||||||
child: ValueListenableBuilder<dynamic>(
|
|
||||||
valueListenable: selectedValueNotifier,
|
|
||||||
builder: (context, selectedValue, _) {
|
|
||||||
final selectedFn = switchFunctions.firstWhere(
|
|
||||||
(f) => f.code == selectedFunction,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (selectedFn is TwoGangCountdown1Function ||
|
|
||||||
selectedFn is TwoGangCountdown2Function) {
|
|
||||||
return _buildCountDownSelector(
|
|
||||||
context,
|
|
||||||
selectedValueNotifier,
|
|
||||||
selectedConditionNotifier,
|
|
||||||
selectedConditionsNotifier,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _buildOperationalValuesList(
|
|
||||||
context,
|
|
||||||
selectedFn as BaseSwitchFunction,
|
|
||||||
selectedValueNotifier,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
// Right side: Value selector
|
||||||
],
|
if (selectedFunction != null)
|
||||||
),
|
Expanded(
|
||||||
|
child: _buildValueSelector(
|
||||||
|
context: context,
|
||||||
|
selectedFunction: selectedFunction,
|
||||||
|
selectedFunctionData: selectedFunctionData,
|
||||||
|
switchFunctions: switchFunctions,
|
||||||
|
device: device,
|
||||||
|
operationName: selectedOperationName ?? '',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 1,
|
||||||
|
width: double.infinity,
|
||||||
|
color: ColorsManager.greyColor,
|
||||||
|
),
|
||||||
|
DialogFooter(
|
||||||
|
onCancel: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
onConfirm: state.addedFunctions.isNotEmpty
|
||||||
|
? () {
|
||||||
|
/// add the functions to the routine bloc
|
||||||
|
// for (var function in state.addedFunctions) {
|
||||||
|
// context.read<RoutineBloc>().add(
|
||||||
|
// AddFunctionToRoutine(
|
||||||
|
// function,
|
||||||
|
// uniqueCustomId
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
context.read<RoutineBloc>().add(
|
||||||
|
AddFunctionToRoutine(
|
||||||
|
state.addedFunctions,
|
||||||
|
uniqueCustomId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
// Return the device data to be added to the container
|
||||||
|
Navigator.pop(context, {
|
||||||
|
'deviceId': functions.first.deviceId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
isConfirmEnabled: selectedFunction != null,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
DialogFooter(
|
);
|
||||||
onCancel: () => Navigator.pop(context),
|
|
||||||
onConfirm: selectedFunction != null &&
|
|
||||||
selectedValueNotifier.value != null
|
|
||||||
? () {
|
|
||||||
final selectedFn = switchFunctions.firstWhere(
|
|
||||||
(f) => f.code == selectedFunction,
|
|
||||||
);
|
|
||||||
final value = selectedValueNotifier.value;
|
|
||||||
final functionData = DeviceFunctionData(
|
|
||||||
entityId: selectedFn.deviceId,
|
|
||||||
functionCode: selectedFn.code,
|
|
||||||
operationName: selectedFn.operationName,
|
|
||||||
value: value,
|
|
||||||
condition: selectedConditionNotifier.value,
|
|
||||||
valueDescription: selectedFn
|
|
||||||
is TwoGangCountdown1Function ||
|
|
||||||
selectedFn is TwoGangCountdown2Function
|
|
||||||
? '${value} sec'
|
|
||||||
: ((selectedFn as BaseSwitchFunction)
|
|
||||||
.getOperationalValues()
|
|
||||||
.firstWhere((v) => v.value == value)
|
|
||||||
.description),
|
|
||||||
);
|
|
||||||
Navigator.pop(
|
|
||||||
context, {selectedFn.code: functionData});
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
isConfirmEnabled: selectedFunction != null,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
).then((value) {
|
|
||||||
selectedFunctionNotifier.dispose();
|
|
||||||
selectedValueNotifier.dispose();
|
|
||||||
selectedConditionNotifier.dispose();
|
|
||||||
selectedConditionsNotifier.dispose();
|
|
||||||
return value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static Widget _buildOperationalValuesList(
|
|
||||||
BuildContext context,
|
|
||||||
BaseSwitchFunction function,
|
|
||||||
ValueNotifier<dynamic> valueNotifier,
|
|
||||||
) {
|
|
||||||
final values = function.getOperationalValues();
|
|
||||||
return ValueListenableBuilder<dynamic>(
|
|
||||||
valueListenable: valueNotifier,
|
|
||||||
builder: (context, selectedValue, _) {
|
|
||||||
return ListView.builder(
|
|
||||||
itemCount: values.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final value = values[index];
|
|
||||||
return ListTile(
|
|
||||||
leading: SvgPicture.asset(
|
|
||||||
value.icon,
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
value.description,
|
|
||||||
style: context.textTheme.bodyMedium,
|
|
||||||
),
|
|
||||||
trailing: Radio<dynamic>(
|
|
||||||
value: value.value,
|
|
||||||
groupValue: selectedValue,
|
|
||||||
onChanged: (newValue) {
|
|
||||||
valueNotifier.value = newValue;
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Widget _buildCountDownSelector(
|
static Widget _buildValueSelector({
|
||||||
|
required BuildContext context,
|
||||||
|
required String selectedFunction,
|
||||||
|
required DeviceFunctionData? selectedFunctionData,
|
||||||
|
required List<BaseSwitchFunction> switchFunctions,
|
||||||
|
AllDevicesModel? device,
|
||||||
|
required String operationName,
|
||||||
|
}) {
|
||||||
|
if (selectedFunction == 'countdown_1' ||
|
||||||
|
selectedFunction == 'countdown_2') {
|
||||||
|
final initialValue = selectedFunctionData?.value ?? 200;
|
||||||
|
return _buildTemperatureSelector(
|
||||||
|
context: context,
|
||||||
|
initialValue: initialValue,
|
||||||
|
selectCode: selectedFunction,
|
||||||
|
currentCondition: selectedFunctionData?.condition,
|
||||||
|
device: device,
|
||||||
|
operationName: operationName,
|
||||||
|
selectedFunctionData: selectedFunctionData,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final selectedFn =
|
||||||
|
switchFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||||
|
final values = selectedFn.getOperationalValues();
|
||||||
|
|
||||||
|
return _buildOperationalValuesList(
|
||||||
|
context: context,
|
||||||
|
values: values,
|
||||||
|
selectedValue: selectedFunctionData?.value,
|
||||||
|
device: device,
|
||||||
|
operationName: operationName,
|
||||||
|
selectCode: selectedFunction,
|
||||||
|
selectedFunctionData: selectedFunctionData,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Widget _buildTemperatureSelector({
|
||||||
|
required BuildContext context,
|
||||||
|
required dynamic initialValue,
|
||||||
|
required String? currentCondition,
|
||||||
|
required String selectCode,
|
||||||
|
AllDevicesModel? device,
|
||||||
|
required String operationName,
|
||||||
|
DeviceFunctionData? selectedFunctionData,
|
||||||
|
}) {
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
_buildConditionToggle(
|
||||||
|
context,
|
||||||
|
currentCondition,
|
||||||
|
selectCode,
|
||||||
|
device,
|
||||||
|
operationName,
|
||||||
|
selectedFunctionData,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
_buildCountDownDisplay(context, initialValue, device, operationName,
|
||||||
|
selectedFunctionData, selectCode),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
_buildCountDownSlider(context, initialValue, device, operationName,
|
||||||
|
selectedFunctionData, selectCode),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build condition toggle for AC functions dialog
|
||||||
|
static Widget _buildConditionToggle(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
ValueNotifier<dynamic> valueNotifier,
|
String? currentCondition,
|
||||||
ValueNotifier<String?> conditionNotifier,
|
String selectCode,
|
||||||
ValueNotifier<List<bool>> conditionsNotifier,
|
AllDevicesModel? device,
|
||||||
|
String operationName,
|
||||||
|
DeviceFunctionData? selectedFunctionData,
|
||||||
|
// Function(String) onConditionChanged,
|
||||||
) {
|
) {
|
||||||
return ValueListenableBuilder<dynamic>(
|
final conditions = ["<", "==", ">"];
|
||||||
valueListenable: valueNotifier,
|
|
||||||
builder: (context, value, _) {
|
return ToggleButtons(
|
||||||
return Column(
|
onPressed: (int index) {
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
context.read<FunctionBloc>().add(
|
||||||
children: [
|
AddFunction(
|
||||||
ValueListenableBuilder<List<bool>>(
|
functionData: DeviceFunctionData(
|
||||||
valueListenable: conditionsNotifier,
|
entityId: device?.uuid ?? '',
|
||||||
builder: (context, selectedConditions, _) {
|
functionCode: selectCode,
|
||||||
return ToggleButtons(
|
operationName: operationName,
|
||||||
onPressed: (int index) {
|
condition: conditions[index],
|
||||||
final newConditions = List<bool>.filled(3, false);
|
value: selectedFunctionData?.value,
|
||||||
newConditions[index] = true;
|
valueDescription: selectedFunctionData?.valueDescription,
|
||||||
conditionsNotifier.value = newConditions;
|
),
|
||||||
conditionNotifier.value = index == 0
|
),
|
||||||
? "<"
|
);
|
||||||
: index == 1
|
},
|
||||||
? "=="
|
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||||
: ">";
|
selectedBorderColor: ColorsManager.primaryColorWithOpacity,
|
||||||
},
|
selectedColor: Colors.white,
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
fillColor: ColorsManager.primaryColorWithOpacity,
|
||||||
selectedBorderColor: ColorsManager.primaryColorWithOpacity,
|
color: ColorsManager.primaryColorWithOpacity,
|
||||||
selectedColor: Colors.white,
|
constraints: const BoxConstraints(
|
||||||
fillColor: ColorsManager.primaryColorWithOpacity,
|
minHeight: 40.0,
|
||||||
color: ColorsManager.primaryColorWithOpacity,
|
minWidth: 40.0,
|
||||||
constraints: const BoxConstraints(
|
),
|
||||||
minHeight: 40.0,
|
isSelected:
|
||||||
minWidth: 40.0,
|
conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||||
),
|
children: conditions.map((c) => Text(c)).toList(),
|
||||||
isSelected: selectedConditions,
|
);
|
||||||
children: const [Text("<"), Text("="), Text(">")],
|
}
|
||||||
);
|
|
||||||
},
|
/// Build temperature display for AC functions dialog
|
||||||
|
static Widget _buildCountDownDisplay(
|
||||||
|
BuildContext context,
|
||||||
|
dynamic initialValue,
|
||||||
|
AllDevicesModel? device,
|
||||||
|
String operationName,
|
||||||
|
DeviceFunctionData? selectedFunctionData,
|
||||||
|
String selectCode) {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: ColorsManager.primaryColorWithOpacity.withOpacity(0.1),
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
'${initialValue ?? 0} sec',
|
||||||
|
style: context.textTheme.headlineMedium!.copyWith(
|
||||||
|
color: ColorsManager.primaryColorWithOpacity,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Widget _buildCountDownSlider(
|
||||||
|
BuildContext context,
|
||||||
|
dynamic initialValue,
|
||||||
|
AllDevicesModel? device,
|
||||||
|
String operationName,
|
||||||
|
DeviceFunctionData? selectedFunctionData,
|
||||||
|
String selectCode,
|
||||||
|
) {
|
||||||
|
final operationalValues = SwitchOperationalValue(
|
||||||
|
icon: '',
|
||||||
|
description: "sec",
|
||||||
|
value: 0.0,
|
||||||
|
minValue: 0,
|
||||||
|
maxValue: 43200,
|
||||||
|
stepValue: 1,
|
||||||
|
);
|
||||||
|
return Slider(
|
||||||
|
value: (initialValue ?? 0).toDouble(),
|
||||||
|
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
||||||
|
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
||||||
|
divisions: (((operationalValues.maxValue ?? 0) -
|
||||||
|
(operationalValues.minValue ?? 0)) /
|
||||||
|
(operationalValues.stepValue ?? 1))
|
||||||
|
.round(),
|
||||||
|
onChanged: (value) {
|
||||||
|
context.read<FunctionBloc>().add(
|
||||||
|
AddFunction(
|
||||||
|
functionData: DeviceFunctionData(
|
||||||
|
entityId: device?.uuid ?? '',
|
||||||
|
functionCode: selectCode,
|
||||||
|
operationName: operationName,
|
||||||
|
value: value,
|
||||||
|
condition: selectedFunctionData?.condition,
|
||||||
|
valueDescription: selectedFunctionData?.valueDescription,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Widget _buildOperationalValuesList({
|
||||||
|
required BuildContext context,
|
||||||
|
required List<SwitchOperationalValue> values,
|
||||||
|
required dynamic selectedValue,
|
||||||
|
AllDevicesModel? device,
|
||||||
|
required String operationName,
|
||||||
|
required String selectCode,
|
||||||
|
DeviceFunctionData? selectedFunctionData,
|
||||||
|
}) {
|
||||||
|
return ListView.builder(
|
||||||
|
shrinkWrap: false,
|
||||||
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
|
itemCount: values.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final value = values[index];
|
||||||
|
final isSelected = selectedValue == value.value;
|
||||||
|
return ListTile(
|
||||||
|
leading: SvgPicture.asset(
|
||||||
|
value.icon,
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
placeholderBuilder: (BuildContext context) => Container(
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
color: Colors.transparent,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
),
|
||||||
Text(
|
title: Text(
|
||||||
'${value ?? 0} sec',
|
value.description,
|
||||||
style: Theme.of(context).textTheme.headlineMedium,
|
style: context.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
trailing: Icon(
|
||||||
Slider(
|
isSelected
|
||||||
value: (value ?? 0).toDouble(),
|
? Icons.radio_button_checked
|
||||||
min: 0,
|
: Icons.radio_button_unchecked,
|
||||||
max: 300,
|
size: 24,
|
||||||
divisions: 300,
|
color: isSelected
|
||||||
onChanged: (newValue) {
|
? ColorsManager.primaryColorWithOpacity
|
||||||
valueNotifier.value = newValue.toInt();
|
: ColorsManager.textGray,
|
||||||
},
|
),
|
||||||
),
|
onTap: () {
|
||||||
],
|
if (!isSelected) {
|
||||||
|
context.read<FunctionBloc>().add(
|
||||||
|
AddFunction(
|
||||||
|
functionData: DeviceFunctionData(
|
||||||
|
entityId: device?.uuid ?? '',
|
||||||
|
functionCode: selectCode,
|
||||||
|
operationName: operationName,
|
||||||
|
value: value.value,
|
||||||
|
condition: selectedFunctionData?.condition,
|
||||||
|
valueDescription:
|
||||||
|
selectedFunctionData?.valueDescription,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
abstract class DeviceFunction<T> {
|
abstract class DeviceFunction<T> {
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
final String deviceName;
|
final String deviceName;
|
||||||
@ -24,7 +22,6 @@ class DeviceFunctionData {
|
|||||||
final dynamic value;
|
final dynamic value;
|
||||||
final String? condition;
|
final String? condition;
|
||||||
final String? valueDescription;
|
final String? valueDescription;
|
||||||
final UniqueKey uniqueKey;
|
|
||||||
|
|
||||||
DeviceFunctionData({
|
DeviceFunctionData({
|
||||||
required this.entityId,
|
required this.entityId,
|
||||||
@ -34,7 +31,7 @@ class DeviceFunctionData {
|
|||||||
required this.value,
|
required this.value,
|
||||||
this.condition,
|
this.condition,
|
||||||
this.valueDescription,
|
this.valueDescription,
|
||||||
}) : uniqueKey = UniqueKey();
|
});
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {
|
return {
|
||||||
|
@ -1,29 +1,30 @@
|
|||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
// import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||||
|
|
||||||
class RoutineItem {
|
// class RoutineItem {
|
||||||
final AllDevicesModel device;
|
// final AllDevicesModel device;
|
||||||
final String? function;
|
// final String? function;
|
||||||
final dynamic value;
|
// final dynamic value;
|
||||||
|
|
||||||
RoutineItem({
|
// RoutineItem({
|
||||||
required this.device,
|
// required this.device,
|
||||||
this.function,
|
// this.function,
|
||||||
this.value,
|
// this.value,
|
||||||
});
|
// });
|
||||||
|
|
||||||
Map<String, dynamic> toMap() {
|
// Map<String, dynamic> toMap() {
|
||||||
return {
|
// return {
|
||||||
'device': device,
|
// 'device': device,
|
||||||
'function': function,
|
// 'function': function,
|
||||||
'value': value,
|
// 'value': value,
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
|
|
||||||
factory RoutineItem.fromMap(Map<String, dynamic> map) {
|
// factory RoutineItem.fromMap(Map<String, dynamic> map) {
|
||||||
return RoutineItem(
|
// return RoutineItem(
|
||||||
device: map['device'] as AllDevicesModel,
|
// device: map['device'] as AllDevicesModel,
|
||||||
function: map['function'],
|
// function: map['function'],
|
||||||
value: map['value'],
|
// value: map['value'],
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
// : uniqueCustomId = uniqueCustomId ?? const Uuid().v4()
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
class ScenesModel {
|
class ScenesModel {
|
||||||
final String id;
|
final String id;
|
||||||
final String name;
|
final String name;
|
||||||
@ -7,11 +5,13 @@ class ScenesModel {
|
|||||||
final String type;
|
final String type;
|
||||||
final String? icon;
|
final String? icon;
|
||||||
|
|
||||||
ScenesModel({required this.id, required this.name, required this.status, required this.type, this.icon});
|
ScenesModel({
|
||||||
|
required this.id,
|
||||||
factory ScenesModel.fromRawJson(String str) => ScenesModel.fromJson(json.decode(str));
|
required this.name,
|
||||||
|
required this.status,
|
||||||
String toRawJson() => json.encode(toJson());
|
required this.type,
|
||||||
|
this.icon,
|
||||||
|
});
|
||||||
|
|
||||||
factory ScenesModel.fromJson(Map<String, dynamic> json) => ScenesModel(
|
factory ScenesModel.fromJson(Map<String, dynamic> json) => ScenesModel(
|
||||||
id: json["id"],
|
id: json["id"],
|
||||||
|
@ -22,9 +22,8 @@ class DraggableCard extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<RoutineBloc, RoutineState>(
|
return BlocBuilder<RoutineBloc, RoutineState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final deviceFunctions = state.selectedFunctions
|
final deviceFunctions =
|
||||||
.where((f) => f.entityId == deviceData['deviceId'])
|
state.selectedFunctions[deviceData['uniqueCustomId']] ?? [];
|
||||||
.toList();
|
|
||||||
|
|
||||||
return Draggable<Map<String, dynamic>>(
|
return Draggable<Map<String, dynamic>>(
|
||||||
data: deviceData,
|
data: deviceData,
|
||||||
@ -45,7 +44,7 @@ class DraggableCard extends StatelessWidget {
|
|||||||
color: ColorsManager.whiteColors,
|
color: ColorsManager.whiteColors,
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
width: 90,
|
width: 110,
|
||||||
height: deviceFunctions.isEmpty ? 123 : null,
|
height: deviceFunctions.isEmpty ? 123 : null,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
@ -3,6 +3,7 @@ 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/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';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class RoutineDevices extends StatelessWidget {
|
class RoutineDevices extends StatelessWidget {
|
||||||
const RoutineDevices({super.key});
|
const RoutineDevices({super.key});
|
||||||
|
@ -5,6 +5,7 @@ import 'package:flutter_bloc/flutter_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/dialog_helper/device_dialog_helper.dart';
|
import 'package:syncrow_web/pages/routiens/helper/dialog_helper/device_dialog_helper.dart';
|
||||||
import 'package:syncrow_web/pages/routiens/widgets/dragable_card.dart';
|
import 'package:syncrow_web/pages/routiens/widgets/dragable_card.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class ThenContainer extends StatelessWidget {
|
class ThenContainer extends StatelessWidget {
|
||||||
const ThenContainer({super.key});
|
const ThenContainer({super.key});
|
||||||
@ -15,34 +16,38 @@ class ThenContainer extends StatelessWidget {
|
|||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
return DragTarget<Map<String, dynamic>>(
|
return DragTarget<Map<String, dynamic>>(
|
||||||
builder: (context, candidateData, rejectedData) {
|
builder: (context, candidateData, rejectedData) {
|
||||||
return Container(
|
return SingleChildScrollView(
|
||||||
padding: const EdgeInsets.all(16),
|
child: Container(
|
||||||
width: double.infinity,
|
padding: const EdgeInsets.all(16),
|
||||||
child: Column(
|
width: double.infinity,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
child: Column(
|
||||||
children: [
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
const Text('THEN',
|
children: [
|
||||||
style:
|
const Text('THEN',
|
||||||
TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
style: TextStyle(
|
||||||
const SizedBox(height: 16),
|
fontSize: 18, fontWeight: FontWeight.bold)),
|
||||||
Wrap(
|
const SizedBox(height: 16),
|
||||||
spacing: 8,
|
Wrap(
|
||||||
runSpacing: 8,
|
spacing: 8,
|
||||||
children: state.thenItems
|
runSpacing: 8,
|
||||||
.map((item) => DraggableCard(
|
children: state.thenItems
|
||||||
// key: Key(item['key']!),
|
.map((item) => DraggableCard(
|
||||||
imagePath: item['imagePath']!,
|
// key: Key(item['key']!),
|
||||||
title: item['title']!,
|
imagePath: item['imagePath']!,
|
||||||
deviceData: item,
|
title: item['title']!,
|
||||||
))
|
deviceData: item,
|
||||||
.toList(),
|
))
|
||||||
),
|
.toList(),
|
||||||
],
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onWillAccept: (data) => data != null,
|
onWillAccept: (data) => data != null,
|
||||||
onAccept: (data) async {
|
onAccept: (data) async {
|
||||||
|
final uniqueCustomId = const Uuid().v4();
|
||||||
|
data['uniqueCustomId'] = uniqueCustomId;
|
||||||
final result =
|
final result =
|
||||||
await DeviceDialogHelper.showDeviceDialog(context, data);
|
await DeviceDialogHelper.showDeviceDialog(context, data);
|
||||||
// if (result != null) {
|
// if (result != null) {
|
||||||
|
32
pubspec.lock
32
pubspec.lock
@ -57,6 +57,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.18.0"
|
version: "1.18.0"
|
||||||
|
crypto:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: crypto
|
||||||
|
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.6"
|
||||||
cupertino_icons:
|
cupertino_icons:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -137,6 +145,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.0.0"
|
version: "7.0.0"
|
||||||
|
fixnum:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: fixnum
|
||||||
|
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
fl_chart:
|
fl_chart:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -533,6 +549,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.0"
|
version: "1.10.0"
|
||||||
|
sprintf:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sprintf
|
||||||
|
sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.0"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -589,6 +613,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.2"
|
version: "1.3.2"
|
||||||
|
uuid:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: uuid
|
||||||
|
sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.5.1"
|
||||||
vector_graphics:
|
vector_graphics:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -51,6 +51,7 @@ dependencies:
|
|||||||
flutter_dotenv: ^5.1.0
|
flutter_dotenv: ^5.1.0
|
||||||
fl_chart: ^0.69.0
|
fl_chart: ^0.69.0
|
||||||
time_picker_spinner: ^1.0.0
|
time_picker_spinner: ^1.0.0
|
||||||
|
uuid: ^4.4.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Reference in New Issue
Block a user