ML-258 Allow to set equipment profile and film for logbook photo (#259)
* added film and equipment profile picker to logbook edit * unified camera icon usages * Update settings_screen.png * save equipment profile and film when taking a photo * extended logbook integration test * cover cascade deletion * updated dependencies * Update logbook_photos_provider_test.dart * regenerated screenshots * refined integration tests * update stub pubspec * fixed lens zoom on screenshots
|
@ -12,7 +12,7 @@ dependencies:
|
|||
m3_lightmeter_resources:
|
||||
git:
|
||||
url: "https://github.com/vodemn/m3_lightmeter_resources"
|
||||
ref: v2.3.0
|
||||
ref: v2.4.0
|
||||
shared_preferences:
|
||||
|
||||
dev_dependencies:
|
||||
|
|
|
@ -3,6 +3,8 @@ import 'package:flutter_test/flutter_test.dart';
|
|||
import 'package:lightmeter/data/models/ev_source_type.dart';
|
||||
import 'package:lightmeter/data/shared_prefs_service.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/res/dimens.dart';
|
||||
import 'package:lightmeter/screens/logbook_photo_edit/components/picker_list_tile/widget_list_tile_picker.dart';
|
||||
import 'package:lightmeter/screens/logbook_photo_edit/screen_logbook_photo_edit.dart';
|
||||
import 'package:lightmeter/screens/logbook_photos/components/grid_tile/widget_grid_tile_logbook_photo.dart';
|
||||
import 'package:lightmeter/screens/settings/components/shared/dialog_picker/widget_dialog_picker.dart';
|
||||
|
@ -28,8 +30,8 @@ void testLogbook(String description) {
|
|||
description,
|
||||
(tester) async {
|
||||
await tester.pumpApplication(
|
||||
equipmentProfiles: {},
|
||||
predefinedFilms: mockFilms.toTogglableMap(),
|
||||
selectedEquipmentProfileId: mockEquipmentProfiles.first.id,
|
||||
selectedFilmId: mockFilms.first.id,
|
||||
customFilms: {},
|
||||
);
|
||||
await tester.takePhoto();
|
||||
|
@ -45,6 +47,9 @@ void testLogbook(String description) {
|
|||
await tester.tap(find.byType(LogbookPhotoGridTile).first);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.ensureVisible(find.text(mockEquipmentProfiles.first.name));
|
||||
await tester.ensureVisible(find.text(mockFilms.first.name));
|
||||
|
||||
/// Add a note, select aperture value and shutter speed value
|
||||
await tester.enterText(
|
||||
find.descendant(
|
||||
|
@ -58,6 +63,26 @@ void testLogbook(String description) {
|
|||
await tester.pumpAndSettle();
|
||||
await tester.openPickerAndSelect<ApertureValue>(S.current.apertureValue, 'f/5.6');
|
||||
await tester.openPickerAndSelect<ShutterSpeedValue>(S.current.shutterSpeedValue, '1/125');
|
||||
expect(
|
||||
find.descendant(
|
||||
of: find.byWidgetPredicate(
|
||||
(widget) => widget is PickerListTile && widget.title == S.current.equipmentProfile,
|
||||
),
|
||||
matching: find.text(mockEquipmentProfiles.first.name),
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(
|
||||
find.descendant(
|
||||
of: find.byWidgetPredicate(
|
||||
(widget) => widget is PickerListTile && widget.title == S.current.film,
|
||||
),
|
||||
matching: find.text(mockFilms.first.name),
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
await tester.openPickerAndSelect<Film>(S.current.film, S.current.notSet);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
/// Save the edits
|
||||
await tester.tap(find.byIcon(Icons.save_outlined));
|
||||
|
@ -76,11 +101,32 @@ void testLogbook(String description) {
|
|||
/// Verify that only one photo is present
|
||||
expect(find.byType(LogbookPhotoGridTile), findsOneWidget);
|
||||
|
||||
/// Got back and delete the equipment profile used to take the first picture
|
||||
await tester.navigatorPop();
|
||||
await tester.tapDescendantTextOf<SettingsScreen>(S.current.equipmentProfiles);
|
||||
await tester.tap(find.byIcon(Icons.edit_outlined).first);
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.byIcon(Icons.delete_outlined));
|
||||
await tester.pumpAndSettle(Dimens.durationML);
|
||||
expect(find.text(mockEquipmentProfiles[0].name), findsNothing);
|
||||
expect(find.text(mockEquipmentProfiles[1].name), findsOneWidget);
|
||||
await tester.navigatorPop();
|
||||
|
||||
/// Open photo again
|
||||
await tester.tapDescendantTextOf<SettingsScreen>(S.current.logbook);
|
||||
await tester.tap(find.byType(LogbookPhotoGridTile).first);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
/// Verify the edits were saved
|
||||
expect(
|
||||
find.descendant(
|
||||
of: find.byWidgetPredicate(
|
||||
(widget) => widget is PickerListTile && widget.title == S.current.equipmentProfile,
|
||||
),
|
||||
matching: find.text(S.current.notSet),
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.text('Test note'), findsOneWidget);
|
||||
expect(find.text('f/5.6'), findsOneWidget);
|
||||
expect(find.text('1/125'), findsOneWidget);
|
||||
|
@ -101,7 +147,7 @@ extension on WidgetTester {
|
|||
await tap(find.text(title));
|
||||
await pumpAndSettle();
|
||||
final dialogFinder = find.byType(DialogPicker<Optional<V>>);
|
||||
final listTileFinder = find.text(valueToSelect);
|
||||
final listTileFinder = find.descendant(of: dialogFinder, matching: find.text(valueToSelect));
|
||||
await scrollUntilVisible(
|
||||
listTileFinder,
|
||||
56,
|
||||
|
|
|
@ -114,6 +114,7 @@ class FilmsProviderState extends State<FilmsProvider> {
|
|||
}
|
||||
|
||||
enum _FilmsModelAspect {
|
||||
all,
|
||||
customFilms,
|
||||
predefinedFilms,
|
||||
filmsInUse,
|
||||
|
@ -134,6 +135,14 @@ class Films extends InheritedModel<_FilmsModelAspect> {
|
|||
required super.child,
|
||||
});
|
||||
|
||||
static List<Film> of<T>(BuildContext context) {
|
||||
final model = InheritedModel.inheritFrom<Films>(context, aspect: _FilmsModelAspect.all)!;
|
||||
return [
|
||||
...model.customFilms.values.map((e) => e.value),
|
||||
...model.predefinedFilms.values.map((e) => e.value),
|
||||
];
|
||||
}
|
||||
|
||||
static List<Film> predefinedFilmsOf<T>(BuildContext context) {
|
||||
return InheritedModel.inheritFrom<Films>(context, aspect: _FilmsModelAspect.predefinedFilms)!
|
||||
.predefinedFilms
|
||||
|
@ -171,10 +180,12 @@ class Films extends InheritedModel<_FilmsModelAspect> {
|
|||
bool updateShouldNotifyDependent(Films oldWidget, Set<_FilmsModelAspect> dependencies) {
|
||||
return (dependencies.contains(_FilmsModelAspect.selected) && oldWidget.selected != selected) ||
|
||||
((dependencies.contains(_FilmsModelAspect.predefinedFilms) ||
|
||||
dependencies.contains(_FilmsModelAspect.filmsInUse)) &&
|
||||
dependencies.contains(_FilmsModelAspect.filmsInUse) ||
|
||||
dependencies.contains(_FilmsModelAspect.all)) &&
|
||||
const DeepCollectionEquality().equals(oldWidget.predefinedFilms, predefinedFilms)) ||
|
||||
((dependencies.contains(_FilmsModelAspect.customFilms) ||
|
||||
dependencies.contains(_FilmsModelAspect.filmsInUse)) &&
|
||||
dependencies.contains(_FilmsModelAspect.filmsInUse) ||
|
||||
dependencies.contains(_FilmsModelAspect.all)) &&
|
||||
const DeepCollectionEquality().equals(oldWidget.customFilms, customFilms));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ import 'package:collection/collection.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/data/geolocation_service.dart';
|
||||
import 'package:lightmeter/platform_config.dart';
|
||||
import 'package:lightmeter/providers/equipment_profile_provider.dart';
|
||||
import 'package:lightmeter/providers/films_provider.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';
|
||||
|
@ -74,6 +76,13 @@ class LogbookPhotosProviderState extends State<LogbookPhotosProvider> {
|
|||
required int nd,
|
||||
}) async {
|
||||
if (context.isPro && _isEnabled) {
|
||||
final equipmentProfile = EquipmentProfiles.selectedOf(context);
|
||||
final equipmentProfileId =
|
||||
equipmentProfile == EquipmentProfilesProvider.defaultProfile ? null : equipmentProfile.id;
|
||||
|
||||
final selectedFilm = Films.selectedOf(context);
|
||||
final filmId = selectedFilm == const FilmStub() ? null : selectedFilm.id;
|
||||
|
||||
final coordinates = await widget.geolocationService.getCurrentPosition();
|
||||
|
||||
final photo = LogbookPhoto(
|
||||
|
@ -84,6 +93,8 @@ class LogbookPhotosProviderState extends State<LogbookPhotosProvider> {
|
|||
iso: iso,
|
||||
nd: nd,
|
||||
coordinates: coordinates,
|
||||
equipmentProfileId: equipmentProfileId,
|
||||
filmId: filmId,
|
||||
);
|
||||
await widget.storageService.addPhoto(photo);
|
||||
_photos[photo.id] = photo;
|
||||
|
|
|
@ -25,6 +25,8 @@ class LogbookPhotoEditBloc extends Bloc<LogbookPhotoEditEvent, LogbookPhotoEditS
|
|||
coordinates: photo.coordinates,
|
||||
aperture: photo.apertureValue,
|
||||
shutterSpeed: photo.shutterSpeedValue,
|
||||
equipmentProfileId: photo.equipmentProfileId,
|
||||
filmId: photo.filmId,
|
||||
note: photo.note,
|
||||
canSave: false,
|
||||
),
|
||||
|
@ -36,6 +38,10 @@ class LogbookPhotoEditBloc extends Bloc<LogbookPhotoEditEvent, LogbookPhotoEditS
|
|||
await _onApertureChanged(e, emit);
|
||||
case final LogbookPhotoShutterSpeedChangedEvent e:
|
||||
await _onShutterSpeedChanged(e, emit);
|
||||
case final LogbookPhotoEquipmentProfileChangedEvent e:
|
||||
await _onEquipmentProfileChanged(e, emit);
|
||||
case final LogbookPhotoFilmChangedEvent e:
|
||||
await _onFilmChanged(e, emit);
|
||||
case final LogbookPhotoNoteChangedEvent e:
|
||||
await _onNoteChanged(e, emit);
|
||||
case LogbookPhotoSaveEvent():
|
||||
|
@ -67,6 +73,26 @@ class LogbookPhotoEditBloc extends Bloc<LogbookPhotoEditEvent, LogbookPhotoEditS
|
|||
);
|
||||
}
|
||||
|
||||
Future<void> _onEquipmentProfileChanged(LogbookPhotoEquipmentProfileChangedEvent event, Emitter emit) async {
|
||||
_newPhoto = _newPhoto.copyWith(equipmentProfileId: Optional(event.equipmentProfile?.id));
|
||||
emit(
|
||||
state.copyWith(
|
||||
equipmentProfileId: Optional(event.equipmentProfile?.id),
|
||||
canSave: _canSave(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onFilmChanged(LogbookPhotoFilmChangedEvent event, Emitter emit) async {
|
||||
_newPhoto = _newPhoto.copyWith(filmId: Optional(event.film?.id));
|
||||
emit(
|
||||
state.copyWith(
|
||||
filmId: Optional(event.film?.id),
|
||||
canSave: _canSave(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onNoteChanged(LogbookPhotoNoteChangedEvent event, Emitter emit) async {
|
||||
_newPhoto = _newPhoto.copyWith(note: event.note);
|
||||
emit(
|
||||
|
|
|
@ -3,11 +3,12 @@ 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 {
|
||||
class PickerListTile<T> extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final String title;
|
||||
final T? selectedValue;
|
||||
final List<T> values;
|
||||
final String Function(T) titleAdapter;
|
||||
final ValueChanged<Optional<T>> onChanged;
|
||||
|
||||
const PickerListTile({
|
||||
|
@ -15,6 +16,7 @@ class PickerListTile<T extends PhotographyValue> extends StatelessWidget {
|
|||
required this.title,
|
||||
required this.selectedValue,
|
||||
required this.values,
|
||||
required this.titleAdapter,
|
||||
required this.onChanged,
|
||||
super.key,
|
||||
});
|
||||
|
@ -24,7 +26,7 @@ class PickerListTile<T extends PhotographyValue> extends StatelessWidget {
|
|||
return ListTile(
|
||||
leading: Icon(icon),
|
||||
title: Text(title),
|
||||
trailing: Text(selectedValue?.toString() ?? S.of(context).notSet),
|
||||
trailing: Text(_titleAdapter(context, selectedValue)),
|
||||
onTap: () {
|
||||
showDialog<Optional<T>>(
|
||||
context: context,
|
||||
|
@ -36,7 +38,7 @@ class PickerListTile<T extends PhotographyValue> extends StatelessWidget {
|
|||
const Optional(null),
|
||||
...values.toSet().map((e) => Optional(e)),
|
||||
],
|
||||
titleAdapter: (context, value) => value.value?.toString() ?? S.of(context).notSet,
|
||||
titleAdapter: (context, value) => _titleAdapter(context, value.value),
|
||||
),
|
||||
).then((value) {
|
||||
if (value != null) {
|
||||
|
@ -46,4 +48,8 @@ class PickerListTile<T extends PhotographyValue> extends StatelessWidget {
|
|||
},
|
||||
);
|
||||
}
|
||||
|
||||
String _titleAdapter(BuildContext context, T? value) {
|
||||
return value != null ? titleAdapter(value) : S.of(context).notSet;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,18 @@ class LogbookPhotoNoteChangedEvent extends LogbookPhotoEditEvent {
|
|||
const LogbookPhotoNoteChangedEvent(this.note);
|
||||
}
|
||||
|
||||
class LogbookPhotoEquipmentProfileChangedEvent extends LogbookPhotoEditEvent {
|
||||
final EquipmentProfile? equipmentProfile;
|
||||
|
||||
const LogbookPhotoEquipmentProfileChangedEvent(this.equipmentProfile);
|
||||
}
|
||||
|
||||
class LogbookPhotoFilmChangedEvent extends LogbookPhotoEditEvent {
|
||||
final Film? film;
|
||||
|
||||
const LogbookPhotoFilmChangedEvent(this.film);
|
||||
}
|
||||
|
||||
class LogbookPhotoSaveEvent extends LogbookPhotoEditEvent {
|
||||
const LogbookPhotoSaveEvent();
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
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/providers/equipment_profile_provider.dart';
|
||||
import 'package:lightmeter/providers/films_provider.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/coordinates_list_tile/widget_list_tile_coordinates_logbook_photo.dart';
|
||||
|
@ -73,6 +76,8 @@ class _LogbookPhotoEditScreenState extends State<LogbookPhotoEditScreen> {
|
|||
child: Column(
|
||||
children: [
|
||||
LogbookPhotoCoordinatesListTile(),
|
||||
_EquipmentProfilePickerListTile(),
|
||||
_FilmPickerListTile(),
|
||||
_NoteListTile(),
|
||||
_EvListTile(),
|
||||
_IsoListTile(),
|
||||
|
@ -224,6 +229,7 @@ class _AperturePickerListTile extends StatelessWidget {
|
|||
title: S.of(context).apertureValue,
|
||||
values: ApertureValue.values,
|
||||
selectedValue: state.aperture,
|
||||
titleAdapter: (value) => value.toString(),
|
||||
onChanged: (value) {
|
||||
context.read<LogbookPhotoEditBloc>().add(LogbookPhotoApertureChangedEvent(value.value));
|
||||
},
|
||||
|
@ -244,6 +250,7 @@ class _ShutterSpeedPickerListTile extends StatelessWidget {
|
|||
title: S.of(context).shutterSpeedValue,
|
||||
values: ShutterSpeedValue.values,
|
||||
selectedValue: state.shutterSpeed,
|
||||
titleAdapter: (value) => value.toString(),
|
||||
onChanged: (value) {
|
||||
context.read<LogbookPhotoEditBloc>().add(LogbookPhotoShutterSpeedChangedEvent(value.value));
|
||||
},
|
||||
|
@ -251,3 +258,45 @@ class _ShutterSpeedPickerListTile extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _EquipmentProfilePickerListTile extends StatelessWidget {
|
||||
const _EquipmentProfilePickerListTile();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<LogbookPhotoEditBloc, LogbookPhotoEditState>(
|
||||
buildWhen: (previous, current) => previous.equipmentProfileId != current.equipmentProfileId,
|
||||
builder: (context, state) => PickerListTile(
|
||||
icon: Icons.camera_alt_outlined,
|
||||
title: S.of(context).equipmentProfile,
|
||||
values: EquipmentProfiles.of(context).skip(1).toList(growable: false),
|
||||
selectedValue: EquipmentProfiles.of(context).firstWhereOrNull((e) => e.id == state.equipmentProfileId),
|
||||
titleAdapter: (value) => value.name,
|
||||
onChanged: (value) {
|
||||
context.read<LogbookPhotoEditBloc>().add(LogbookPhotoEquipmentProfileChangedEvent(value.value));
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _FilmPickerListTile extends StatelessWidget {
|
||||
const _FilmPickerListTile();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<LogbookPhotoEditBloc, LogbookPhotoEditState>(
|
||||
buildWhen: (previous, current) => previous.filmId != current.filmId,
|
||||
builder: (context, state) => PickerListTile(
|
||||
icon: Icons.camera_roll_outlined,
|
||||
title: S.of(context).film,
|
||||
values: Films.of(context),
|
||||
selectedValue: Films.of(context).firstWhereOrNull((e) => e.id == state.filmId),
|
||||
titleAdapter: (value) => value.name,
|
||||
onChanged: (value) {
|
||||
context.read<LogbookPhotoEditBloc>().add(LogbookPhotoFilmChangedEvent(value.value));
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ class LogbookPhotoEditState {
|
|||
final Coordinates? coordinates;
|
||||
final ApertureValue? aperture;
|
||||
final ShutterSpeedValue? shutterSpeed;
|
||||
final String? equipmentProfileId;
|
||||
final String? filmId;
|
||||
final String? note;
|
||||
final bool canSave;
|
||||
final bool isLoading;
|
||||
|
@ -24,6 +26,8 @@ class LogbookPhotoEditState {
|
|||
this.coordinates,
|
||||
this.aperture,
|
||||
this.shutterSpeed,
|
||||
this.equipmentProfileId,
|
||||
this.filmId,
|
||||
this.note,
|
||||
required this.canSave,
|
||||
this.isLoading = false,
|
||||
|
@ -33,6 +37,8 @@ class LogbookPhotoEditState {
|
|||
String? name,
|
||||
Optional<ApertureValue>? aperture,
|
||||
Optional<ShutterSpeedValue>? shutterSpeed,
|
||||
Optional<String>? equipmentProfileId,
|
||||
Optional<String>? filmId,
|
||||
String? note,
|
||||
bool? canSave,
|
||||
bool? isLoading,
|
||||
|
@ -46,6 +52,8 @@ class LogbookPhotoEditState {
|
|||
nd: nd,
|
||||
aperture: aperture != null ? aperture.value : this.aperture,
|
||||
shutterSpeed: shutterSpeed != null ? shutterSpeed.value : this.shutterSpeed,
|
||||
equipmentProfileId: equipmentProfileId != null ? equipmentProfileId.value : this.equipmentProfileId,
|
||||
filmId: filmId != null ? filmId.value : this.filmId,
|
||||
note: note ?? this.note,
|
||||
canSave: canSave ?? this.canSave,
|
||||
isLoading: isLoading ?? this.isLoading,
|
||||
|
|
|
@ -26,7 +26,7 @@ class _EquipmentProfilePickerState extends State<EquipmentProfilePicker> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedDialogPicker<EquipmentProfile>(
|
||||
icon: Icons.camera_outlined,
|
||||
icon: Icons.camera_alt_outlined,
|
||||
title: S.of(context).equipmentProfile,
|
||||
selectedValue: EquipmentProfiles.selectedOf(context),
|
||||
values: EquipmentProfiles.inUseOf(context),
|
||||
|
|
|
@ -11,7 +11,7 @@ class CameraFeaturesListTile extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListTile(
|
||||
leading: const Icon(Icons.camera_alt_outlined),
|
||||
leading: const Icon(Icons.camera_enhance_outlined),
|
||||
title: Text(S.of(context).cameraFeatures),
|
||||
onTap: () {
|
||||
UserPreferencesProvider.cameraConfigOf(context).entries.map(
|
||||
|
@ -26,7 +26,7 @@ class CameraFeaturesListTile extends StatelessWidget {
|
|||
showDialog(
|
||||
context: context,
|
||||
builder: (_) => DialogSwitch<CameraFeature>(
|
||||
icon: Icons.camera_alt_outlined,
|
||||
icon: Icons.camera_enhance_outlined,
|
||||
title: S.of(context).cameraFeatures,
|
||||
items: [
|
||||
DialogSwitchListItem(
|
||||
|
|
|
@ -8,7 +8,7 @@ class EquipmentProfilesListTile extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListTile(
|
||||
leading: const Icon(Icons.camera_outlined),
|
||||
leading: const Icon(Icons.camera_alt_outlined),
|
||||
title: Text(S.of(context).equipmentProfiles),
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed(NavigationRoutes.equipmentProfilesListScreen.name);
|
||||
|
|
12
pubspec.lock
|
@ -861,20 +861,20 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: "v4.0.1"
|
||||
resolved-ref: ce431af9fc86694b3bd8d1e2a2a988d9b6184b17
|
||||
ref: "v4.1.0"
|
||||
resolved-ref: "15adfa4f6fea06a6c62c58f5171a41813058040c"
|
||||
url: "https://github.com/vodemn/m3_lightmeter_iap"
|
||||
source: git
|
||||
version: "4.0.1+34"
|
||||
version: "4.1.0+35"
|
||||
m3_lightmeter_resources:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: "v2.3.1"
|
||||
resolved-ref: "8b39ac1927b791652618509abe0391f844229b93"
|
||||
ref: "v2.4.0"
|
||||
resolved-ref: cc9ae43a7859398a6ab2ecf7f8713153dbfd99cd
|
||||
url: "https://github.com/vodemn/m3_lightmeter_resources"
|
||||
source: git
|
||||
version: "2.3.1+12"
|
||||
version: "2.4.0+13"
|
||||
macros:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -33,11 +33,11 @@ dependencies:
|
|||
m3_lightmeter_iap:
|
||||
git:
|
||||
url: "https://github.com/vodemn/m3_lightmeter_iap"
|
||||
ref: v4.0.1
|
||||
ref: v4.1.0
|
||||
m3_lightmeter_resources:
|
||||
git:
|
||||
url: "https://github.com/vodemn/m3_lightmeter_resources"
|
||||
ref: v2.3.1
|
||||
ref: v2.4.0
|
||||
map_launcher: 3.2.0
|
||||
material_color_utilities: 0.12.0
|
||||
package_info_plus: 8.1.3
|
||||
|
@ -68,10 +68,6 @@ dev_dependencies:
|
|||
|
||||
dependency_overrides:
|
||||
geolocator_android: 4.6.1
|
||||
m3_lightmeter_resources:
|
||||
git:
|
||||
url: "https://github.com/vodemn/m3_lightmeter_resources"
|
||||
ref: v2.3.1
|
||||
material_color_utilities: 0.11.1
|
||||
|
||||
flutter:
|
||||
|
|
|
@ -36,6 +36,31 @@ import 'models/screenshot_args.dart';
|
|||
|
||||
//https://stackoverflow.com/a/67186625/13167574
|
||||
|
||||
final _mockEquipmentProfile = EquipmentProfile(
|
||||
id: '1',
|
||||
name: 'Praktica + Zenitar',
|
||||
apertureValues: ApertureValue.values.sublist(
|
||||
ApertureValue.values.indexOf(const ApertureValue(1.7, StopType.half)),
|
||||
ApertureValue.values.indexOf(const ApertureValue(16, StopType.full)) + 1,
|
||||
),
|
||||
ndValues: NdValue.values.sublist(0, 3),
|
||||
shutterSpeedValues: ShutterSpeedValue.values.sublist(
|
||||
ShutterSpeedValue.values.indexOf(const ShutterSpeedValue(1000, true, StopType.full)),
|
||||
ShutterSpeedValue.values.indexOf(const ShutterSpeedValue(1, false, StopType.full)) + 1,
|
||||
),
|
||||
isoValues: const [
|
||||
IsoValue(50, StopType.full),
|
||||
IsoValue(100, StopType.full),
|
||||
IsoValue(200, StopType.full),
|
||||
IsoValue(250, StopType.third),
|
||||
IsoValue(400, StopType.full),
|
||||
IsoValue(500, StopType.third),
|
||||
IsoValue(800, StopType.full),
|
||||
IsoValue(1600, StopType.full),
|
||||
IsoValue(3200, StopType.full),
|
||||
],
|
||||
lensZoom: 50 / (Platform.isAndroid ? 24 : 26),
|
||||
);
|
||||
const _mockFilm = FilmExponential(id: '1', name: 'Ilford HP5+', iso: 400, exponent: 1.34);
|
||||
final Color _lightThemeColor = primaryColorsList[5];
|
||||
final Color _darkThemeColor = primaryColorsList[3];
|
||||
|
@ -109,6 +134,8 @@ void main() {
|
|||
testWidgets('Generate light theme screenshots', (tester) async {
|
||||
await mockSharedPrefs(theme: ThemeType.light, color: _lightThemeColor);
|
||||
await tester.pumpApplication(
|
||||
equipmentProfiles: [_mockEquipmentProfile].toTogglableMap(),
|
||||
selectedEquipmentProfileId: _mockEquipmentProfile.id,
|
||||
predefinedFilms: [_mockFilm].toTogglableMap(),
|
||||
customFilms: {},
|
||||
selectedFilmId: _mockFilm.id,
|
||||
|
@ -159,6 +186,8 @@ void main() {
|
|||
nd: photo.nd,
|
||||
apertureValue: const ApertureValue(2.0, StopType.full),
|
||||
shutterSpeedValue: photo.shutterSpeedValue,
|
||||
equipmentProfileId: _mockEquipmentProfile.id,
|
||||
filmId: _mockFilm.id,
|
||||
),
|
||||
);
|
||||
await tester.tapDescendantTextOf<SettingsScreen>(S.current.logbook);
|
||||
|
|
Before Width: | Height: | Size: 466 KiB After Width: | Height: | Size: 469 KiB |
Before Width: | Height: | Size: 221 KiB After Width: | Height: | Size: 221 KiB |
Before Width: | Height: | Size: 737 KiB After Width: | Height: | Size: 572 KiB |
Before Width: | Height: | Size: 238 KiB After Width: | Height: | Size: 248 KiB |
Before Width: | Height: | Size: 230 KiB After Width: | Height: | Size: 229 KiB |
Before Width: | Height: | Size: 469 KiB After Width: | Height: | Size: 479 KiB |
Before Width: | Height: | Size: 224 KiB After Width: | Height: | Size: 224 KiB |
Before Width: | Height: | Size: 218 KiB After Width: | Height: | Size: 218 KiB |
Before Width: | Height: | Size: 343 KiB After Width: | Height: | Size: 346 KiB |
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 164 KiB |
Before Width: | Height: | Size: 535 KiB After Width: | Height: | Size: 416 KiB |
Before Width: | Height: | Size: 187 KiB After Width: | Height: | Size: 186 KiB |
Before Width: | Height: | Size: 339 KiB After Width: | Height: | Size: 346 KiB |
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 163 KiB |
Before Width: | Height: | Size: 508 KiB After Width: | Height: | Size: 512 KiB |
Before Width: | Height: | Size: 232 KiB After Width: | Height: | Size: 232 KiB |
Before Width: | Height: | Size: 792 KiB After Width: | Height: | Size: 617 KiB |
Before Width: | Height: | Size: 260 KiB After Width: | Height: | Size: 260 KiB |
Before Width: | Height: | Size: 499 KiB After Width: | Height: | Size: 506 KiB |
Before Width: | Height: | Size: 231 KiB After Width: | Height: | Size: 228 KiB |
|
@ -1,6 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:lightmeter/data/geolocation_service.dart';
|
||||
import 'package:lightmeter/providers/equipment_profile_provider.dart';
|
||||
import 'package:lightmeter/providers/films_provider.dart';
|
||||
import 'package:lightmeter/providers/logbook_photos_provider.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
@ -36,6 +38,13 @@ void main() {
|
|||
when(() => storageService.deletePhoto(any<String>())).thenAnswer((_) async {});
|
||||
when(() => storageService.getPhotos()).thenAnswer((_) => Future.value(_customPhotos));
|
||||
|
||||
when(() => storageService.selectedEquipmentProfileId).thenReturn('');
|
||||
when(() => storageService.getEquipmentProfiles()).thenAnswer((_) => Future.value({}));
|
||||
|
||||
when(() => storageService.selectedFilmId).thenReturn(const FilmStub().id);
|
||||
when(() => storageService.getPredefinedFilms()).thenAnswer((_) => Future.value({}));
|
||||
when(() => storageService.getCustomFilms()).thenAnswer((_) => Future.value({}));
|
||||
|
||||
when(() => geolocationService.getCurrentPosition()).thenAnswer((_) => Future.value());
|
||||
});
|
||||
|
||||
|
@ -47,10 +56,16 @@ void main() {
|
|||
await tester.pumpWidget(
|
||||
IAPProducts(
|
||||
isPro: isPro,
|
||||
child: LogbookPhotosProvider(
|
||||
child: EquipmentProfilesProvider(
|
||||
storageService: storageService,
|
||||
geolocationService: geolocationService,
|
||||
child: const _Application(),
|
||||
child: FilmsProvider(
|
||||
storageService: storageService,
|
||||
child: LogbookPhotosProvider(
|
||||
storageService: storageService,
|
||||
geolocationService: geolocationService,
|
||||
child: const _Application(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -47,7 +47,7 @@ void main() {
|
|||
await pumpApplication(tester);
|
||||
expectReadingValueContainerText(S.current.equipmentProfile);
|
||||
await tester.openAnimatedPicker<EquipmentProfilePicker>();
|
||||
expect(find.byIcon(Icons.camera_outlined), findsOneWidget);
|
||||
expect(find.byIcon(Icons.camera_alt_outlined), findsOneWidget);
|
||||
expectDialogPickerText<EquipmentProfile>(S.current.equipmentProfile);
|
||||
},
|
||||
);
|
||||
|
|
Before Width: | Height: | Size: 474 KiB After Width: | Height: | Size: 468 KiB |