m3_lightmeter/lib/providers/equipment_profile_provider.dart

186 lines
6.3 KiB
Dart
Raw Permalink Normal View History

2024-11-06 14:28:16 +00:00
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:lightmeter/utils/context_utils.dart';
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
2024-11-06 14:28:16 +00:00
class EquipmentProfilesProvider extends StatefulWidget {
static const EquipmentProfile defaultProfile = EquipmentProfile(
id: '',
name: '',
apertureValues: ApertureValue.values,
ndValues: NdValue.values,
shutterSpeedValues: ShutterSpeedValue.values,
isoValues: IsoValue.values,
);
final EquipmentProfilesStorageService storageService;
final VoidCallback? onInitialized;
final Widget child;
2024-11-06 14:28:16 +00:00
const EquipmentProfilesProvider({
required this.storageService,
this.onInitialized,
required this.child,
super.key,
});
2024-11-06 14:28:16 +00:00
static EquipmentProfilesProviderState of(BuildContext context) {
return context.findAncestorStateOfType<EquipmentProfilesProviderState>()!;
}
@override
2024-11-06 14:28:16 +00:00
State<EquipmentProfilesProvider> createState() => EquipmentProfilesProviderState();
}
2024-11-06 14:28:16 +00:00
class EquipmentProfilesProviderState extends State<EquipmentProfilesProvider> {
2024-11-11 13:27:03 +00:00
final TogglableMap<EquipmentProfile> _customProfiles = {};
String _selectedId = '';
EquipmentProfile get _selectedProfile =>
_customProfiles[_selectedId]?.value ?? EquipmentProfilesProvider.defaultProfile;
@override
void initState() {
super.initState();
_init();
}
@override
Widget build(BuildContext context) {
return EquipmentProfiles(
2024-11-06 14:28:16 +00:00
profiles: context.isPro ? _customProfiles : {},
selected: context.isPro ? _selectedProfile : EquipmentProfilesProvider.defaultProfile,
child: widget.child,
);
}
Future<void> _init() async {
_selectedId = widget.storageService.selectedEquipmentProfileId;
_customProfiles.addAll(await widget.storageService.getProfiles());
_discardSelectedIfNotIncluded();
if (mounted) setState(() {});
widget.onInitialized?.call();
}
Future<void> addProfile(EquipmentProfile profile) async {
await widget.storageService.addProfile(profile);
_customProfiles[profile.id] = (value: profile, isUsed: true);
setState(() {});
}
Future<void> updateProfile(EquipmentProfile profile) async {
final oldProfile = _customProfiles[profile.id]!.value;
await widget.storageService.updateProfile(
id: profile.id,
name: oldProfile.name != profile.name ? profile.name : null,
apertureValues: oldProfile.apertureValues != profile.apertureValues ? profile.apertureValues : null,
shutterSpeedValues:
oldProfile.shutterSpeedValues != profile.shutterSpeedValues ? profile.shutterSpeedValues : null,
isoValues: oldProfile.isoValues != profile.isoValues ? profile.isoValues : null,
ndValues: oldProfile.ndValues != profile.ndValues ? profile.ndValues : null,
lensZoom: oldProfile.lensZoom != profile.lensZoom ? profile.lensZoom : null,
);
_customProfiles[profile.id] = (value: profile, isUsed: _customProfiles[profile.id]!.isUsed);
setState(() {});
}
Future<void> deleteProfile(EquipmentProfile profile) async {
await widget.storageService.deleteProfile(profile.id);
if (profile.id == _selectedId) {
2024-11-06 14:28:16 +00:00
_selectedId = EquipmentProfilesProvider.defaultProfile.id;
widget.storageService.selectedEquipmentProfileId = EquipmentProfilesProvider.defaultProfile.id;
}
_customProfiles.remove(profile.id);
_discardSelectedIfNotIncluded();
setState(() {});
}
2024-11-06 14:28:16 +00:00
void selectProfile(EquipmentProfile data) {
if (_selectedId != data.id) {
setState(() {
_selectedId = data.id;
});
widget.storageService.selectedEquipmentProfileId = _selectedProfile.id;
}
}
Future<void> toggleProfile(EquipmentProfile profile, bool enabled) async {
if (_customProfiles.containsKey(profile.id)) {
_customProfiles[profile.id] = (value: profile, isUsed: enabled);
} else {
return;
}
await widget.storageService.updateProfile(id: profile.id, isUsed: enabled);
_discardSelectedIfNotIncluded();
setState(() {});
}
void _discardSelectedIfNotIncluded() {
if (_selectedId == EquipmentProfilesProvider.defaultProfile.id) {
return;
}
final isSelectedUsed = _customProfiles[_selectedId]?.isUsed ?? false;
if (!isSelectedUsed) {
_selectedId = EquipmentProfilesProvider.defaultProfile.id;
widget.storageService.selectedEquipmentProfileId = _selectedId;
}
}
2024-11-06 14:28:16 +00:00
}
enum _EquipmentProfilesModelAspect {
profiles,
profilesInUse,
2024-11-06 14:28:16 +00:00
selected,
}
2024-11-06 14:28:16 +00:00
class EquipmentProfiles extends InheritedModel<_EquipmentProfilesModelAspect> {
2024-11-11 13:27:03 +00:00
final TogglableMap<EquipmentProfile> profiles;
2024-11-06 14:28:16 +00:00
final EquipmentProfile selected;
const EquipmentProfiles({
2024-11-06 14:28:16 +00:00
required this.profiles,
required this.selected,
required super.child,
});
2024-11-06 14:28:16 +00:00
/// _default + profiles create by the user
static List<EquipmentProfile> of(BuildContext context) {
2024-11-06 14:28:16 +00:00
final model =
InheritedModel.inheritFrom<EquipmentProfiles>(context, aspect: _EquipmentProfilesModelAspect.profiles)!;
return List<EquipmentProfile>.from(
[
EquipmentProfilesProvider.defaultProfile,
...model.profiles.values.map((p) => p.value),
],
);
}
static List<EquipmentProfile> inUseOf(BuildContext context) {
final model =
InheritedModel.inheritFrom<EquipmentProfiles>(context, aspect: _EquipmentProfilesModelAspect.profilesInUse)!;
return List<EquipmentProfile>.from(
[
EquipmentProfilesProvider.defaultProfile,
...model.profiles.values.where((p) => p.isUsed).map((p) => p.value),
],
);
}
static EquipmentProfile selectedOf(BuildContext context) {
2024-11-06 14:28:16 +00:00
return InheritedModel.inheritFrom<EquipmentProfiles>(context, aspect: _EquipmentProfilesModelAspect.selected)!
.selected;
}
2024-11-06 14:28:16 +00:00
@override
bool updateShouldNotify(EquipmentProfiles _) => true;
@override
bool updateShouldNotifyDependent(EquipmentProfiles oldWidget, Set<_EquipmentProfilesModelAspect> dependencies) {
return (dependencies.contains(_EquipmentProfilesModelAspect.selected) && oldWidget.selected != selected) ||
((dependencies.contains(_EquipmentProfilesModelAspect.profiles) ||
dependencies.contains(_EquipmentProfilesModelAspect.profilesInUse)) &&
2024-11-06 14:28:16 +00:00
const DeepCollectionEquality().equals(oldWidget.profiles, profiles));
}
}