add/edit pinhole profiles

This commit is contained in:
Vadim 2025-09-03 20:41:21 +02:00
parent 3aa0014b6a
commit 76a6754a3b
12 changed files with 338 additions and 254 deletions

View file

@ -34,6 +34,8 @@
"calibrationMessage": "Die Messgenauigkeit hängt von der Gerätehardware ab. Testen Sie die App und kalibrieren Sie EV-Werte für beste Ergebnisse", "calibrationMessage": "Die Messgenauigkeit hängt von der Gerätehardware ab. Testen Sie die App und kalibrieren Sie EV-Werte für beste Ergebnisse",
"calibrationMessageCameraOnly": "Die Messgenauigkeit hängt von der Kamera ab. Testen Sie die App und kalibrieren Sie EV-Werte für beste Ergebnisse", "calibrationMessageCameraOnly": "Die Messgenauigkeit hängt von der Kamera ab. Testen Sie die App und kalibrieren Sie EV-Werte für beste Ergebnisse",
"camera": "Kamera", "camera": "Kamera",
"pinholeCamera": "Lochkamera",
"equipmentProfileType": "Ausrüstungsprofiltyp",
"lightSensor": "Lichtsensor", "lightSensor": "Lichtsensor",
"showEv100": "EV\u2081\u2080\u2080 anzeigen", "showEv100": "EV\u2081\u2080\u2080 anzeigen",
"meteringScreenLayout": "Messansicht Layout", "meteringScreenLayout": "Messansicht Layout",

View file

@ -34,6 +34,8 @@
"calibrationMessage": "Measurement accuracy depends on your device's hardware. Test the app and calibrate EV values for optimal results", "calibrationMessage": "Measurement accuracy depends on your device's hardware. Test the app and calibrate EV values for optimal results",
"calibrationMessageCameraOnly": "Measurement accuracy depends on your device's camera. Test the app and calibrate EV values for optimal results", "calibrationMessageCameraOnly": "Measurement accuracy depends on your device's camera. Test the app and calibrate EV values for optimal results",
"camera": "Camera", "camera": "Camera",
"pinholeCamera": "Pinhole Camera",
"equipmentProfileType": "Equipment profile type",
"lightSensor": "Light sensor", "lightSensor": "Light sensor",
"showEv100": "Show EV\u2081\u2080\u2080", "showEv100": "Show EV\u2081\u2080\u2080",
"meteringScreenLayout": "Metering screen layout", "meteringScreenLayout": "Metering screen layout",

View file

@ -34,6 +34,8 @@
"calibrationMessage": "La précision dépend du matériel de l'appareil. Testez l'app et calibrez les valeurs EV pour de meilleurs résultats", "calibrationMessage": "La précision dépend du matériel de l'appareil. Testez l'app et calibrez les valeurs EV pour de meilleurs résultats",
"calibrationMessageCameraOnly": "La précision dépend de la caméra de l'appareil. Testez l'app et calibrez les valeurs EV pour de meilleurs résultats", "calibrationMessageCameraOnly": "La précision dépend de la caméra de l'appareil. Testez l'app et calibrez les valeurs EV pour de meilleurs résultats",
"camera": "Caméra", "camera": "Caméra",
"pinholeCamera": "Sténopé",
"equipmentProfileType": "Type de profil d'équipement",
"lightSensor": "Capteur de lumière", "lightSensor": "Capteur de lumière",
"showEv100": "Montrer EV\u2081\u2080\u2080", "showEv100": "Montrer EV\u2081\u2080\u2080",
"meteringScreenLayout": "Disposition de l'écran de mesure", "meteringScreenLayout": "Disposition de l'écran de mesure",

View file

@ -34,6 +34,8 @@
"calibrationMessage": "Dokładność pomiaru zależy od sprzętu urządzenia. Przetestuj aplikację i skalibruj wartości EV dla optymalnych wyników", "calibrationMessage": "Dokładność pomiaru zależy od sprzętu urządzenia. Przetestuj aplikację i skalibruj wartości EV dla optymalnych wyników",
"calibrationMessageCameraOnly": "Dokładność pomiaru zależy od kamery urządzenia. Przetestuj aplikację i skalibruj wartości EV dla optymalnych wyników", "calibrationMessageCameraOnly": "Dokładność pomiaru zależy od kamery urządzenia. Przetestuj aplikację i skalibruj wartości EV dla optymalnych wyników",
"camera": "Kamera", "camera": "Kamera",
"pinholeCamera": "Kamera otworkowa",
"equipmentProfileType": "Typ profilu sprzętu",
"lightSensor": "Czujnik światła", "lightSensor": "Czujnik światła",
"showEv100": "Pokaż EV\u2081\u2080\u2080", "showEv100": "Pokaż EV\u2081\u2080\u2080",
"meteringScreenLayout": "Układ ekranu pomiaru", "meteringScreenLayout": "Układ ekranu pomiaru",

View file

@ -34,6 +34,8 @@
"calibrationMessage": "Точность измерений данного приложения полностью зависит от точности камеры и датчика освещенности вашего устройства. Поэтому рекомендуется самостоятельно подобрать калибровочные значения, которые дадут желаемый результат измерений.", "calibrationMessage": "Точность измерений данного приложения полностью зависит от точности камеры и датчика освещенности вашего устройства. Поэтому рекомендуется самостоятельно подобрать калибровочные значения, которые дадут желаемый результат измерений.",
"calibrationMessageCameraOnly": "Точность измерений данного приложения полностью зависит от точности камеры вашего устройства. Поэтому рекомендуется самостоятельно подобрать калибровочное значение, которое даст желаемый результат измерений.", "calibrationMessageCameraOnly": "Точность измерений данного приложения полностью зависит от точности камеры вашего устройства. Поэтому рекомендуется самостоятельно подобрать калибровочное значение, которое даст желаемый результат измерений.",
"camera": "Камера", "camera": "Камера",
"pinholeCamera": "Пинхол-камера",
"equipmentProfileType": "Тип профиля оборудования",
"lightSensor": "Датчик освещённости", "lightSensor": "Датчик освещённости",
"showEv100": "Показывать EV\u2081\u2080\u2080", "showEv100": "Показывать EV\u2081\u2080\u2080",
"meteringScreenLayout": "Элементы главного экрана", "meteringScreenLayout": "Элементы главного экрана",

View file

@ -34,6 +34,8 @@
"calibrationMessage": "测量精度取决于设备硬件。请测试并校准 EV 值以获得最佳结果。", "calibrationMessage": "测量精度取决于设备硬件。请测试并校准 EV 值以获得最佳结果。",
"calibrationMessageCameraOnly": "测量精度取决于设备摄像头。请测试并校准 EV 值以获得最佳结果。", "calibrationMessageCameraOnly": "测量精度取决于设备摄像头。请测试并校准 EV 值以获得最佳结果。",
"camera": "相机", "camera": "相机",
"pinholeCamera": "针孔相机",
"equipmentProfileType": "设备配置类型",
"lightSensor": "光线传感器", "lightSensor": "光线传感器",
"showEv100": "显示 EV\u2081\u2080\u2080", "showEv100": "显示 EV\u2081\u2080\u2080",
"meteringScreenLayout": "布局", "meteringScreenLayout": "布局",

View file

@ -1,3 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:lightmeter/providers/equipment_profile_provider.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/event_equipment_profile_edit.dart';
@ -5,49 +6,88 @@ import 'package:lightmeter/screens/equipment_profile_edit/state_equipment_profil
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
class EquipmentProfileEditBloc extends Bloc<EquipmentProfileEditEvent, EquipmentProfileEditState> { sealed class IEquipmentProfileEditBloc<T extends IEquipmentProfile>
extends Bloc<IEquipmentProfileEditEvent<T>, EquipmentProfileEditState<T>> {
@protected
final EquipmentProfilesProviderState profilesProvider; final EquipmentProfilesProviderState profilesProvider;
final EquipmentProfile _originalEquipmentProfile; @protected
EquipmentProfile _newEquipmentProfile; final T originalEquipmentProfile;
final bool _isEdit; @protected
final bool isEdit;
factory EquipmentProfileEditBloc( IEquipmentProfileEditBloc(
EquipmentProfilesProviderState profilesProvider, { this.profilesProvider, {
required EquipmentProfile? profile, required T profile,
required bool isEdit, required this.isEdit,
}) => }) : originalEquipmentProfile = profile,
profile != null
? EquipmentProfileEditBloc._(
profilesProvider,
profile,
isEdit,
)
: EquipmentProfileEditBloc._(
profilesProvider,
EquipmentProfilesProvider.defaultProfile,
isEdit,
);
EquipmentProfileEditBloc._(
this.profilesProvider,
EquipmentProfile profile,
this._isEdit,
) : _originalEquipmentProfile = profile,
_newEquipmentProfile = profile,
super( super(
EquipmentProfileEditState( EquipmentProfileEditState<T>(
name: profile.name, profile: profile,
apertureValues: profile.apertureValues,
shutterSpeedValues: profile.shutterSpeedValues,
isoValues: profile.isoValues,
ndValues: profile.ndValues,
lensZoom: profile.lensZoom,
exposureOffset: profile.exposureOffset,
canSave: false, canSave: false,
), ),
) { ) {
on<EquipmentProfileEditEvent>( on<IEquipmentProfileEditEvent<T>>(mapEventToState);
(event, emit) async { }
@protected
@mustCallSuper
Future<void> mapEventToState(IEquipmentProfileEditEvent<T> event, Emitter emit) async {
switch (event) {
case EquipmentProfileSaveEvent():
await _onSave(event, emit);
case EquipmentProfileCopyEvent():
await _onCopy(event, emit);
case EquipmentProfileDeleteEvent():
await _onDelete(event, emit);
default:
}
}
@protected
Future<T> createProfile(String id);
@protected
void emitProfile(T profile, Emitter emit) {
emit(
state.copyWith(
profile: profile,
canSave: _canSave(profile),
),
);
}
Future<void> _onSave(EquipmentProfileSaveEvent<T> _, Emitter emit) async {
emit(state.copyWith(isLoading: true));
final profileId = isEdit ? originalEquipmentProfile.id : const Uuid().v1();
final newProfile = await createProfile(profileId);
assert(newProfile.id == profileId, 'The new profile id must be the same as the original profile id');
await profilesProvider.addProfile(newProfile);
emit(state.copyWith(isLoading: false));
}
Future<void> _onCopy(EquipmentProfileCopyEvent<T> _, Emitter emit) async {
emit(state.copyWith(isLoading: true));
emit(state.copyWith(isLoading: false, profileToCopy: state.profile));
}
Future<void> _onDelete(EquipmentProfileDeleteEvent<T> _, Emitter emit) async {
emit(state.copyWith(isLoading: true));
await profilesProvider.deleteProfile(originalEquipmentProfile);
emit(state.copyWith(isLoading: false));
}
bool _canSave(T profile) => profile != originalEquipmentProfile;
}
class EquipmentProfileEditBloc extends IEquipmentProfileEditBloc<EquipmentProfile> {
EquipmentProfileEditBloc(
super.profilesProvider, {
required super.profile,
required super.isEdit,
});
@override
Future<void> mapEventToState(IEquipmentProfileEditEvent<EquipmentProfile> event, Emitter emit) async {
switch (event) { switch (event) {
case final EquipmentProfileNameChangedEvent e: case final EquipmentProfileNameChangedEvent e:
await _onNameChanged(e, emit); await _onNameChanged(e, emit);
@ -63,131 +103,102 @@ class EquipmentProfileEditBloc extends Bloc<EquipmentProfileEditEvent, Equipment
await _onLensZoomChanged(e, emit); await _onLensZoomChanged(e, emit);
case final EquipmentProfileExposureOffsetChangedEvent e: case final EquipmentProfileExposureOffsetChangedEvent e:
await _onExposureOffsetChanged(e, emit); await _onExposureOffsetChanged(e, emit);
case EquipmentProfileSaveEvent(): default:
await _onSave(event, emit); return super.mapEventToState(event, emit);
case EquipmentProfileCopyEvent():
await _onCopy(event, emit);
case EquipmentProfileDeleteEvent():
await _onDelete(event, emit);
} }
}, }
@override
Future<EquipmentProfile> createProfile(String id) async {
return EquipmentProfile(
id: id,
name: state.profile.name,
apertureValues: state.profile.apertureValues,
shutterSpeedValues: state.profile.shutterSpeedValues,
isoValues: state.profile.isoValues,
ndValues: state.profile.ndValues,
lensZoom: state.profile.lensZoom,
exposureOffset: state.profile.exposureOffset,
); );
} }
Future<void> _onNameChanged(EquipmentProfileNameChangedEvent event, Emitter emit) async { Future<void> _onNameChanged(EquipmentProfileNameChangedEvent event, Emitter emit) async {
_newEquipmentProfile = _newEquipmentProfile.copyWith(name: event.name); emitProfile(state.profile.copyWith(name: event.name), emit);
emit(
state.copyWith(
name: event.name,
canSave: _canSave(event.name, state.lensZoom),
),
);
} }
Future<void> _onApertureValuesChanged(EquipmentProfileApertureValuesChangedEvent event, Emitter emit) async { Future<void> _onApertureValuesChanged(EquipmentProfileApertureValuesChangedEvent event, Emitter emit) async {
_newEquipmentProfile = _newEquipmentProfile.copyWith(apertureValues: event.apertureValues); emitProfile(state.profile.copyWith(apertureValues: event.apertureValues), emit);
emit(
state.copyWith(
apertureValues: event.apertureValues,
canSave: _canSave(state.name, state.lensZoom),
),
);
} }
Future<void> _onShutterSpeedValuesChanged(EquipmentProfileShutterSpeedValuesChangedEvent event, Emitter emit) async { Future<void> _onShutterSpeedValuesChanged(EquipmentProfileShutterSpeedValuesChangedEvent event, Emitter emit) async {
_newEquipmentProfile = _newEquipmentProfile.copyWith(shutterSpeedValues: event.shutterSpeedValues); emitProfile(state.profile.copyWith(shutterSpeedValues: event.shutterSpeedValues), emit);
emit(
state.copyWith(
shutterSpeedValues: event.shutterSpeedValues,
canSave: _canSave(state.name, state.lensZoom),
),
);
} }
Future<void> _onIsoValuesChanged(EquipmentProfileIsoValuesChangedEvent event, Emitter emit) async { Future<void> _onIsoValuesChanged(EquipmentProfileIsoValuesChangedEvent event, Emitter emit) async {
_newEquipmentProfile = _newEquipmentProfile.copyWith(isoValues: event.isoValues); emitProfile(state.profile.copyWith(isoValues: event.isoValues), emit);
emit(
state.copyWith(
isoValues: event.isoValues,
canSave: _canSave(state.name, state.lensZoom),
),
);
} }
Future<void> _onNdValuesChanged(EquipmentProfileNdValuesChangedEvent event, Emitter emit) async { Future<void> _onNdValuesChanged(EquipmentProfileNdValuesChangedEvent event, Emitter emit) async {
_newEquipmentProfile = _newEquipmentProfile.copyWith(ndValues: event.ndValues); emitProfile(state.profile.copyWith(ndValues: event.ndValues), emit);
emit(
state.copyWith(
ndValues: event.ndValues,
canSave: _canSave(state.name, state.lensZoom),
),
);
} }
Future<void> _onLensZoomChanged(EquipmentProfileLensZoomChangedEvent event, Emitter emit) async { Future<void> _onLensZoomChanged(EquipmentProfileLensZoomChangedEvent event, Emitter emit) async {
_newEquipmentProfile = _newEquipmentProfile.copyWith(lensZoom: event.lensZoom); emitProfile(state.profile.copyWith(lensZoom: event.lensZoom), emit);
emit(
state.copyWith(
lensZoom: event.lensZoom,
canSave: _canSave(state.name, event.lensZoom),
),
);
} }
Future<void> _onExposureOffsetChanged(EquipmentProfileExposureOffsetChangedEvent event, Emitter emit) async { Future<void> _onExposureOffsetChanged(EquipmentProfileExposureOffsetChangedEvent event, Emitter emit) async {
_newEquipmentProfile = _newEquipmentProfile.copyWith(exposureOffset: event.exposureOffset); emitProfile(state.profile.copyWith(exposureOffset: event.exposureOffset), emit);
emit( }
state.copyWith( }
exposureOffset: event.exposureOffset,
canSave: _canSave(state.name, event.exposureOffset), class PinholeEquipmentProfileEditBloc extends IEquipmentProfileEditBloc<PinholeEquipmentProfile> {
), PinholeEquipmentProfileEditBloc(
); super.profilesProvider, {
} required super.profile,
required super.isEdit,
Future<void> _onSave(EquipmentProfileSaveEvent _, Emitter emit) async { });
emit(state.copyWith(isLoading: true));
if (_isEdit) { @override
await profilesProvider.updateProfile( Future<void> mapEventToState(IEquipmentProfileEditEvent<PinholeEquipmentProfile> event, Emitter emit) async {
EquipmentProfile( switch (event) {
id: _originalEquipmentProfile.id, case final EquipmentProfileNameChangedEvent e:
name: state.name, await _onNameChanged(e, emit);
apertureValues: state.apertureValues, case final EquipmentProfileApertureValuesChangedEvent e:
ndValues: state.ndValues, await _onApertureValuesChanged(e, emit);
shutterSpeedValues: state.shutterSpeedValues, case final EquipmentProfileLensZoomChangedEvent e:
isoValues: state.isoValues, await _onLensZoomChanged(e, emit);
lensZoom: state.lensZoom, case final EquipmentProfileExposureOffsetChangedEvent e:
exposureOffset: state.exposureOffset, await _onExposureOffsetChanged(e, emit);
), default:
); return super.mapEventToState(event, emit);
} else { }
await profilesProvider.addProfile( }
EquipmentProfile(
id: const Uuid().v1(), @override
name: state.name, Future<PinholeEquipmentProfile> createProfile(String id) async {
apertureValues: state.apertureValues, return PinholeEquipmentProfile(
ndValues: state.ndValues, id: id,
shutterSpeedValues: state.shutterSpeedValues, name: state.profile.name,
isoValues: state.isoValues, aperture: state.profile.aperture,
lensZoom: state.lensZoom, isoValues: state.profile.isoValues,
exposureOffset: state.exposureOffset, lensZoom: state.profile.lensZoom,
), exposureOffset: state.profile.exposureOffset,
); );
} }
emit(state.copyWith(isLoading: false));
} Future<void> _onNameChanged(EquipmentProfileNameChangedEvent event, Emitter emit) async {
emitProfile(state.profile.copyWith(name: event.name), emit);
Future<void> _onCopy(EquipmentProfileCopyEvent _, Emitter emit) async { }
emit(state.copyWith(isLoading: true));
emit(state.copyWith(isLoading: false, profileToCopy: _originalEquipmentProfile)); Future<void> _onApertureValuesChanged(EquipmentProfileApertureValuesChangedEvent event, Emitter emit) async {
} //emitProfile(state.profile.copyWith(apertureValues: event.apertureValues), emit);
}
Future<void> _onDelete(EquipmentProfileDeleteEvent _, Emitter emit) async {
emit(state.copyWith(isLoading: true)); Future<void> _onLensZoomChanged(EquipmentProfileLensZoomChangedEvent event, Emitter emit) async {
await profilesProvider.deleteProfile(_newEquipmentProfile); emitProfile(state.profile.copyWith(lensZoom: event.lensZoom), emit);
emit(state.copyWith(isLoading: false)); }
}
Future<void> _onExposureOffsetChanged(EquipmentProfileExposureOffsetChangedEvent event, Emitter emit) async {
bool _canSave(String name, double? lensZoom) { emitProfile(state.profile.copyWith(exposureOffset: event.exposureOffset), emit);
return name.isNotEmpty && _newEquipmentProfile != _originalEquipmentProfile;
} }
} }

View file

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

View file

@ -7,11 +7,14 @@ import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
enum EquipmentProfileEditType { add, edit } enum EquipmentProfileEditType { add, edit }
class EquipmentProfileEditArgs { class EquipmentProfileEditArgs<T extends IEquipmentProfile> {
final EquipmentProfileEditType editType; final EquipmentProfileEditType editType;
final EquipmentProfile? profile; final T profile;
const EquipmentProfileEditArgs({required this.editType, this.profile}); const EquipmentProfileEditArgs({
required this.editType,
required this.profile,
});
} }
class EquipmentProfileEditFlow extends StatelessWidget { class EquipmentProfileEditFlow extends StatelessWidget {
@ -25,13 +28,50 @@ class EquipmentProfileEditFlow extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( switch (args.profile) {
case final EquipmentProfile profile:
return _IEquipmentProfileBlocProvider<EquipmentProfile, EquipmentProfileEditBloc>(
create: (_) => EquipmentProfileEditBloc( create: (_) => EquipmentProfileEditBloc(
EquipmentProfilesProvider.of(context), EquipmentProfilesProvider.of(context),
profile: args.profile, profile: profile,
isEdit: _isEdit, isEdit: _isEdit,
), ),
child: EquipmentProfileEditScreen(isEdit: _isEdit), isEdit: _isEdit,
);
case final PinholeEquipmentProfile profile:
return _IEquipmentProfileBlocProvider<PinholeEquipmentProfile, PinholeEquipmentProfileEditBloc>(
create: (_) => PinholeEquipmentProfileEditBloc(
EquipmentProfilesProvider.of(context),
profile: profile,
isEdit: _isEdit,
),
isEdit: _isEdit,
);
}
}
}
class _IEquipmentProfileBlocProvider<T extends IEquipmentProfile, V extends IEquipmentProfileEditBloc<T>>
extends StatelessWidget {
final V Function(BuildContext context) create;
final bool isEdit;
const _IEquipmentProfileBlocProvider({
required this.create,
required this.isEdit,
super.key,
});
@override
Widget build(BuildContext context) {
return BlocProvider<IEquipmentProfileEditBloc<T>>(
create: create,
child: Builder(
builder: (context) => BlocProvider<V>.value(
value: context.read<IEquipmentProfileEditBloc<T>>() as V,
child: EquipmentProfileEditScreen<T>(isEdit: isEdit),
),
),
); );
} }
} }

View file

@ -17,7 +17,7 @@ import 'package:lightmeter/utils/double_to_zoom.dart';
import 'package:lightmeter/utils/to_string_signed.dart'; import 'package:lightmeter/utils/to_string_signed.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
class EquipmentProfileEditScreen extends StatefulWidget { class EquipmentProfileEditScreen<T extends IEquipmentProfile> extends StatefulWidget {
final bool isEdit; final bool isEdit;
const EquipmentProfileEditScreen({ const EquipmentProfileEditScreen({
@ -26,13 +26,13 @@ class EquipmentProfileEditScreen extends StatefulWidget {
}); });
@override @override
State<EquipmentProfileEditScreen> createState() => _EquipmentProfileEditScreenState(); State<EquipmentProfileEditScreen<T>> createState() => _EquipmentProfileEditScreenState<T>();
} }
class _EquipmentProfileEditScreenState extends State<EquipmentProfileEditScreen> { class _EquipmentProfileEditScreenState<T extends IEquipmentProfile> extends State<EquipmentProfileEditScreen<T>> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocConsumer<EquipmentProfileEditBloc, EquipmentProfileEditState>( return BlocConsumer<IEquipmentProfileEditBloc<T>, EquipmentProfileEditState<T>>(
listenWhen: (previous, current) => previous.isLoading != current.isLoading, listenWhen: (previous, current) => previous.isLoading != current.isLoading,
listener: (context, state) { listener: (context, state) {
if (state.isLoading) { if (state.isLoading) {
@ -41,9 +41,9 @@ class _EquipmentProfileEditScreenState extends State<EquipmentProfileEditScreen>
if (state.profileToCopy != null) { if (state.profileToCopy != null) {
Navigator.of(context).pushReplacementNamed( Navigator.of(context).pushReplacementNamed(
NavigationRoutes.equipmentProfileEditScreen.name, NavigationRoutes.equipmentProfileEditScreen.name,
arguments: EquipmentProfileEditArgs( arguments: EquipmentProfileEditArgs<T>(
editType: EquipmentProfileEditType.add, editType: EquipmentProfileEditType.add,
profile: state.profileToCopy, profile: state.profileToCopy!,
), ),
); );
} else { } else {
@ -57,25 +57,25 @@ class _EquipmentProfileEditScreenState extends State<EquipmentProfileEditScreen>
child: SliverScreen( child: SliverScreen(
title: Text(widget.isEdit ? S.of(context).editEquipmentProfileTitle : S.of(context).addEquipmentProfileTitle), title: Text(widget.isEdit ? S.of(context).editEquipmentProfileTitle : S.of(context).addEquipmentProfileTitle),
appBarActions: [ appBarActions: [
BlocBuilder<EquipmentProfileEditBloc, EquipmentProfileEditState>( BlocBuilder<IEquipmentProfileEditBloc<T>, EquipmentProfileEditState<T>>(
buildWhen: (previous, current) => previous.canSave != current.canSave, buildWhen: (previous, current) => previous.canSave != current.canSave,
builder: (context, state) => IconButton( builder: (context, state) => IconButton(
onPressed: state.canSave onPressed: state.canSave
? () { ? () {
context.read<EquipmentProfileEditBloc>().add(const EquipmentProfileSaveEvent()); context.read<IEquipmentProfileEditBloc<T>>().add(const EquipmentProfileSaveEvent());
} }
: null, : null,
icon: const Icon(Icons.save_outlined), icon: const Icon(Icons.save_outlined),
), ),
), ),
if (widget.isEdit) if (widget.isEdit)
BlocBuilder<EquipmentProfileEditBloc, EquipmentProfileEditState>( BlocBuilder<IEquipmentProfileEditBloc<T>, EquipmentProfileEditState<T>>(
buildWhen: (previous, current) => previous.canSave != current.canSave, buildWhen: (previous, current) => previous.canSave != current.canSave,
builder: (context, state) => IconButton( builder: (context, state) => IconButton(
onPressed: state.canSave onPressed: state.canSave
? null ? null
: () { : () {
context.read<EquipmentProfileEditBloc>().add(const EquipmentProfileCopyEvent()); context.read<IEquipmentProfileEditBloc<T>>().add(const EquipmentProfileCopyEvent());
}, },
icon: const Icon(Icons.copy_outlined), icon: const Icon(Icons.copy_outlined),
), ),
@ -83,7 +83,7 @@ class _EquipmentProfileEditScreenState extends State<EquipmentProfileEditScreen>
if (widget.isEdit) if (widget.isEdit)
IconButton( IconButton(
onPressed: () { onPressed: () {
context.read<EquipmentProfileEditBloc>().add(const EquipmentProfileDeleteEvent()); context.read<IEquipmentProfileEditBloc<T>>().add(const EquipmentProfileDeleteEvent());
}, },
icon: const Icon(Icons.delete_outlined), icon: const Icon(Icons.delete_outlined),
), ),
@ -102,16 +102,25 @@ class _EquipmentProfileEditScreenState extends State<EquipmentProfileEditScreen>
padding: const EdgeInsets.symmetric(vertical: Dimens.paddingM), padding: const EdgeInsets.symmetric(vertical: Dimens.paddingM),
child: Opacity( child: Opacity(
opacity: state.isLoading ? Dimens.disabledOpacity : Dimens.enabledOpacity, opacity: state.isLoading ? Dimens.disabledOpacity : Dimens.enabledOpacity,
child: const Column( child: Column(
children: [ children: switch (state.profile) {
_NameFieldBuilder(), EquipmentProfile() => [
_IsoValuesListTileBuilder(), _NameFieldBuilder<T>(),
_NdValuesListTileBuilder(),
_ApertureValuesListTileBuilder(), _ApertureValuesListTileBuilder(),
_ShutterSpeedValuesListTileBuilder(), _ShutterSpeedValuesListTileBuilder(),
_LensZoomListTileBuilder(), _IsoValuesListTileBuilder<T>(),
_ExposureOffsetListTileBuilder(), _NdValuesListTileBuilder(),
_LensZoomListTileBuilder<T>(),
_ExposureOffsetListTileBuilder<T>(),
], ],
PinholeEquipmentProfile() => [
_NameFieldBuilder<T>(),
// TODO: Add aperture value list tile for pinhole equipment profile
_IsoValuesListTileBuilder<T>(),
_LensZoomListTileBuilder<T>(),
_ExposureOffsetListTileBuilder<T>(),
],
},
), ),
), ),
), ),
@ -126,12 +135,13 @@ class _EquipmentProfileEditScreenState extends State<EquipmentProfileEditScreen>
} }
} }
class _NameFieldBuilder extends StatelessWidget { class _NameFieldBuilder<T extends IEquipmentProfile> extends StatelessWidget {
const _NameFieldBuilder(); const _NameFieldBuilder();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<EquipmentProfileEditBloc, EquipmentProfileEditState>( return BlocBuilder<IEquipmentProfileEditBloc<T>, EquipmentProfileEditState<T>>(
buildWhen: (previous, current) => previous.profile.name != current.profile.name,
builder: (context, state) => Padding( builder: (context, state) => Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
left: Dimens.paddingM, left: Dimens.paddingM,
@ -141,13 +151,13 @@ class _NameFieldBuilder extends StatelessWidget {
), ),
child: LightmeterTextField( child: LightmeterTextField(
autofocus: true, autofocus: true,
initialValue: state.name, initialValue: state.profile.name,
maxLength: 48, maxLength: 48,
hintText: S.of(context).name, hintText: S.of(context).name,
style: Theme.of(context).listTileTheme.titleTextStyle, style: Theme.of(context).listTileTheme.titleTextStyle,
leading: const Icon(Icons.edit_outlined), leading: const Icon(Icons.edit_outlined),
onChanged: (value) { onChanged: (value) {
context.read<EquipmentProfileEditBloc>().add(EquipmentProfileNameChangedEvent(value)); context.read<IEquipmentProfileEditBloc<T>>().add(EquipmentProfileNameChangedEvent<T>(value));
}, },
), ),
), ),
@ -155,20 +165,20 @@ class _NameFieldBuilder extends StatelessWidget {
} }
} }
class _IsoValuesListTileBuilder extends StatelessWidget { class _IsoValuesListTileBuilder<T extends IEquipmentProfile> extends StatelessWidget {
const _IsoValuesListTileBuilder(); const _IsoValuesListTileBuilder();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<EquipmentProfileEditBloc, EquipmentProfileEditState>( return BlocBuilder<IEquipmentProfileEditBloc<T>, EquipmentProfileEditState<T>>(
builder: (context, state) => FilterListTile<IsoValue>( builder: (context, state) => FilterListTile<IsoValue>(
icon: Icons.iso_outlined, icon: Icons.iso_outlined,
title: S.of(context).isoValues, title: S.of(context).isoValues,
description: S.of(context).isoValuesFilterDescription, description: S.of(context).isoValuesFilterDescription,
values: IsoValue.values, values: IsoValue.values,
selectedValues: state.isoValues, selectedValues: state.profile.isoValues,
onChanged: (value) { onChanged: (value) {
context.read<EquipmentProfileEditBloc>().add(EquipmentProfileIsoValuesChangedEvent(value)); context.read<IEquipmentProfileEditBloc<T>>().add(EquipmentProfileIsoValuesChangedEvent<T>(value));
}, },
), ),
); );
@ -180,13 +190,13 @@ class _NdValuesListTileBuilder extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<EquipmentProfileEditBloc, EquipmentProfileEditState>( return BlocBuilder<EquipmentProfileEditBloc, EquipmentProfileEditState<EquipmentProfile>>(
builder: (context, state) => FilterListTile<NdValue>( builder: (context, state) => FilterListTile<NdValue>(
icon: Icons.filter_b_and_w_outlined, icon: Icons.filter_b_and_w_outlined,
title: S.of(context).ndFilters, title: S.of(context).ndFilters,
description: S.of(context).ndFiltersFilterDescription, description: S.of(context).ndFiltersFilterDescription,
values: NdValue.values, values: NdValue.values,
selectedValues: state.ndValues, selectedValues: state.profile.ndValues,
onChanged: (value) { onChanged: (value) {
context.read<EquipmentProfileEditBloc>().add(EquipmentProfileNdValuesChangedEvent(value)); context.read<EquipmentProfileEditBloc>().add(EquipmentProfileNdValuesChangedEvent(value));
}, },
@ -200,13 +210,13 @@ class _ApertureValuesListTileBuilder extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<EquipmentProfileEditBloc, EquipmentProfileEditState>( return BlocBuilder<EquipmentProfileEditBloc, EquipmentProfileEditState<EquipmentProfile>>(
builder: (context, state) => RangePickerListTile<ApertureValue>( builder: (context, state) => RangePickerListTile<ApertureValue>(
icon: Icons.camera_outlined, icon: Icons.camera_outlined,
title: S.of(context).apertureValues, title: S.of(context).apertureValues,
description: S.of(context).apertureValuesFilterDescription, description: S.of(context).apertureValuesFilterDescription,
values: ApertureValue.values, values: ApertureValue.values,
selectedValues: state.apertureValues, selectedValues: state.profile.apertureValues,
onChanged: (value) { onChanged: (value) {
context.read<EquipmentProfileEditBloc>().add(EquipmentProfileApertureValuesChangedEvent(value)); context.read<EquipmentProfileEditBloc>().add(EquipmentProfileApertureValuesChangedEvent(value));
}, },
@ -220,13 +230,13 @@ class _ShutterSpeedValuesListTileBuilder extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<EquipmentProfileEditBloc, EquipmentProfileEditState>( return BlocBuilder<EquipmentProfileEditBloc, EquipmentProfileEditState<EquipmentProfile>>(
builder: (context, state) => RangePickerListTile<ShutterSpeedValue>( builder: (context, state) => RangePickerListTile<ShutterSpeedValue>(
icon: Icons.shutter_speed_outlined, icon: Icons.shutter_speed_outlined,
title: S.of(context).shutterSpeedValues, title: S.of(context).shutterSpeedValues,
description: S.of(context).shutterSpeedValuesFilterDescription, description: S.of(context).shutterSpeedValuesFilterDescription,
values: ShutterSpeedValue.values, values: ShutterSpeedValue.values,
selectedValues: state.shutterSpeedValues, selectedValues: state.profile.shutterSpeedValues,
trailingAdapter: (context, value) => trailingAdapter: (context, value) =>
value.value == 1 ? S.of(context).shutterSpeedManualShort : value.toString(), value.value == 1 ? S.of(context).shutterSpeedManualShort : value.toString(),
dialogValueAdapter: (context, value) => value.value == 1 ? S.of(context).shutterSpeedManual : value.toString(), dialogValueAdapter: (context, value) => value.value == 1 ? S.of(context).shutterSpeedManual : value.toString(),
@ -238,42 +248,44 @@ class _ShutterSpeedValuesListTileBuilder extends StatelessWidget {
} }
} }
class _LensZoomListTileBuilder extends StatelessWidget { class _LensZoomListTileBuilder<T extends IEquipmentProfile> extends StatelessWidget {
const _LensZoomListTileBuilder(); const _LensZoomListTileBuilder();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<EquipmentProfileEditBloc, EquipmentProfileEditState>( return BlocBuilder<IEquipmentProfileEditBloc<T>, EquipmentProfileEditState<T>>(
buildWhen: (previous, current) => previous.profile.lensZoom != current.profile.lensZoom,
builder: (context, state) => SliderPickerListTile( builder: (context, state) => SliderPickerListTile(
icon: Icons.zoom_in_outlined, icon: Icons.zoom_in_outlined,
title: S.of(context).lensZoom, title: S.of(context).lensZoom,
description: S.of(context).lensZoomDescription, description: S.of(context).lensZoomDescription,
value: state.lensZoom, value: state.profile.lensZoom,
range: CameraContainerBloc.zoomMaxRange, range: CameraContainerBloc.zoomMaxRange,
valueAdapter: (context, value) => value.toZoom(context), valueAdapter: (context, value) => value.toZoom(context),
onChanged: (value) { onChanged: (value) {
context.read<EquipmentProfileEditBloc>().add(EquipmentProfileLensZoomChangedEvent(value)); context.read<IEquipmentProfileEditBloc<T>>().add(EquipmentProfileLensZoomChangedEvent<T>(value));
}, },
), ),
); );
} }
} }
class _ExposureOffsetListTileBuilder extends StatelessWidget { class _ExposureOffsetListTileBuilder<T extends IEquipmentProfile> extends StatelessWidget {
const _ExposureOffsetListTileBuilder(); const _ExposureOffsetListTileBuilder();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<EquipmentProfileEditBloc, EquipmentProfileEditState>( return BlocBuilder<IEquipmentProfileEditBloc<T>, EquipmentProfileEditState<T>>(
buildWhen: (previous, current) => previous.profile.exposureOffset != current.profile.exposureOffset,
builder: (context, state) => SliderPickerListTile( builder: (context, state) => SliderPickerListTile(
icon: Icons.light_mode_outlined, icon: Icons.light_mode_outlined,
title: S.of(context).exposureOffset, title: S.of(context).exposureOffset,
description: S.of(context).exposureOffsetDescription, description: S.of(context).exposureOffsetDescription,
value: state.exposureOffset, value: state.profile.exposureOffset,
range: CameraContainerBloc.exposureMaxRange, range: CameraContainerBloc.exposureMaxRange,
valueAdapter: (context, value) => S.of(context).evValue(value.toStringSignedAsFixed(1)), valueAdapter: (context, value) => S.of(context).evValue(value.toStringSignedAsFixed(1)),
onChanged: (value) { onChanged: (value) {
context.read<EquipmentProfileEditBloc>().add(EquipmentProfileExposureOffsetChangedEvent(value)); context.read<IEquipmentProfileEditBloc<T>>().add(EquipmentProfileExposureOffsetChangedEvent<T>(value));
}, },
), ),
); );

View file

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

View file

@ -4,11 +4,14 @@ import 'package:lightmeter/navigation/routes.dart';
import 'package:lightmeter/providers/equipment_profile_provider.dart'; import 'package:lightmeter/providers/equipment_profile_provider.dart';
import 'package:lightmeter/res/dimens.dart'; import 'package:lightmeter/res/dimens.dart';
import 'package:lightmeter/screens/equipment_profile_edit/flow_equipment_profile_edit.dart'; import 'package:lightmeter/screens/equipment_profile_edit/flow_equipment_profile_edit.dart';
import 'package:lightmeter/screens/settings/components/shared/dialog_picker/widget_dialog_picker.dart';
import 'package:lightmeter/screens/shared/sliver_placeholder/widget_sliver_placeholder.dart'; import 'package:lightmeter/screens/shared/sliver_placeholder/widget_sliver_placeholder.dart';
import 'package:lightmeter/screens/shared/sliver_screen/screen_sliver.dart'; import 'package:lightmeter/screens/shared/sliver_screen/screen_sliver.dart';
import 'package:lightmeter/utils/guard_pro_tap.dart'; import 'package:lightmeter/utils/guard_pro_tap.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
enum _EquipmentProfileType { regular, pinhole }
class EquipmentProfilesScreen extends StatefulWidget { class EquipmentProfilesScreen extends StatefulWidget {
const EquipmentProfilesScreen({super.key}); const EquipmentProfilesScreen({super.key});
@ -45,15 +48,45 @@ class _EquipmentProfilesScreenState extends State<EquipmentProfilesScreen> with
guardProTap( guardProTap(
context, context,
() { () {
showDialog<_EquipmentProfileType>(
context: context,
builder: (_) => DialogPicker<_EquipmentProfileType>(
icon: Icons.camera_alt_outlined,
title: S.of(context).equipmentProfileType,
selectedValue: _EquipmentProfileType.regular,
values: _EquipmentProfileType.values,
titleAdapter: (context, value) => switch (value) {
_EquipmentProfileType.regular => S.of(context).camera,
_EquipmentProfileType.pinhole => S.of(context).pinholeCamera,
},
),
).then((value) {
if (value != null && mounted) {
Navigator.of(context).pushNamed( Navigator.of(context).pushNamed(
NavigationRoutes.equipmentProfileEditScreen.name, NavigationRoutes.equipmentProfileEditScreen.name,
arguments: const EquipmentProfileEditArgs(editType: EquipmentProfileEditType.add), arguments: switch (value) {
_EquipmentProfileType.regular => const EquipmentProfileEditArgs(
editType: EquipmentProfileEditType.add,
profile: EquipmentProfilesProvider.defaultProfile,
),
_EquipmentProfileType.pinhole => EquipmentProfileEditArgs(
editType: EquipmentProfileEditType.add,
profile: PinholeEquipmentProfile(
id: EquipmentProfilesProvider.defaultProfile.id,
name: EquipmentProfilesProvider.defaultProfile.name,
aperture: 22,
isoValues: EquipmentProfilesProvider.defaultProfile.isoValues,
),
),
},
); );
}
});
}, },
); );
} }
void _editProfile(EquipmentProfile profile) { void _editProfile(IEquipmentProfile profile) {
Navigator.of(context).pushNamed( Navigator.of(context).pushNamed(
NavigationRoutes.equipmentProfileEditScreen.name, NavigationRoutes.equipmentProfileEditScreen.name,
arguments: EquipmentProfileEditArgs( arguments: EquipmentProfileEditArgs(
@ -65,9 +98,9 @@ class _EquipmentProfilesScreenState extends State<EquipmentProfilesScreen> with
} }
class _EquipmentProfilesListBuilder extends StatelessWidget { class _EquipmentProfilesListBuilder extends StatelessWidget {
final List<EquipmentProfile> values; final List<IEquipmentProfile> values;
final void Function(EquipmentProfile profile) onEdit; final void Function(IEquipmentProfile profile) onEdit;
final void Function(EquipmentProfile profile, bool value) onCheckbox; final void Function(String id, bool value) onCheckbox;
const _EquipmentProfilesListBuilder({ const _EquipmentProfilesListBuilder({
required this.values, required this.values,
@ -102,7 +135,7 @@ class _EquipmentProfilesListBuilder extends StatelessWidget {
title: Text(values[index].name), title: Text(values[index].name),
controlAffinity: ListTileControlAffinity.leading, controlAffinity: ListTileControlAffinity.leading,
value: EquipmentProfiles.inUseOf(context).contains(values[index]), value: EquipmentProfiles.inUseOf(context).contains(values[index]),
onChanged: (value) => onCheckbox(values[index], value ?? false), onChanged: (value) => onCheckbox(values[index].id, value ?? false),
secondary: IconButton( secondary: IconButton(
onPressed: () => onEdit(values[index]), onPressed: () => onEdit(values[index]),
icon: const Icon(Icons.edit_outlined), icon: const Icon(Icons.edit_outlined),