m3_lightmeter/lib/providers/logbook_photos_provider.dart

158 lines
4.7 KiB
Dart
Raw Normal View History

2025-07-09 19:48:24 +00:00
import 'dart:io';
2025-06-13 20:54:02 +00:00
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
2025-07-10 13:18:47 +00:00
import 'package:lightmeter/providers/services_provider.dart';
2025-06-13 20:54:02 +00:00
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';
2025-07-09 19:48:24 +00:00
import 'package:uuid/v8.dart';
2025-06-13 20:54:02 +00:00
class LogbookPhotosProvider extends StatefulWidget {
final LogbookPhotosStorageService storageService;
final VoidCallback? onInitialized;
final Widget child;
const LogbookPhotosProvider({
required this.storageService,
this.onInitialized,
required this.child,
super.key,
});
static LogbookPhotosProviderState of(BuildContext context) {
return context.findAncestorStateOfType<LogbookPhotosProviderState>()!;
}
@override
State<LogbookPhotosProvider> createState() => LogbookPhotosProviderState();
}
class LogbookPhotosProviderState extends State<LogbookPhotosProvider> {
final Map<String, LogbookPhoto> _photos = {};
2025-07-11 09:37:59 +00:00
bool _isEnabled = true;
2025-06-13 20:54:02 +00:00
@override
void initState() {
super.initState();
_init();
}
@override
Widget build(BuildContext context) {
return LogbookPhotos(
photos: context.isPro ? _photos.values.toList(growable: false) : [],
2025-07-11 09:37:59 +00:00
isEnabled: _isEnabled,
2025-06-13 20:54:02 +00:00
child: widget.child,
);
}
2025-07-11 09:37:59 +00:00
void saveLogbookPhotos(bool save) {
setState(() {
_isEnabled = save;
});
}
2025-06-13 20:54:02 +00:00
Future<void> _init() async {
_photos.addAll(
Map.fromIterable(
await widget.storageService.getPhotos(),
key: (photo) => (photo as LogbookPhoto).id,
),
);
if (mounted) setState(() {});
widget.onInitialized?.call();
}
2025-07-09 19:48:24 +00:00
Future<void> addPhotoIfPossible(
String path, {
required double ev100,
required int iso,
required int nd,
}) async {
2025-07-11 09:37:59 +00:00
if (context.isPro && _isEnabled) {
2025-07-10 13:18:47 +00:00
final geolocationService = ServicesProvider.of(context).geolocationService;
final coordinates = await geolocationService.getCurrentPosition();
2025-07-09 19:48:24 +00:00
final photo = LogbookPhoto(
id: const UuidV8().generate(),
name: path,
timestamp: DateTime.timestamp(),
ev: ev100,
iso: iso,
nd: nd,
2025-07-10 13:18:47 +00:00
coordinates: coordinates,
2025-07-09 19:48:24 +00:00
);
2025-07-11 20:36:03 +00:00
await widget.storageService.addPhoto(photo);
2025-07-09 19:48:24 +00:00
_photos[photo.id] = photo;
setState(() {});
} else {
Directory(path).deleteSync(recursive: true);
}
2025-06-13 20:54:02 +00:00
}
Future<void> updateProfile(LogbookPhoto photo) async {
final oldProfile = _photos[photo.id]!;
2025-07-10 11:52:48 +00:00
await widget.storageService.updatePhoto(
id: photo.id,
note: oldProfile.note != photo.note ? photo.note : null,
apertureValue: oldProfile.apertureValue != photo.apertureValue ? photo.apertureValue : null,
removeApertureValue: photo.apertureValue == null,
shutterSpeedValue: oldProfile.shutterSpeedValue != photo.shutterSpeedValue ? photo.shutterSpeedValue : null,
removeShutterSpeedValue: photo.shutterSpeedValue == null,
);
_photos[photo.id] = photo;
setState(() {});
2025-06-13 20:54:02 +00:00
}
Future<void> deleteProfile(LogbookPhoto photo) async {
await widget.storageService.deletePhoto(photo.id);
_photos.remove(photo.id);
2025-07-09 19:48:24 +00:00
Directory(photo.name).deleteSync(recursive: true);
2025-06-13 20:54:02 +00:00
setState(() {});
}
}
2025-07-11 09:37:59 +00:00
enum _LogbookPhotosModelAspect { photosList, isEnabled }
class LogbookPhotos extends InheritedModel<_LogbookPhotosModelAspect> {
2025-06-13 20:54:02 +00:00
final List<LogbookPhoto> photos;
2025-07-11 09:37:59 +00:00
final bool isEnabled;
2025-06-13 20:54:02 +00:00
const LogbookPhotos({
required this.photos,
2025-07-11 09:37:59 +00:00
required this.isEnabled,
2025-06-13 20:54:02 +00:00
required super.child,
});
2025-07-11 09:37:59 +00:00
static List<LogbookPhoto> of(BuildContext context, {bool listen = true}) {
2025-06-13 20:54:02 +00:00
return (listen
2025-07-11 09:37:59 +00:00
? InheritedModel.inheritFrom<LogbookPhotos>(context, aspect: _LogbookPhotosModelAspect.photosList)
2025-06-13 20:54:02 +00:00
: context.getInheritedWidgetOfExactType<LogbookPhotos>())!
.photos;
}
2025-07-11 09:37:59 +00:00
static bool isEnabledOf(BuildContext context, {bool listen = true}) {
return (listen
? InheritedModel.inheritFrom<LogbookPhotos>(context, aspect: _LogbookPhotosModelAspect.isEnabled)
: context.getInheritedWidgetOfExactType<LogbookPhotos>())!
.isEnabled;
}
@override
bool updateShouldNotify(LogbookPhotos oldWidget) =>
!const DeepCollectionEquality().equals(oldWidget.photos, photos) || oldWidget.isEnabled != isEnabled;
2025-06-13 20:54:02 +00:00
@override
2025-07-11 09:37:59 +00:00
bool updateShouldNotifyDependent(LogbookPhotos oldWidget, Set<_LogbookPhotosModelAspect> aspects) {
if (aspects.contains(_LogbookPhotosModelAspect.photosList) &&
!const DeepCollectionEquality().equals(oldWidget.photos, photos)) {
return true;
}
if (aspects.contains(_LogbookPhotosModelAspect.isEnabled) && oldWidget.isEnabled != isEnabled) {
return true;
}
return false;
}
2025-06-13 20:54:02 +00:00
}