mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2025-08-04 20:26:42 +00:00
implemented LogbookPhotoEditScreen
This commit is contained in:
parent
a517a28daf
commit
4e7c080b97
16 changed files with 603 additions and 11 deletions
3
devtools_options.yaml
Normal file
3
devtools_options.yaml
Normal file
|
@ -0,0 +1,3 @@
|
|||
description: This file stores settings for Dart & Flutter DevTools.
|
||||
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||
extensions:
|
3
iap/devtools_options.yaml
Normal file
3
iap/devtools_options.yaml
Normal file
|
@ -0,0 +1,3 @@
|
|||
description: This file stores settings for Dart & Flutter DevTools.
|
||||
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||
extensions:
|
|
@ -12,7 +12,10 @@ import 'package:lightmeter/screens/equipment_profiles/screen_equipment_profiles.
|
|||
import 'package:lightmeter/screens/film_edit/flow_film_edit.dart';
|
||||
import 'package:lightmeter/screens/films/screen_films.dart';
|
||||
import 'package:lightmeter/screens/lightmeter_pro/screen_lightmeter_pro.dart';
|
||||
import 'package:lightmeter/screens/logbook/screen_logbook.dart';
|
||||
import 'package:lightmeter/screens/logbook_photo_edit/flow_logbook_photo_edit.dart';
|
||||
import 'package:lightmeter/screens/metering/flow_metering.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
import 'package:lightmeter/screens/settings/flow_settings.dart';
|
||||
import 'package:lightmeter/screens/shared/release_notes_dialog/flow_dialog_release_notes.dart';
|
||||
import 'package:lightmeter/screens/timer/flow_timer.dart';
|
||||
|
@ -51,13 +54,15 @@ class Application extends StatelessWidget {
|
|||
routes: {
|
||||
NavigationRoutes.meteringScreen.name: (_) => const ReleaseNotesFlow(child: MeteringFlow()),
|
||||
NavigationRoutes.settingsScreen.name: (_) => const SettingsFlow(),
|
||||
NavigationRoutes.equipmentProfilesListScreen.name: (_) => const EquipmentProfilesScreen(),
|
||||
NavigationRoutes.equipmentProfilesListScreen.name: (_) => const LogbookScreen(),
|
||||
NavigationRoutes.equipmentProfileEditScreen.name: (context) =>
|
||||
EquipmentProfileEditFlow(args: context.routeArgs<EquipmentProfileEditArgs>()),
|
||||
NavigationRoutes.filmsListScreen.name: (_) => const FilmsScreen(),
|
||||
NavigationRoutes.filmEditScreen.name: (context) => FilmEditFlow(args: context.routeArgs<FilmEditArgs>()),
|
||||
NavigationRoutes.proFeaturesScreen.name: (_) => LightmeterProScreen(),
|
||||
NavigationRoutes.timerScreen.name: (context) => TimerFlow(args: context.routeArgs<TimerFlowArgs>()),
|
||||
NavigationRoutes.logbookPhotoEditScreen.name: (context) =>
|
||||
LogbookPhotoEditFlow(args: LogbookPhotoEditArgs(photo: context.routeArgs<LogbookPhoto>())),
|
||||
},
|
||||
),
|
||||
);
|
||||
|
|
|
@ -55,10 +55,12 @@
|
|||
"equipmentProfileNameHint": "Praktica MTL5B",
|
||||
"equipmentProfileAllValues": "Alle",
|
||||
"apertureValues": "Blend-Werte",
|
||||
"apertureValue": "Blend-Wert",
|
||||
"apertureValuesFilterDescription": "Wähle die anzuzeigenden Blend-Werte aus. Die Werte sind normalerweise von dem verwendeten Objektiv bestimmt.",
|
||||
"ndFilters": "ND Filter",
|
||||
"ndFiltersFilterDescription": "Wähle die anzuzeigenden ND Filter aus. (Beispielsweise die Meistverwendeten)",
|
||||
"shutterSpeedValues": "Belichtungszeiten",
|
||||
"shutterSpeedValue": "Belichtungszeit",
|
||||
"shutterSpeedValuesFilterDescription": "Wähle die anzuzeigenden Belichtungszeiten aus. Die Werte sind normalerweise von der Kamera bestimmt.",
|
||||
"shutterSpeedManualShort": "B",
|
||||
"shutterSpeedManual": "Manuell",
|
||||
|
@ -163,5 +165,11 @@
|
|||
"filmFormulaExponentialRfPlaceholder": "1.3",
|
||||
"name": "Name",
|
||||
"addEquipmentProfileTitle": "Ausrüstung hinzufügen",
|
||||
"editEquipmentProfileTitle": "Ausrüstung bearbeiten"
|
||||
"editEquipmentProfileTitle": "Ausrüstung bearbeiten",
|
||||
"editPhotoTitle": "Foto bearbeiten",
|
||||
"date": "Datum",
|
||||
"ndFilter": "ND Filter",
|
||||
"film": "Film",
|
||||
"note": "Notiz",
|
||||
"notSet": "Nicht gesetzt"
|
||||
}
|
|
@ -55,10 +55,12 @@
|
|||
"equipmentProfileNameHint": "Praktica MTL5B",
|
||||
"equipmentProfileAllValues": "All",
|
||||
"apertureValues": "Aperture values",
|
||||
"apertureValue": "Aperture value",
|
||||
"apertureValuesFilterDescription": "Select the range of aperture values to display. This is usually determined by the lens you are using.",
|
||||
"ndFilters": "ND filters",
|
||||
"ndFiltersFilterDescription": "Select the ND filters to display. These may be your most commonly used ND filters or the ones that fit your lens.",
|
||||
"shutterSpeedValues": "Shutter speed values",
|
||||
"shutterSpeedValue": "Shutter speed value",
|
||||
"shutterSpeedValuesFilterDescription": "Select the range of shutter speed values to display. This is usually determined by the camera body you are using.",
|
||||
"shutterSpeedManualShort": "B",
|
||||
"shutterSpeedManual": "Manual",
|
||||
|
@ -163,5 +165,11 @@
|
|||
"filmFormulaExponentialRfPlaceholder": "1.3",
|
||||
"name": "Name",
|
||||
"addEquipmentProfileTitle": "Add equipment",
|
||||
"editEquipmentProfileTitle": "Edit equipment"
|
||||
"editEquipmentProfileTitle": "Edit equipment",
|
||||
"editPhotoTitle": "Edit Photo",
|
||||
"date": "Date",
|
||||
"ndFilter": "ND Filter",
|
||||
"film": "Film",
|
||||
"note": "Note",
|
||||
"notSet": "Not set"
|
||||
}
|
|
@ -55,10 +55,12 @@
|
|||
"equipmentProfileNameHint": "Praktica MTL5B",
|
||||
"equipmentProfileAllValues": "Tout",
|
||||
"apertureValues": "Valeurs Aperture",
|
||||
"apertureValue": "Valeur Aperture",
|
||||
"apertureValuesFilterDescription": "Sélectionnez la plage de valeurs d'ouverture à afficher. Cela est généralement déterminé par l'objectif que vous utilisez.",
|
||||
"ndFilters": "Filtres ND",
|
||||
"ndFiltersFilterDescription": "Sélectionnez les filtres ND à afficher. Ce sont peut-être vos filtres ND les plus couramment utilisés ou ceux qui correspondent à votre lentille.",
|
||||
"shutterSpeedValues": "Valeurs de la vitesse d'obturation",
|
||||
"shutterSpeedValue": "Valeur de la vitesse d'obturation",
|
||||
"shutterSpeedValuesFilterDescription": "Sélectionnez la plage de valeurs de vitesse d'obturation à afficher. Cela est généralement déterminé par le corps de l'appareil que vous utilisez.",
|
||||
"shutterSpeedManualShort": "B",
|
||||
"shutterSpeedManual": "Manuelle",
|
||||
|
@ -154,5 +156,11 @@
|
|||
"filmFormulaExponentialRfPlaceholder": "1.3",
|
||||
"name": "Titre",
|
||||
"addEquipmentProfileTitle": "Ajouter un profil",
|
||||
"editEquipmentProfileTitle": "Editer le profil"
|
||||
"editEquipmentProfileTitle": "Editer le profil",
|
||||
"editPhotoTitle": "Modifier la photo",
|
||||
"date": "Date",
|
||||
"ndFilter": "Filtre ND",
|
||||
"film": "Film",
|
||||
"note": "Note",
|
||||
"notSet": "Non défini"
|
||||
}
|
|
@ -55,10 +55,12 @@
|
|||
"equipmentProfileNameHint": "Praktica MTL5B",
|
||||
"equipmentProfileAllValues": "Все",
|
||||
"apertureValues": "Значения диафрагмы",
|
||||
"apertureValue": "Значение диафрагмы",
|
||||
"apertureValuesFilterDescription": "Выберите диапазон значений диафрагмы для отображения. Обычно определяется объективом, который вы используете.",
|
||||
"ndFilters": "ND фильтры",
|
||||
"ndFiltersFilterDescription": "Выберите ND фильтры для отображения. Это могут быть наиболее часто используемые ND фильтры или фильтры, подходящие под ваш объектив.",
|
||||
"shutterSpeedValues": "Значения выдержки",
|
||||
"shutterSpeedValue": "Значение выдержки",
|
||||
"shutterSpeedValuesFilterDescription": "Выберите диапазон значений выдержки. Обычно ограничивается возможностями вашей камеры.",
|
||||
"shutterSpeedManualShort": "B",
|
||||
"shutterSpeedManual": "Ручная",
|
||||
|
@ -153,5 +155,11 @@
|
|||
"filmFormulaExponentialRfPlaceholder": "1.3",
|
||||
"name": "Название",
|
||||
"addEquipmentProfileTitle": "Добавить профиль",
|
||||
"editEquipmentProfileTitle": "Редактировать профиль"
|
||||
"editEquipmentProfileTitle": "Редактировать профиль",
|
||||
"editPhotoTitle": "Редактировать фото",
|
||||
"date": "Дата",
|
||||
"ndFilter": "ND фильтр",
|
||||
"film": "Плёнка",
|
||||
"note": "Заметка",
|
||||
"notSet": "Не задано"
|
||||
}
|
|
@ -55,10 +55,12 @@
|
|||
"equipmentProfileNameHint": "Praktica MTL5B",
|
||||
"equipmentProfileAllValues": "全部",
|
||||
"apertureValues": "光圈值",
|
||||
"apertureValue": "光圈值",
|
||||
"apertureValuesFilterDescription": "选择要显示的光圈值范围。取决于使用的镜头。",
|
||||
"ndFilters": "ND 滤镜",
|
||||
"ndFiltersFilterDescription": "选择要显示的 ND 滤镜系数。取决于使用的 ND 滤镜",
|
||||
"shutterSpeedValues": "快门速度",
|
||||
"shutterSpeedValue": "快门速度",
|
||||
"shutterSpeedValuesFilterDescription": "选择要显示的快门速度范围。取决于相机机身。",
|
||||
"shutterSpeedManualShort": "B门",
|
||||
"shutterSpeedManual": "手动",
|
||||
|
@ -151,5 +153,11 @@
|
|||
"filmFormulaExponentialRf": "Rf",
|
||||
"filmFormulaExponentialRfPlaceholder": "1.3",
|
||||
"addEquipmentProfileTitle": "添加设备",
|
||||
"editEquipmentProfileTitle": "编辑设备"
|
||||
"editEquipmentProfileTitle": "编辑设备",
|
||||
"editPhotoTitle": "编辑照片",
|
||||
"date": "日期",
|
||||
"ndFilter": "ND 滤镜",
|
||||
"film": "胶片",
|
||||
"note": "备注",
|
||||
"notSet": "未设置"
|
||||
}
|
|
@ -7,4 +7,5 @@ enum NavigationRoutes {
|
|||
filmEditScreen,
|
||||
proFeaturesScreen,
|
||||
timerScreen,
|
||||
logbookPhotoEditScreen,
|
||||
}
|
||||
|
|
|
@ -36,7 +36,12 @@ class _LogbookScreenState extends State<LogbookScreen> with SingleTickerProvider
|
|||
);
|
||||
}
|
||||
|
||||
void _editProfile(LogbookPhoto photo) {}
|
||||
void _editProfile(LogbookPhoto photo) {
|
||||
Navigator.of(context).pushNamed(
|
||||
NavigationRoutes.logbookPhotoEditScreen.name,
|
||||
arguments: photo,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _PicturesGridBuilder extends StatelessWidget {
|
||||
|
@ -62,10 +67,13 @@ class _PicturesGridBuilder extends StatelessWidget {
|
|||
),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(BuildContext context, int index) {
|
||||
return Container(
|
||||
alignment: Alignment.center,
|
||||
color: Colors.teal[100 * (index % 9)],
|
||||
child: Image.file(File(values[index].name)),
|
||||
return GestureDetector(
|
||||
onTap: () => onEdit(values[index]),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
color: Colors.teal[100 * (index % 9)],
|
||||
child: Image.file(File(values[index].name)),
|
||||
),
|
||||
);
|
||||
},
|
||||
childCount: values.length,
|
||||
|
|
96
lib/screens/logbook_photo_edit/bloc_logbook_photo_edit.dart
Normal file
96
lib/screens/logbook_photo_edit/bloc_logbook_photo_edit.dart
Normal file
|
@ -0,0 +1,96 @@
|
|||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:lightmeter/providers/logbook_photos_provider.dart';
|
||||
import 'package:lightmeter/screens/logbook_photo_edit/event_logbook_photo_edit.dart';
|
||||
import 'package:lightmeter/screens/logbook_photo_edit/state_logbook_photo_edit.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
class LogbookPhotoEditBloc extends Bloc<LogbookPhotoEditEvent, LogbookPhotoEditState> {
|
||||
final LogbookPhotosProviderState photosProvider;
|
||||
final LogbookPhoto _originalPhoto;
|
||||
LogbookPhoto _newPhoto;
|
||||
|
||||
LogbookPhotoEditBloc(
|
||||
this.photosProvider,
|
||||
LogbookPhoto photo,
|
||||
) : _originalPhoto = photo,
|
||||
_newPhoto = photo,
|
||||
super(
|
||||
LogbookPhotoEditState(
|
||||
id: photo.id,
|
||||
name: photo.name,
|
||||
timestamp: photo.timestamp,
|
||||
ev: photo.ev,
|
||||
iso: photo.iso,
|
||||
nd: photo.nd,
|
||||
film: photo.film,
|
||||
coordinates: photo.coordinates,
|
||||
aperture: null,
|
||||
shutterSpeed: null,
|
||||
note: photo.note,
|
||||
canSave: false,
|
||||
),
|
||||
) {
|
||||
on<LogbookPhotoEditEvent>(
|
||||
(event, emit) async {
|
||||
switch (event) {
|
||||
case final LogbookPhotoApertureChangedEvent e:
|
||||
await _onApertureChanged(e, emit);
|
||||
case final LogbookPhotoShutterSpeedChangedEvent e:
|
||||
await _onShutterSpeedChanged(e, emit);
|
||||
case final LogbookPhotoNoteChangedEvent e:
|
||||
await _onNoteChanged(e, emit);
|
||||
case LogbookPhotoSaveEvent():
|
||||
await _onSave(event, emit);
|
||||
case LogbookPhotoDeleteEvent():
|
||||
await _onDelete(event, emit);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onApertureChanged(LogbookPhotoApertureChangedEvent event, Emitter emit) async {
|
||||
// For now, we'll just update the state since LogbookPhoto doesn't support aperture
|
||||
emit(
|
||||
state.copyWith(
|
||||
aperture: event.aperture,
|
||||
canSave: _canSave(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onShutterSpeedChanged(LogbookPhotoShutterSpeedChangedEvent event, Emitter emit) async {
|
||||
// For now, we'll just update the state since LogbookPhoto doesn't support shutterSpeed
|
||||
emit(
|
||||
state.copyWith(
|
||||
shutterSpeed: event.shutterSpeed,
|
||||
canSave: _canSave(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onNoteChanged(LogbookPhotoNoteChangedEvent event, Emitter emit) async {
|
||||
_newPhoto = _newPhoto.copyWith(note: event.note);
|
||||
emit(
|
||||
state.copyWith(
|
||||
note: event.note,
|
||||
canSave: _canSave(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onSave(LogbookPhotoSaveEvent _, Emitter emit) async {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
await photosProvider.updateProfile(_newPhoto);
|
||||
emit(state.copyWith(isLoading: false));
|
||||
}
|
||||
|
||||
Future<void> _onDelete(LogbookPhotoDeleteEvent _, Emitter emit) async {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
await photosProvider.deleteProfile(_newPhoto);
|
||||
emit(state.copyWith(isLoading: false));
|
||||
}
|
||||
|
||||
bool _canSave() {
|
||||
return _newPhoto != _originalPhoto;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/screens/settings/components/shared/dialog_picker/widget_dialog_picker.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
class PickerListTile<T extends PhotographyValue> extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final String title;
|
||||
final T? selectedValue;
|
||||
final List<T> values;
|
||||
final ValueChanged<T?> onChanged;
|
||||
|
||||
const PickerListTile({
|
||||
required this.icon,
|
||||
required this.title,
|
||||
required this.selectedValue,
|
||||
required this.values,
|
||||
required this.onChanged,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListTile(
|
||||
leading: Icon(icon),
|
||||
title: Text(title),
|
||||
trailing: Text(selectedValue?.toString() ?? S.of(context).notSet),
|
||||
onTap: () {
|
||||
showDialog<T?>(
|
||||
context: context,
|
||||
builder: (_) => DialogPicker<T?>(
|
||||
icon: icon,
|
||||
title: title,
|
||||
selectedValue: selectedValue,
|
||||
values: [null, ...values],
|
||||
titleAdapter: (context, value) => value?.toString() ?? S.of(context).notSet,
|
||||
),
|
||||
).then((value) {
|
||||
if (value != null) {
|
||||
onChanged(value);
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
31
lib/screens/logbook_photo_edit/event_logbook_photo_edit.dart
Normal file
31
lib/screens/logbook_photo_edit/event_logbook_photo_edit.dart
Normal file
|
@ -0,0 +1,31 @@
|
|||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
sealed class LogbookPhotoEditEvent {
|
||||
const LogbookPhotoEditEvent();
|
||||
}
|
||||
|
||||
class LogbookPhotoApertureChangedEvent extends LogbookPhotoEditEvent {
|
||||
final ApertureValue? aperture;
|
||||
|
||||
const LogbookPhotoApertureChangedEvent(this.aperture);
|
||||
}
|
||||
|
||||
class LogbookPhotoShutterSpeedChangedEvent extends LogbookPhotoEditEvent {
|
||||
final ShutterSpeedValue? shutterSpeed;
|
||||
|
||||
const LogbookPhotoShutterSpeedChangedEvent(this.shutterSpeed);
|
||||
}
|
||||
|
||||
class LogbookPhotoNoteChangedEvent extends LogbookPhotoEditEvent {
|
||||
final String? note;
|
||||
|
||||
const LogbookPhotoNoteChangedEvent(this.note);
|
||||
}
|
||||
|
||||
class LogbookPhotoSaveEvent extends LogbookPhotoEditEvent {
|
||||
const LogbookPhotoSaveEvent();
|
||||
}
|
||||
|
||||
class LogbookPhotoDeleteEvent extends LogbookPhotoEditEvent {
|
||||
const LogbookPhotoDeleteEvent();
|
||||
}
|
32
lib/screens/logbook_photo_edit/flow_logbook_photo_edit.dart
Normal file
32
lib/screens/logbook_photo_edit/flow_logbook_photo_edit.dart
Normal file
|
@ -0,0 +1,32 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:lightmeter/providers/logbook_photos_provider.dart';
|
||||
import 'package:lightmeter/screens/logbook_photo_edit/bloc_logbook_photo_edit.dart';
|
||||
import 'package:lightmeter/screens/logbook_photo_edit/screen_logbook_photo_edit.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
class LogbookPhotoEditArgs {
|
||||
final LogbookPhoto photo;
|
||||
|
||||
const LogbookPhotoEditArgs({required this.photo});
|
||||
}
|
||||
|
||||
class LogbookPhotoEditFlow extends StatelessWidget {
|
||||
final LogbookPhotoEditArgs args;
|
||||
|
||||
const LogbookPhotoEditFlow({
|
||||
required this.args,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (_) => LogbookPhotoEditBloc(
|
||||
LogbookPhotosProvider.of(context),
|
||||
args.photo,
|
||||
),
|
||||
child: const LogbookPhotoEditScreen(),
|
||||
);
|
||||
}
|
||||
}
|
263
lib/screens/logbook_photo_edit/screen_logbook_photo_edit.dart
Normal file
263
lib/screens/logbook_photo_edit/screen_logbook_photo_edit.dart
Normal file
|
@ -0,0 +1,263 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/platform_config.dart';
|
||||
import 'package:lightmeter/res/dimens.dart';
|
||||
import 'package:lightmeter/screens/logbook_photo_edit/bloc_logbook_photo_edit.dart';
|
||||
import 'package:lightmeter/screens/logbook_photo_edit/components/picker_list_tile/widget_list_tile_picker.dart';
|
||||
import 'package:lightmeter/screens/logbook_photo_edit/event_logbook_photo_edit.dart';
|
||||
import 'package:lightmeter/screens/logbook_photo_edit/state_logbook_photo_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:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
class LogbookPhotoEditScreen extends StatefulWidget {
|
||||
const LogbookPhotoEditScreen({super.key});
|
||||
|
||||
@override
|
||||
State<LogbookPhotoEditScreen> createState() => _LogbookPhotoEditScreenState();
|
||||
}
|
||||
|
||||
class _LogbookPhotoEditScreenState extends State<LogbookPhotoEditScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocConsumer<LogbookPhotoEditBloc, LogbookPhotoEditState>(
|
||||
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(S.of(context).editPhotoTitle),
|
||||
appBarActions: [
|
||||
BlocBuilder<LogbookPhotoEditBloc, LogbookPhotoEditState>(
|
||||
buildWhen: (previous, current) => previous.canSave != current.canSave,
|
||||
builder: (context, state) => IconButton(
|
||||
onPressed: state.canSave
|
||||
? () {
|
||||
context.read<LogbookPhotoEditBloc>().add(const LogbookPhotoSaveEvent());
|
||||
}
|
||||
: null,
|
||||
icon: const Icon(Icons.save_outlined),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
context.read<LogbookPhotoEditBloc>().add(const LogbookPhotoDeleteEvent());
|
||||
},
|
||||
icon: const Icon(Icons.delete_outlined),
|
||||
),
|
||||
],
|
||||
slivers: [
|
||||
SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(
|
||||
Dimens.paddingM,
|
||||
0,
|
||||
Dimens.paddingM,
|
||||
Dimens.paddingM,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
const _PhotoPreviewBuilder(),
|
||||
const SizedBox(height: Dimens.grid16),
|
||||
Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: Dimens.paddingM),
|
||||
child: Opacity(
|
||||
opacity: state.isLoading ? Dimens.disabledOpacity : Dimens.enabledOpacity,
|
||||
child: const Column(
|
||||
children: [
|
||||
_DateListTile(),
|
||||
_NoteListTile(),
|
||||
_EvListTile(),
|
||||
_IsoListTile(),
|
||||
_NdFilterListTile(),
|
||||
_AperturePickerListTile(),
|
||||
_ShutterSpeedPickerListTile(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(child: SizedBox(height: MediaQuery.paddingOf(context).bottom)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _PhotoPreviewBuilder extends StatelessWidget {
|
||||
const _PhotoPreviewBuilder();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<LogbookPhotoEditBloc, LogbookPhotoEditState>(
|
||||
buildWhen: (_, __) => false,
|
||||
builder: (context, state) => AspectRatio(
|
||||
aspectRatio: PlatformConfig.cameraPreviewAspectRatio,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(Dimens.borderRadiusM),
|
||||
child: Image.file(
|
||||
File(state.name),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _DateListTile extends StatelessWidget {
|
||||
const _DateListTile();
|
||||
|
||||
String _formatDate(DateTime dateTime) {
|
||||
final day = dateTime.day.toString().padLeft(2, '0');
|
||||
final month = dateTime.month.toString().padLeft(2, '0');
|
||||
final year = dateTime.year.toString();
|
||||
final hour = dateTime.hour.toString().padLeft(2, '0');
|
||||
final minute = dateTime.minute.toString().padLeft(2, '0');
|
||||
return '$day.$month.$year $hour:$minute';
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<LogbookPhotoEditBloc, LogbookPhotoEditState>(
|
||||
buildWhen: (_, __) => false,
|
||||
builder: (context, state) => ListTile(
|
||||
leading: const Icon(Icons.access_time),
|
||||
title: Text(S.of(context).date),
|
||||
trailing: Text(_formatDate(state.timestamp)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _NoteListTile extends StatelessWidget {
|
||||
const _NoteListTile();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<LogbookPhotoEditBloc, LogbookPhotoEditState>(
|
||||
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.note,
|
||||
maxLength: 500,
|
||||
hintText: S.of(context).note,
|
||||
style: Theme.of(context).listTileTheme.titleTextStyle,
|
||||
leading: const Icon(Icons.note_outlined),
|
||||
onChanged: (value) {
|
||||
context.read<LogbookPhotoEditBloc>().add(LogbookPhotoNoteChangedEvent(value));
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _EvListTile extends StatelessWidget {
|
||||
const _EvListTile();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<LogbookPhotoEditBloc, LogbookPhotoEditState>(
|
||||
buildWhen: (_, __) => false,
|
||||
builder: (context, state) => ListTile(
|
||||
leading: const Icon(Icons.exposure),
|
||||
title: Text(S.of(context).ev),
|
||||
trailing: Text(state.ev.toStringAsFixed(1)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _IsoListTile extends StatelessWidget {
|
||||
const _IsoListTile();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<LogbookPhotoEditBloc, LogbookPhotoEditState>(
|
||||
buildWhen: (_, __) => false,
|
||||
builder: (context, state) => ListTile(
|
||||
leading: const Icon(Icons.iso_outlined),
|
||||
title: Text(S.of(context).iso),
|
||||
trailing: Text(state.iso.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _NdFilterListTile extends StatelessWidget {
|
||||
const _NdFilterListTile();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<LogbookPhotoEditBloc, LogbookPhotoEditState>(
|
||||
buildWhen: (_, __) => false,
|
||||
builder: (context, state) => ListTile(
|
||||
leading: const Icon(Icons.filter_b_and_w_outlined),
|
||||
title: Text(S.of(context).ndFilter),
|
||||
trailing: Text(state.nd.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _AperturePickerListTile extends StatelessWidget {
|
||||
const _AperturePickerListTile();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<LogbookPhotoEditBloc, LogbookPhotoEditState>(
|
||||
buildWhen: (previous, current) => previous.aperture != current.aperture,
|
||||
builder: (context, state) => PickerListTile(
|
||||
icon: Icons.camera_outlined,
|
||||
title: S.of(context).apertureValue,
|
||||
values: ApertureValue.values,
|
||||
selectedValue: state.aperture,
|
||||
onChanged: (value) {
|
||||
context.read<LogbookPhotoEditBloc>().add(LogbookPhotoApertureChangedEvent(value));
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ShutterSpeedPickerListTile extends StatelessWidget {
|
||||
const _ShutterSpeedPickerListTile();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<LogbookPhotoEditBloc, LogbookPhotoEditState>(
|
||||
buildWhen: (previous, current) => previous.shutterSpeed != current.shutterSpeed,
|
||||
builder: (context, state) => PickerListTile(
|
||||
icon: Icons.shutter_speed_outlined,
|
||||
title: S.of(context).shutterSpeedValue,
|
||||
values: ShutterSpeedValue.values,
|
||||
selectedValue: state.shutterSpeed,
|
||||
onChanged: (value) {
|
||||
context.read<LogbookPhotoEditBloc>().add(LogbookPhotoShutterSpeedChangedEvent(value));
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
64
lib/screens/logbook_photo_edit/state_logbook_photo_edit.dart
Normal file
64
lib/screens/logbook_photo_edit/state_logbook_photo_edit.dart
Normal file
|
@ -0,0 +1,64 @@
|
|||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
class LogbookPhotoEditState {
|
||||
final String id;
|
||||
final String name;
|
||||
final DateTime timestamp;
|
||||
final double ev;
|
||||
final int iso;
|
||||
final int nd;
|
||||
final Film film;
|
||||
final Coordinates? coordinates;
|
||||
final ApertureValue? aperture;
|
||||
final ShutterSpeedValue? shutterSpeed;
|
||||
final String? note;
|
||||
final bool canSave;
|
||||
final bool isLoading;
|
||||
|
||||
const LogbookPhotoEditState({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.timestamp,
|
||||
required this.ev,
|
||||
required this.iso,
|
||||
required this.nd,
|
||||
required this.film,
|
||||
this.coordinates,
|
||||
this.aperture,
|
||||
this.shutterSpeed,
|
||||
this.note,
|
||||
required this.canSave,
|
||||
this.isLoading = false,
|
||||
});
|
||||
|
||||
LogbookPhotoEditState copyWith({
|
||||
String? id,
|
||||
String? name,
|
||||
DateTime? timestamp,
|
||||
double? ev,
|
||||
int? iso,
|
||||
int? nd,
|
||||
Film? film,
|
||||
Coordinates? coordinates,
|
||||
ApertureValue? aperture,
|
||||
ShutterSpeedValue? shutterSpeed,
|
||||
String? note,
|
||||
bool? canSave,
|
||||
bool? isLoading,
|
||||
}) =>
|
||||
LogbookPhotoEditState(
|
||||
id: id ?? this.id,
|
||||
name: name ?? this.name,
|
||||
timestamp: timestamp ?? this.timestamp,
|
||||
ev: ev ?? this.ev,
|
||||
iso: iso ?? this.iso,
|
||||
nd: nd ?? this.nd,
|
||||
film: film ?? this.film,
|
||||
coordinates: coordinates ?? this.coordinates,
|
||||
aperture: aperture ?? this.aperture,
|
||||
shutterSpeed: shutterSpeed ?? this.shutterSpeed,
|
||||
note: note ?? this.note,
|
||||
canSave: canSave ?? this.canSave,
|
||||
isLoading: isLoading ?? this.isLoading,
|
||||
);
|
||||
}
|
Loading…
Reference in a new issue