implemented EquipmentProfileEditScreen

This commit is contained in:
Vadim 2024-11-06 14:16:24 +01:00
parent 5ddaed8dfb
commit 1d0d901218
12 changed files with 523 additions and 128 deletions

View file

@ -160,5 +160,7 @@
"filmFormulaExponential": "T=t^Rf",
"filmFormulaExponentialRf": "Rf",
"filmFormulaExponentialRfPlaceholder": "1.3",
"name": "Name"
"name": "Name",
"addEquipmentProfileTitle": "Add equipment profile",
"editEquipmentProfileTitle": "Edit equipment profile"
}

View file

@ -0,0 +1,160 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:lightmeter/providers/equipment_profile_provider.dart';
import 'package:lightmeter/screens/equipment_profile_edit/event_equipment_profile_edit.dart';
import 'package:lightmeter/screens/equipment_profile_edit/state_equipment_profile_edit.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
import 'package:uuid/uuid.dart';
class EquipmentProfileEditBloc extends Bloc<EquipmentProfileEditEvent, EquipmentProfileEditState> {
static const EquipmentProfile _defaultProfile = EquipmentProfile(
id: '',
name: '',
apertureValues: ApertureValue.values,
ndValues: NdValue.values,
shutterSpeedValues: ShutterSpeedValue.values,
isoValues: IsoValue.values,
);
final EquipmentProfileProviderState profilesProvider;
final EquipmentProfile _originalEquipmentProfile;
EquipmentProfile _newEquipmentProfile;
final bool _isEdit;
factory EquipmentProfileEditBloc(
EquipmentProfileProviderState profilesProvider, {
required EquipmentProfile? profile,
required bool isEdit,
}) =>
profile != null
? EquipmentProfileEditBloc._(
profilesProvider,
profile,
isEdit,
)
: EquipmentProfileEditBloc._(
profilesProvider,
_defaultProfile,
isEdit,
);
EquipmentProfileEditBloc._(
this.profilesProvider,
EquipmentProfile profile,
this._isEdit,
) : _originalEquipmentProfile = profile,
_newEquipmentProfile = profile,
super(
EquipmentProfileEditState(
name: profile.name,
apertureValues: profile.apertureValues,
shutterSpeedValues: profile.shutterSpeedValues,
isoValues: profile.isoValues,
ndValues: profile.ndValues,
lensZoom: profile.lensZoom,
canSave: false,
),
) {
on<EquipmentProfileEditEvent>(
(event, emit) async {
switch (event) {
case final EquipmentProfileNameChangedEvent e:
await _onNameChanged(e, emit);
case final EquipmentProfileApertureValuesChangedEvent e:
await _onApertureValuesChanged(e, emit);
case final EquipmentProfileShutterSpeedValuesChangedEvent e:
await _onShutterSpeedValuesChanged(e, emit);
case final EquipmentProfileIsoValuesChangedEvent e:
await _onIsoValuesChanged(e, emit);
case final EquipmentProfileNdValuesChangedEvent e:
await _onNdValuesChanged(e, emit);
case final EquipmentProfileLensZoomChangedEvent e:
await _onLensZoomChanged(e, emit);
case EquipmentProfileSaveEvent():
await _onSave(event, emit);
case EquipmentProfileDeleteEvent():
await _onDelete(event, emit);
}
},
);
}
Future<void> _onNameChanged(EquipmentProfileNameChangedEvent event, Emitter emit) async {
_newEquipmentProfile = _newEquipmentProfile.copyWith(name: event.name);
emit(
state.copyWith(
name: event.name,
canSave: _canSave(event.name, state.lensZoom),
),
);
}
Future<void> _onApertureValuesChanged(EquipmentProfileApertureValuesChangedEvent event, Emitter emit) async {
_newEquipmentProfile = _newEquipmentProfile.copyWith(apertureValues: event.apertureValues);
emit(state.copyWith(apertureValues: event.apertureValues));
}
Future<void> _onShutterSpeedValuesChanged(EquipmentProfileShutterSpeedValuesChangedEvent event, Emitter emit) async {
_newEquipmentProfile = _newEquipmentProfile.copyWith(shutterSpeedValues: event.shutterSpeedValues);
emit(state.copyWith(shutterSpeedValues: event.shutterSpeedValues));
}
Future<void> _onIsoValuesChanged(EquipmentProfileIsoValuesChangedEvent event, Emitter emit) async {
_newEquipmentProfile = _newEquipmentProfile.copyWith(isoValues: event.isoValues);
emit(state.copyWith(isoValues: event.isoValues));
}
Future<void> _onNdValuesChanged(EquipmentProfileNdValuesChangedEvent event, Emitter emit) async {
_newEquipmentProfile = _newEquipmentProfile.copyWith(ndValues: event.ndValues);
emit(state.copyWith(ndValues: event.ndValues));
}
Future<void> _onLensZoomChanged(EquipmentProfileLensZoomChangedEvent event, Emitter emit) async {
_newEquipmentProfile = _newEquipmentProfile.copyWith(lensZoom: event.lensZoom);
emit(
state.copyWith(
lensZoom: event.lensZoom,
canSave: _canSave(state.name, event.lensZoom),
),
);
}
Future<void> _onSave(EquipmentProfileSaveEvent _, Emitter emit) async {
emit(state.copyWith(isLoading: true));
if (_isEdit) {
await profilesProvider.addProfile(
EquipmentProfile(
id: const Uuid().v1(),
name: state.name,
apertureValues: state.apertureValues,
ndValues: state.ndValues,
shutterSpeedValues: state.shutterSpeedValues,
isoValues: state.isoValues,
lensZoom: state.lensZoom,
),
);
} else {
await profilesProvider.updateProfile(
EquipmentProfile(
id: _originalEquipmentProfile.id,
name: state.name,
apertureValues: state.apertureValues,
ndValues: state.ndValues,
shutterSpeedValues: state.shutterSpeedValues,
isoValues: state.isoValues,
lensZoom: state.lensZoom,
),
);
}
emit(state.copyWith(isLoading: false));
}
Future<void> _onDelete(EquipmentProfileDeleteEvent _, Emitter emit) async {
emit(state.copyWith(isLoading: true));
await profilesProvider.deleteProfile(_newEquipmentProfile);
emit(state.copyWith(isLoading: false));
}
bool _canSave(String name, double? exponent) {
return name.isNotEmpty && exponent != null && _newEquipmentProfile != _originalEquipmentProfile;
}
}

View file

@ -0,0 +1,49 @@
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
sealed class EquipmentProfileEditEvent {
const EquipmentProfileEditEvent();
}
class EquipmentProfileNameChangedEvent extends EquipmentProfileEditEvent {
final String name;
const EquipmentProfileNameChangedEvent(this.name);
}
class EquipmentProfileIsoValuesChangedEvent extends EquipmentProfileEditEvent {
final List<IsoValue> isoValues;
const EquipmentProfileIsoValuesChangedEvent(this.isoValues);
}
class EquipmentProfileNdValuesChangedEvent extends EquipmentProfileEditEvent {
final List<NdValue> ndValues;
const EquipmentProfileNdValuesChangedEvent(this.ndValues);
}
class EquipmentProfileApertureValuesChangedEvent extends EquipmentProfileEditEvent {
final List<ApertureValue> apertureValues;
const EquipmentProfileApertureValuesChangedEvent(this.apertureValues);
}
class EquipmentProfileShutterSpeedValuesChangedEvent extends EquipmentProfileEditEvent {
final List<ShutterSpeedValue> shutterSpeedValues;
const EquipmentProfileShutterSpeedValuesChangedEvent(this.shutterSpeedValues);
}
class EquipmentProfileLensZoomChangedEvent extends EquipmentProfileEditEvent {
final double lensZoom;
const EquipmentProfileLensZoomChangedEvent(this.lensZoom);
}
class EquipmentProfileSaveEvent extends EquipmentProfileEditEvent {
const EquipmentProfileSaveEvent();
}
class EquipmentProfileDeleteEvent extends EquipmentProfileEditEvent {
const EquipmentProfileDeleteEvent();
}

View file

@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:lightmeter/providers/equipment_profile_provider.dart';
import 'package:lightmeter/screens/equipment_profile_edit/bloc_equipment_profile_edit.dart';
import 'package:lightmeter/screens/equipment_profile_edit/screen_equipment_profile_edit.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
class EquipmentProfileEditArgs {
final EquipmentProfile? profile;
const EquipmentProfileEditArgs({this.profile});
}
class EquipmentProfileEditFlow extends StatelessWidget {
final EquipmentProfileEditArgs args;
const EquipmentProfileEditFlow({required this.args, super.key});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => EquipmentProfileEditBloc(
EquipmentProfileProvider.of(context),
profile: args.profile,
isEdit: args.profile != null,
),
child: EquipmentProfileEditScreen(isEdit: args.profile != null),
);
}
}

View file

@ -0,0 +1,233 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:lightmeter/generated/l10n.dart';
import 'package:lightmeter/res/dimens.dart';
import 'package:lightmeter/screens/equipment_profile_edit/bloc_equipment_profile_edit.dart';
import 'package:lightmeter/screens/equipment_profile_edit/components/filter_list_tile/widget_list_tile_filter.dart';
import 'package:lightmeter/screens/equipment_profile_edit/components/range_picker_list_tile/widget_list_tile_range_picker.dart';
import 'package:lightmeter/screens/equipment_profile_edit/components/slider_picker_list_tile/widget_list_tile_slider_picker.dart';
import 'package:lightmeter/screens/equipment_profile_edit/event_equipment_profile_edit.dart';
import 'package:lightmeter/screens/equipment_profile_edit/state_equipment_profile_edit.dart';
import 'package:lightmeter/screens/shared/sliver_screen/screen_sliver.dart';
import 'package:lightmeter/screens/shared/text_field/widget_text_field.dart';
import 'package:lightmeter/utils/double_to_zoom.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
class EquipmentProfileEditScreen extends StatefulWidget {
final bool isEdit;
const EquipmentProfileEditScreen({
required this.isEdit,
super.key,
});
@override
State<EquipmentProfileEditScreen> createState() => _EquipmentProfileEditScreenState();
}
class _EquipmentProfileEditScreenState extends State<EquipmentProfileEditScreen> {
@override
Widget build(BuildContext context) {
return BlocConsumer<EquipmentProfileEditBloc, EquipmentProfileEditState>(
listenWhen: (previous, current) => previous.isLoading != current.isLoading,
listener: (context, state) {
if (state.isLoading) {
FocusScope.of(context).unfocus();
} else {
Navigator.of(context).pop();
}
},
buildWhen: (previous, current) => previous.isLoading != current.isLoading,
builder: (context, state) => IgnorePointer(
ignoring: state.isLoading,
child: SliverScreen(
title: Text(widget.isEdit ? S.of(context).editEquipmentProfileTitle : S.of(context).addEquipmentProfileTitle),
appBarActions: [
BlocBuilder<EquipmentProfileEditBloc, EquipmentProfileEditState>(
buildWhen: (previous, current) => previous.canSave != current.canSave,
builder: (context, state) => IconButton(
onPressed: state.canSave
? () {
context.read<EquipmentProfileEditBloc>().add(const EquipmentProfileSaveEvent());
}
: null,
icon: const Icon(Icons.save),
),
),
if (widget.isEdit)
IconButton(
onPressed: () {
context.read<EquipmentProfileEditBloc>().add(const EquipmentProfileDeleteEvent());
},
icon: const Icon(Icons.delete),
),
],
slivers: [
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.fromLTRB(
Dimens.paddingM,
0,
Dimens.paddingM,
Dimens.paddingM,
),
child: Card(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: Dimens.paddingM),
child: Opacity(
opacity: state.isLoading ? Dimens.disabledOpacity : Dimens.enabledOpacity,
child: const Column(
children: [
_NameFieldBuilder(),
_IsoValuesListTileBuilder(),
_NdValuesListTileBuilder(),
_ApertureValuesListTileBuilder(),
_ShutterSpeedValuesListTileBuilder(),
_LensZoomListTileBuilder(),
],
),
),
),
),
),
),
SliverToBoxAdapter(child: SizedBox(height: MediaQuery.paddingOf(context).bottom)),
],
),
),
);
}
}
class _NameFieldBuilder extends StatelessWidget {
const _NameFieldBuilder();
@override
Widget build(BuildContext context) {
return BlocBuilder<EquipmentProfileEditBloc, EquipmentProfileEditState>(
builder: (context, state) => Padding(
padding: const EdgeInsets.only(
left: Dimens.paddingM,
top: Dimens.paddingS / 2,
right: Dimens.paddingL,
bottom: Dimens.paddingS / 2,
),
child: LightmeterTextField(
initialValue: state.name,
autofocus: true,
maxLength: 48,
hintText: S.of(context).name,
style: Theme.of(context).listTileTheme.titleTextStyle,
leading: const Icon(Icons.edit_outlined),
onChanged: (value) {
context.read<EquipmentProfileEditBloc>().add(EquipmentProfileNameChangedEvent(value));
},
),
),
);
}
}
class _IsoValuesListTileBuilder extends StatelessWidget {
const _IsoValuesListTileBuilder();
@override
Widget build(BuildContext context) {
return BlocBuilder<EquipmentProfileEditBloc, EquipmentProfileEditState>(
builder: (context, state) => FilterListTile<IsoValue>(
icon: Icons.iso_outlined,
title: S.of(context).isoValues,
description: S.of(context).isoValuesFilterDescription,
values: IsoValue.values,
selectedValues: state.isoValues,
onChanged: (value) {
context.read<EquipmentProfileEditBloc>().add(EquipmentProfileIsoValuesChangedEvent(value));
},
),
);
}
}
class _NdValuesListTileBuilder extends StatelessWidget {
const _NdValuesListTileBuilder();
@override
Widget build(BuildContext context) {
return BlocBuilder<EquipmentProfileEditBloc, EquipmentProfileEditState>(
builder: (context, state) => FilterListTile<NdValue>(
icon: Icons.filter_b_and_w_outlined,
title: S.of(context).ndFilters,
description: S.of(context).ndFiltersFilterDescription,
values: NdValue.values,
selectedValues: state.ndValues,
onChanged: (value) {
context.read<EquipmentProfileEditBloc>().add(EquipmentProfileNdValuesChangedEvent(value));
},
),
);
}
}
class _ApertureValuesListTileBuilder extends StatelessWidget {
const _ApertureValuesListTileBuilder();
@override
Widget build(BuildContext context) {
return BlocBuilder<EquipmentProfileEditBloc, EquipmentProfileEditState>(
builder: (context, state) => RangePickerListTile<ApertureValue>(
icon: Icons.camera_outlined,
title: S.of(context).apertureValues,
description: S.of(context).apertureValuesFilterDescription,
values: ApertureValue.values,
selectedValues: state.apertureValues,
onChanged: (value) {
context.read<EquipmentProfileEditBloc>().add(EquipmentProfileApertureValuesChangedEvent(value));
},
),
);
}
}
class _ShutterSpeedValuesListTileBuilder extends StatelessWidget {
const _ShutterSpeedValuesListTileBuilder();
@override
Widget build(BuildContext context) {
return BlocBuilder<EquipmentProfileEditBloc, EquipmentProfileEditState>(
builder: (context, state) => RangePickerListTile<ShutterSpeedValue>(
icon: Icons.shutter_speed_outlined,
title: S.of(context).shutterSpeedValues,
description: S.of(context).shutterSpeedValuesFilterDescription,
values: ShutterSpeedValue.values,
selectedValues: state.shutterSpeedValues,
trailingAdapter: (context, value) =>
value.value == 1 ? S.of(context).shutterSpeedManualShort : value.toString(),
dialogValueAdapter: (context, value) => value.value == 1 ? S.of(context).shutterSpeedManual : value.toString(),
onChanged: (value) {
context.read<EquipmentProfileEditBloc>().add(EquipmentProfileShutterSpeedValuesChangedEvent(value));
},
),
);
}
}
class _LensZoomListTileBuilder extends StatelessWidget {
const _LensZoomListTileBuilder();
@override
Widget build(BuildContext context) {
return BlocBuilder<EquipmentProfileEditBloc, EquipmentProfileEditState>(
builder: (context, state) => SliderPickerListTile(
icon: Icons.zoom_in_outlined,
title: S.of(context).lensZoom,
description: S.of(context).lensZoomDescription,
value: state.lensZoom,
range: const RangeValues(1, 7),
valueAdapter: (_, value) => value.toZoom(),
onChanged: (value) {
context.read<EquipmentProfileEditBloc>().add(EquipmentProfileLensZoomChangedEvent(value));
},
),
);
}
}

View file

@ -0,0 +1,44 @@
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
class EquipmentProfileEditState {
final String name;
final List<ApertureValue> apertureValues;
final List<NdValue> ndValues;
final List<ShutterSpeedValue> shutterSpeedValues;
final List<IsoValue> isoValues;
final double lensZoom;
final bool canSave;
final bool isLoading;
const EquipmentProfileEditState({
required this.name,
required this.apertureValues,
required this.ndValues,
required this.shutterSpeedValues,
required this.isoValues,
required this.lensZoom,
required this.canSave,
this.isLoading = false,
});
EquipmentProfileEditState copyWith({
String? name,
List<ApertureValue>? apertureValues,
List<NdValue>? ndValues,
List<ShutterSpeedValue>? shutterSpeedValues,
List<IsoValue>? isoValues,
double? lensZoom,
bool? canSave,
bool? isLoading,
}) =>
EquipmentProfileEditState(
name: name ?? this.name,
apertureValues: apertureValues ?? this.apertureValues,
ndValues: ndValues ?? this.ndValues,
shutterSpeedValues: shutterSpeedValues ?? this.shutterSpeedValues,
isoValues: isoValues ?? this.isoValues,
lensZoom: lensZoom ?? this.lensZoom,
canSave: canSave ?? this.canSave,
isLoading: isLoading ?? this.isLoading,
);
}

View file

@ -4,11 +4,6 @@ import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:lightmeter/generated/l10n.dart';
import 'package:lightmeter/res/dimens.dart';
import 'package:lightmeter/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_container/components/filter_list_tile/widget_list_tile_filter.dart';
import 'package:lightmeter/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_container/components/range_picker_list_tile/widget_list_tile_range_picker.dart';
import 'package:lightmeter/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_container/components/slider_picker_list_tile/widget_list_tile_slider_picker.dart';
import 'package:lightmeter/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_name_dialog/widget_dialog_equipment_profile_name.dart';
import 'package:lightmeter/utils/double_to_zoom.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
class EquipmentProfileContainer extends StatefulWidget {
@ -130,17 +125,7 @@ class EquipmentProfileContainerState extends State<EquipmentProfileContainer> wi
);
}
void _showNameDialog() {
showDialog<String>(
context: context,
builder: (_) => EquipmentProfileNameDialog(initialValue: _equipmentData.name),
).then((value) {
if (value != null) {
_equipmentData = _equipmentData.copyWith(name: value);
widget.onUpdate(_equipmentData);
}
});
}
void _showNameDialog() {}
void expand() {
widget.onExpand();
@ -238,51 +223,6 @@ class _AnimatedEquipmentListTiles extends AnimatedWidget {
opacity: _progress.value,
child: Column(
children: [
FilterListTile<IsoValue>(
icon: Icons.iso_outlined,
title: S.of(context).isoValues,
description: S.of(context).isoValuesFilterDescription,
values: IsoValue.values,
selectedValues: equipmentData.isoValues,
onChanged: onIsoValuesSelecred,
),
FilterListTile<NdValue>(
icon: Icons.filter_b_and_w_outlined,
title: S.of(context).ndFilters,
description: S.of(context).ndFiltersFilterDescription,
values: NdValue.values,
selectedValues: equipmentData.ndValues,
onChanged: onNdValuesSelected,
),
RangePickerListTile<ApertureValue>(
icon: Icons.camera_outlined,
title: S.of(context).apertureValues,
description: S.of(context).apertureValuesFilterDescription,
values: ApertureValue.values,
selectedValues: equipmentData.apertureValues,
onChanged: onApertureValuesSelected,
),
RangePickerListTile<ShutterSpeedValue>(
icon: Icons.shutter_speed_outlined,
title: S.of(context).shutterSpeedValues,
description: S.of(context).shutterSpeedValuesFilterDescription,
values: ShutterSpeedValue.values,
selectedValues: equipmentData.shutterSpeedValues,
onChanged: onShutterSpeedValuesSelected,
trailingAdapter: (context, value) =>
value.value == 1 ? S.of(context).shutterSpeedManualShort : value.toString(),
dialogValueAdapter: (context, value) =>
value.value == 1 ? S.of(context).shutterSpeedManual : value.toString(),
),
SliderPickerListTile(
icon: Icons.zoom_in_outlined,
title: S.of(context).lensZoom,
description: S.of(context).lensZoomDescription,
value: equipmentData.lensZoom,
range: const RangeValues(1, 7),
onChanged: onLensZoomChanged,
valueAdapter: (_, value) => value.toZoom(),
),
ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: Dimens.paddingM),
trailing: Row(

View file

@ -1,49 +0,0 @@
import 'package:flutter/material.dart';
import 'package:lightmeter/generated/l10n.dart';
import 'package:lightmeter/res/dimens.dart';
class EquipmentProfileNameDialog extends StatefulWidget {
final String initialValue;
const EquipmentProfileNameDialog({this.initialValue = '', super.key});
@override
State<EquipmentProfileNameDialog> createState() => _EquipmentProfileNameDialogState();
}
class _EquipmentProfileNameDialogState extends State<EquipmentProfileNameDialog> {
late final _nameController = TextEditingController(text: widget.initialValue);
@override
void dispose() {
_nameController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AlertDialog(
icon: const Icon(Icons.edit_outlined),
titlePadding: Dimens.dialogIconTitlePadding,
title: Text(S.of(context).equipmentProfileName),
content: TextField(
autofocus: true,
controller: _nameController,
decoration: InputDecoration(hintText: S.of(context).equipmentProfileNameHint),
),
actions: [
TextButton(
onPressed: Navigator.of(context).pop,
child: Text(S.of(context).cancel),
),
ValueListenableBuilder(
valueListenable: _nameController,
builder: (_, value, __) => TextButton(
onPressed: value.text.isNotEmpty ? () => Navigator.of(context).pop(value.text) : null,
child: Text(S.of(context).save),
),
),
],
);
}
}

View file

@ -3,7 +3,6 @@ import 'package:lightmeter/generated/l10n.dart';
import 'package:lightmeter/providers/equipment_profile_provider.dart';
import 'package:lightmeter/res/dimens.dart';
import 'package:lightmeter/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_container/widget_container_equipment_profile.dart';
import 'package:lightmeter/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_name_dialog/widget_dialog_equipment_profile_name.dart';
import 'package:lightmeter/screens/shared/sliver_placeholder/widget_sliver_placeholder.dart';
import 'package:lightmeter/screens/shared/sliver_screen/screen_sliver.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
@ -73,24 +72,11 @@ class _EquipmentProfilesScreenState extends State<EquipmentProfilesScreen> {
);
}
void _addProfile([EquipmentProfile? copyFrom]) {
showDialog<String>(
context: context,
builder: (_) => const EquipmentProfileNameDialog(),
).then((name) {
if (name != null) {
//EquipmentProfileProvider.of(context).addProfile(name, copyFrom);
}
});
}
void _addProfile([EquipmentProfile? copyFrom]) {}
void _updateProfileAt(EquipmentProfile data) {
EquipmentProfileProvider.of(context).updateProfile(data);
}
void _updateProfileAt(EquipmentProfile data) {}
void _removeProfileAt(EquipmentProfile data) {
EquipmentProfileProvider.of(context).deleteProfile(data);
}
void _removeProfileAt(EquipmentProfile data) {}
void _keepExpandedAt(int index) {
keysMap.values.toList().getRange(0, index).forEach((element) {