m3_lightmeter/lib/screens/logbook_photos/screen_logbook_photos.dart
Vadim 7ad47c0636
ML-203 Logging EXIF data (#239)
* typos

* added `LogbookPhotosProvider`

* implemented `LogbookScreen`

* implemented `LogbookPhotoEditScreen`

* added photo update

* save geolocation

* added `CameraSettingsSection`

* adjusted logbook grid

* added hero animation

* fixed logbook list updates

* added empty logbook state

* added `saveLogbookPhotos` option

* fixed updating photos

* made `DialogPicker` content scrollable

* added tests for `LogbookPhotosProvider`

* made image preview full-width

* made note field multiline

* wip

* migrated to new iap service

* fixed unit tests

* typo

* fixed arb formatting

* stub logbook photos for tests

* implemented integration test for logbook

* moved date to title

* redundant bottom padding

* added logbook photo screen to screenshots generator

* Update settings.gradle

* aligned iap stub with iap release

* sync

* made logbook iap

* debug screenshots

* Update runner.dart

* fixed dialog picker of optional values

* added bottom padding to logbook edit screen

* fixed tests

* Create camera_stub_image.jpg

* Update films_provider_test.dart

* rename

* Update pubspec.yaml

* added logbook to pro features
2025-07-29 12:38:48 +02:00

130 lines
4.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:lightmeter/generated/l10n.dart';
import 'package:lightmeter/navigation/routes.dart';
import 'package:lightmeter/platform_config.dart';
import 'package:lightmeter/providers/logbook_photos_provider.dart';
import 'package:lightmeter/res/dimens.dart';
import 'package:lightmeter/screens/logbook_photos/components/grid_tile/widget_grid_tile_logbook_photo.dart';
import 'package:lightmeter/screens/shared/icon_placeholder/widget_icon_placeholder.dart';
import 'package:lightmeter/screens/shared/sliver_screen/screen_sliver.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
class LogbookPhotosScreen extends StatefulWidget {
const LogbookPhotosScreen({super.key});
@override
State<LogbookPhotosScreen> createState() => _LogbookPhotosScreenState();
}
class _LogbookPhotosScreenState extends State<LogbookPhotosScreen> with SingleTickerProviderStateMixin {
@override
Widget build(BuildContext context) {
return SliverScreen(
title: Text(S.of(context).logbook),
slivers: [
SliverToBoxAdapter(
child: Card(
margin: const EdgeInsets.symmetric(horizontal: Dimens.paddingM),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: Dimens.paddingM),
child: SwitchListTile(
secondary: const Icon(Icons.book_outlined),
title: Text(S.of(context).saveNewPhotos),
value: LogbookPhotos.isEnabledOf(context),
onChanged: LogbookPhotosProvider.of(context).saveLogbookPhotos,
),
),
),
),
_PicturesGridBuilder(
values: LogbookPhotos.of(context),
onEdit: _editProfile,
),
SliverToBoxAdapter(
child: SizedBox(height: MediaQuery.paddingOf(context).bottom),
),
],
);
}
void _editProfile(LogbookPhoto photo) {
Navigator.of(context).pushNamed(
NavigationRoutes.logbookPhotoEditScreen.name,
arguments: photo,
);
}
}
class _PicturesGridBuilder extends StatefulWidget {
final List<LogbookPhoto> values;
final void Function(LogbookPhoto photo) onEdit;
static const int _crossAxisCount = 3;
const _PicturesGridBuilder({
required this.values,
required this.onEdit,
});
@override
State<_PicturesGridBuilder> createState() => _PicturesGridBuilderState();
}
class _PicturesGridBuilderState extends State<_PicturesGridBuilder> {
late Map<String, GlobalKey> _keys = _generateKeys();
@override
void didUpdateWidget(_PicturesGridBuilder oldWidget) {
super.didUpdateWidget(oldWidget);
_keys = _generateKeys();
}
@override
Widget build(BuildContext context) {
if (widget.values.isEmpty) {
return SliverFillRemaining(
hasScrollBody: false,
child: Center(
child: IconPlaceholder(
icon: Icons.photo_outlined,
text: S.of(context).noPhotos,
),
),
);
}
return SliverPadding(
padding: const EdgeInsets.all(Dimens.paddingM),
sliver: SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: (MediaQuery.sizeOf(context).width -
Dimens.paddingS * (_PicturesGridBuilder._crossAxisCount - 1) -
Dimens.paddingM * 2) /
_PicturesGridBuilder._crossAxisCount,
mainAxisSpacing: Dimens.paddingS,
crossAxisSpacing: Dimens.paddingS,
childAspectRatio: PlatformConfig.cameraPreviewAspectRatio,
),
delegate: SliverChildBuilderDelegate(
//TODO: fix jumping after the photo is edited
(_, int index) => LogbookPhotoGridTile(
key: _keys[widget.values[index].id],
photo: widget.values[index],
onTap: () => widget.onEdit(widget.values[index]),
),
childCount: widget.values.length,
),
),
);
}
Map<String, GlobalKey> _generateKeys() {
return Map.fromEntries(
widget.values.map(
(photo) => MapEntry(
photo.id,
GlobalKey(debugLabel: photo.id),
),
),
);
}
}