Compare commits

..

1 commit

Author SHA1 Message Date
Vadim
69e6e0e251
Merge 4aed4417cb into 3aa0014b6a 2025-09-05 20:35:18 +00:00
8 changed files with 59 additions and 97 deletions

View file

@ -7,7 +7,6 @@ import 'package:lightmeter/data/models/metering_screen_layout_config.dart';
import 'package:lightmeter/data/shared_prefs_service.dart'; import 'package:lightmeter/data/shared_prefs_service.dart';
import 'package:lightmeter/generated/l10n.dart'; import 'package:lightmeter/generated/l10n.dart';
import 'package:lightmeter/res/dimens.dart'; import 'package:lightmeter/res/dimens.dart';
import 'package:lightmeter/screens/equipment_profiles/components/equipment_profile_type_picker/widget_picker_equipment_profile_type.dart';
import 'package:lightmeter/screens/metering/components/bottom_controls/widget_bottom_controls.dart'; import 'package:lightmeter/screens/metering/components/bottom_controls/widget_bottom_controls.dart';
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/equipment_profile_picker/widget_picker_equipment_profiles.dart'; import 'package:lightmeter/screens/metering/components/shared/readings_container/components/equipment_profile_picker/widget_picker_equipment_profiles.dart';
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/film_picker/widget_picker_film.dart'; import 'package:lightmeter/screens/metering/components/shared/readings_container/components/film_picker/widget_picker_film.dart';
@ -57,7 +56,8 @@ void testE2E(String description) {
/// Create Praktica + Zenitar profile from scratch /// Create Praktica + Zenitar profile from scratch
await tester.openSettings(); await tester.openSettings();
await tester.tapDescendantTextOf<SettingsScreen>(S.current.equipmentProfiles); await tester.tapDescendantTextOf<SettingsScreen>(S.current.equipmentProfiles);
await tester.addEquipmentProfile(EquipmentProfileType.regular); await tester.tap(find.byIcon(Icons.add_outlined).first);
await tester.pumpAndSettle();
await tester.enterProfileName(mockEquipmentProfiles[0].name); await tester.enterProfileName(mockEquipmentProfiles[0].name);
await tester.setIsoValues(mockEquipmentProfiles[0].isoValues); await tester.setIsoValues(mockEquipmentProfiles[0].isoValues);
await tester.setNdValues(mockEquipmentProfiles[0].ndValues); await tester.setNdValues(mockEquipmentProfiles[0].ndValues);
@ -70,7 +70,8 @@ void testE2E(String description) {
await tester.saveEdits(); await tester.saveEdits();
/// Create Praktica + Jupiter profile from Zenitar profile /// Create Praktica + Jupiter profile from Zenitar profile
await tester.editEquipmentProfile(mockEquipmentProfiles[1].name); await tester.tap(find.byIcon(Icons.edit_outlined));
await tester.pumpAndSettle();
await tester.tap(find.byIcon(Icons.copy_outlined).first); await tester.tap(find.byIcon(Icons.copy_outlined).first);
await tester.pumpAndSettle(); await tester.pumpAndSettle();
await tester.enterProfileName(mockEquipmentProfiles[1].name); await tester.enterProfileName(mockEquipmentProfiles[1].name);
@ -89,7 +90,7 @@ void testE2E(String description) {
/// Select some initial settings according to the selected gear and film /// Select some initial settings according to the selected gear and film
/// Then take a photo and verify, that exposure pairs range and EV matches the selected settings /// Then take a photo and verify, that exposure pairs range and EV matches the selected settings
await tester.openPickerAndSelect<EquipmentProfilePicker, IEquipmentProfile>(mockEquipmentProfiles[0].name); await tester.openPickerAndSelect<EquipmentProfilePicker, EquipmentProfile>(mockEquipmentProfiles[0].name);
await tester.openPickerAndSelect<FilmPicker, Film>(mockFilms[0].name); await tester.openPickerAndSelect<FilmPicker, Film>(mockFilms[0].name);
await tester.openPickerAndSelect<IsoValuePicker, IsoValue>('400'); await tester.openPickerAndSelect<IsoValuePicker, IsoValue>('400');
expectPickerTitle<EquipmentProfilePicker>(mockEquipmentProfiles[0].name); expectPickerTitle<EquipmentProfilePicker>(mockEquipmentProfiles[0].name);
@ -121,7 +122,7 @@ void testE2E(String description) {
// ); // );
/// Select another lens without ND /// Select another lens without ND
await tester.openPickerAndSelect<EquipmentProfilePicker, IEquipmentProfile>(mockEquipmentProfiles[1].name); await tester.openPickerAndSelect<EquipmentProfilePicker, EquipmentProfile>(mockEquipmentProfiles[1].name);
await tester.openPickerAndSelect<NdValuePicker, NdValue>('None'); await tester.openPickerAndSelect<NdValuePicker, NdValue>('None');
await _expectMeteringStateAndMeasure( await _expectMeteringStateAndMeasure(
tester, tester,
@ -151,7 +152,8 @@ void testE2E(String description) {
/// Delete profile /// Delete profile
await tester.openSettings(); await tester.openSettings();
await tester.tapDescendantTextOf<SettingsScreen>(S.current.equipmentProfiles); await tester.tapDescendantTextOf<SettingsScreen>(S.current.equipmentProfiles);
await tester.editEquipmentProfile(mockEquipmentProfiles[0].name); await tester.tap(find.byIcon(Icons.edit_outlined).first);
await tester.pumpAndSettle();
await tester.deleteEdits(); await tester.deleteEdits();
expect(find.text(mockEquipmentProfiles[0].name), findsNothing); expect(find.text(mockEquipmentProfiles[0].name), findsNothing);
expect(find.text(mockEquipmentProfiles[1].name), findsOneWidget); expect(find.text(mockEquipmentProfiles[1].name), findsOneWidget);

View file

@ -6,7 +6,7 @@ import 'package:lightmeter/data/models/ev_source_type.dart';
import 'package:lightmeter/data/models/metering_screen_layout_config.dart'; import 'package:lightmeter/data/models/metering_screen_layout_config.dart';
import 'package:lightmeter/data/shared_prefs_service.dart'; import 'package:lightmeter/data/shared_prefs_service.dart';
import 'package:lightmeter/generated/l10n.dart'; import 'package:lightmeter/generated/l10n.dart';
import 'package:lightmeter/screens/equipment_profiles/components/equipment_profile_type_picker/widget_picker_equipment_profile_type.dart'; import 'package:lightmeter/screens/equipment_profile_edit/screen_equipment_profile_edit.dart';
import 'package:lightmeter/screens/lightmeter_pro/screen_lightmeter_pro.dart'; import 'package:lightmeter/screens/lightmeter_pro/screen_lightmeter_pro.dart';
import 'package:lightmeter/screens/logbook_photos/screen_logbook_photos.dart'; import 'package:lightmeter/screens/logbook_photos/screen_logbook_photos.dart';
import 'package:lightmeter/screens/settings/screen_settings.dart'; import 'package:lightmeter/screens/settings/screen_settings.dart';
@ -49,7 +49,7 @@ void testGuardProTap(String description) {
await tester.navigatorPop(true); await tester.navigatorPop(true);
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(find.byType(LightmeterProScreen), findsNothing); expect(find.byType(LightmeterProScreen), findsNothing);
expect(find.byType(EquipmentProfilesTypePicker), findsOneWidget); expect(find.byType(EquipmentProfileEditScreen), findsOneWidget);
await tester.navigatorPop(); await tester.navigatorPop();
await tester.navigatorPop(); await tester.navigatorPop();

View file

@ -104,7 +104,8 @@ void testLogbook(String description) {
/// Got back and delete the equipment profile used to take the first picture /// Got back and delete the equipment profile used to take the first picture
await tester.navigatorPop(); await tester.navigatorPop();
await tester.tapDescendantTextOf<SettingsScreen>(S.current.equipmentProfiles); await tester.tapDescendantTextOf<SettingsScreen>(S.current.equipmentProfiles);
await tester.editEquipmentProfile(mockEquipmentProfiles.first.name); await tester.tap(find.byIcon(Icons.edit_outlined).first);
await tester.pumpAndSettle();
await tester.tap(find.byIcon(Icons.delete_outlined)); await tester.tap(find.byIcon(Icons.delete_outlined));
await tester.pumpAndSettle(Dimens.durationML); await tester.pumpAndSettle(Dimens.durationML);
expect(find.text(mockEquipmentProfiles[0].name), findsNothing); expect(find.text(mockEquipmentProfiles[0].name), findsNothing);

View file

@ -123,9 +123,6 @@ const defaultEquipmentProfile = EquipmentProfile(
isoValues: IsoValue.values, isoValues: IsoValue.values,
); );
final mockProfiles = [...mockEquipmentProfiles, ...mockPinholeEquipmentProfiles]
..sort((a, b) => a.name.toLowerCase().compareTo(b.name.toLowerCase()));
final mockEquipmentProfiles = [ final mockEquipmentProfiles = [
EquipmentProfile( EquipmentProfile(
id: '1', id: '1',

View file

@ -5,7 +5,6 @@ import 'package:lightmeter/application_wrapper.dart';
import 'package:lightmeter/environment.dart'; import 'package:lightmeter/environment.dart';
import 'package:lightmeter/generated/l10n.dart'; import 'package:lightmeter/generated/l10n.dart';
import 'package:lightmeter/res/dimens.dart'; import 'package:lightmeter/res/dimens.dart';
import 'package:lightmeter/screens/equipment_profiles/components/equipment_profile_type_picker/widget_picker_equipment_profile_type.dart';
import 'package:lightmeter/screens/metering/components/shared/exposure_pairs_list/widget_list_exposure_pairs.dart'; import 'package:lightmeter/screens/metering/components/shared/exposure_pairs_list/widget_list_exposure_pairs.dart';
import 'package:lightmeter/screens/metering/screen_metering.dart'; import 'package:lightmeter/screens/metering/screen_metering.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
@ -118,24 +117,3 @@ extension WidgetTesterExposurePairsListActions on WidgetTester {
); );
} }
} }
extension WidgetTesterEquipmentProfilesActions on WidgetTester {
Future<void> addEquipmentProfile(EquipmentProfileType type) async {
await tap(find.byIcon(Icons.add_outlined).first);
await pumpAndSettle();
await tap(
find.text(
switch (type) {
EquipmentProfileType.regular => S.current.camera,
EquipmentProfileType.pinhole => S.current.pinholeCamera,
},
),
);
await tapSelectButton();
}
Future<void> editEquipmentProfile(String name) async {
await tap(find.byIcon(Icons.edit_outlined).at(mockProfiles.indexWhere((p) => p.name == name)));
await pumpAndSettle();
}
}

View file

@ -1,30 +0,0 @@
import 'package:flutter/material.dart';
import 'package:lightmeter/generated/l10n.dart';
import 'package:lightmeter/screens/settings/components/shared/dialog_picker/widget_dialog_picker.dart';
enum EquipmentProfileType { regular, pinhole }
class EquipmentProfilesTypePicker extends StatelessWidget {
const EquipmentProfilesTypePicker._();
static Future<EquipmentProfileType?> show(BuildContext context) {
return showDialog<EquipmentProfileType>(
context: context,
builder: (_) => const EquipmentProfilesTypePicker._(),
);
}
@override
Widget build(BuildContext context) {
return DialogPicker<EquipmentProfileType>(
icon: Icons.camera_alt_outlined,
title: S.of(context).equipmentProfileType,
selectedValue: EquipmentProfileType.regular,
values: EquipmentProfileType.values,
titleAdapter: (context, value) => switch (value) {
EquipmentProfileType.regular => S.of(context).camera,
EquipmentProfileType.pinhole => S.of(context).pinholeCamera,
},
);
}
}

View file

@ -4,12 +4,14 @@ import 'package:lightmeter/navigation/routes.dart';
import 'package:lightmeter/providers/equipment_profile_provider.dart'; import 'package:lightmeter/providers/equipment_profile_provider.dart';
import 'package:lightmeter/res/dimens.dart'; import 'package:lightmeter/res/dimens.dart';
import 'package:lightmeter/screens/equipment_profile_edit/flow_equipment_profile_edit.dart'; import 'package:lightmeter/screens/equipment_profile_edit/flow_equipment_profile_edit.dart';
import 'package:lightmeter/screens/equipment_profiles/components/equipment_profile_type_picker/widget_picker_equipment_profile_type.dart'; import 'package:lightmeter/screens/settings/components/shared/dialog_picker/widget_dialog_picker.dart';
import 'package:lightmeter/screens/shared/sliver_placeholder/widget_sliver_placeholder.dart'; import 'package:lightmeter/screens/shared/sliver_placeholder/widget_sliver_placeholder.dart';
import 'package:lightmeter/screens/shared/sliver_screen/screen_sliver.dart'; import 'package:lightmeter/screens/shared/sliver_screen/screen_sliver.dart';
import 'package:lightmeter/utils/guard_pro_tap.dart'; import 'package:lightmeter/utils/guard_pro_tap.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
enum _EquipmentProfileType { regular, pinhole }
class EquipmentProfilesScreen extends StatefulWidget { class EquipmentProfilesScreen extends StatefulWidget {
const EquipmentProfilesScreen({super.key}); const EquipmentProfilesScreen({super.key});
@ -46,16 +48,28 @@ class _EquipmentProfilesScreenState extends State<EquipmentProfilesScreen> with
guardProTap( guardProTap(
context, context,
() { () {
EquipmentProfilesTypePicker.show(context).then((value) { showDialog<_EquipmentProfileType>(
context: context,
builder: (_) => DialogPicker<_EquipmentProfileType>(
icon: Icons.camera_alt_outlined,
title: S.of(context).equipmentProfileType,
selectedValue: _EquipmentProfileType.regular,
values: _EquipmentProfileType.values,
titleAdapter: (context, value) => switch (value) {
_EquipmentProfileType.regular => S.of(context).camera,
_EquipmentProfileType.pinhole => S.of(context).pinholeCamera,
},
),
).then((value) {
if (value != null && mounted) { if (value != null && mounted) {
Navigator.of(context).pushNamed( Navigator.of(context).pushNamed(
NavigationRoutes.equipmentProfileEditScreen.name, NavigationRoutes.equipmentProfileEditScreen.name,
arguments: switch (value) { arguments: switch (value) {
EquipmentProfileType.regular => const EquipmentProfileEditArgs( _EquipmentProfileType.regular => const EquipmentProfileEditArgs(
editType: EquipmentProfileEditType.add, editType: EquipmentProfileEditType.add,
profile: EquipmentProfilesProvider.defaultProfile, profile: EquipmentProfilesProvider.defaultProfile,
), ),
EquipmentProfileType.pinhole => EquipmentProfileEditArgs( _EquipmentProfileType.pinhole => EquipmentProfileEditArgs(
editType: EquipmentProfileEditType.add, editType: EquipmentProfileEditType.add,
profile: PinholeEquipmentProfile( profile: PinholeEquipmentProfile(
id: EquipmentProfilesProvider.defaultProfile.id, id: EquipmentProfilesProvider.defaultProfile.id,

View file

@ -218,9 +218,14 @@ void main() {
testWidgets( testWidgets(
'Generate timer screenshot', 'Generate timer screenshot',
(tester) async { (tester) async {
const timerExposurePair = ExposurePair(
ApertureValue(16, StopType.full),
ShutterSpeedValue(8, false, StopType.full),
);
await mockSharedPrefs( await mockSharedPrefs(
iso: 100,
nd: 8, nd: 8,
calibration: -2.3, calibration: -0.3,
theme: ThemeType.light, theme: ThemeType.light,
color: _lightThemeColor, color: _lightThemeColor,
); );
@ -231,22 +236,13 @@ void main() {
); );
await tester.takePhoto(); await tester.takePhoto();
final exposurePairs = MeteringContainerBuidler.buildExposureValues(
5,
StopType.third,
defaultEquipmentProfile,
);
final timerExposurePair = exposurePairs.firstWhere((e) => e.aperture == const ApertureValue(16, StopType.full));
await tester.scrollToExposurePair( await tester.scrollToExposurePair(
exposurePairs: exposurePairs, ev: 5,
exposurePair: exposurePairs.firstWhere((e) => e.aperture == const ApertureValue(16, StopType.full)), exposurePair: timerExposurePair,
); );
await tester.tap(find.text(_mockFilm.reciprocityFailure(timerExposurePair.shutterSpeed).toString()));
final correctedShutterSpeed = _mockFilm.reciprocityFailure(timerExposurePair.shutterSpeed);
await tester.tap(find.text(correctedShutterSpeed.toString()));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
await tester.mockTimerResumedState(correctedShutterSpeed); await tester.mockTimerResumedState(timerExposurePair.shutterSpeed);
await tester.takeScreenshotLight(binding, 'timer'); await tester.takeScreenshotLight(binding, 'timer');
}, },
); );
@ -261,28 +257,32 @@ extension on WidgetTester {
_takeScreenshot(binding, name, _themeDark); _takeScreenshot(binding, name, _themeDark);
Future<void> _takeScreenshot(IntegrationTestWidgetsFlutterBinding binding, String name, ThemeData theme) async { Future<void> _takeScreenshot(IntegrationTestWidgetsFlutterBinding binding, String name, ThemeData theme) async {
const deviceName = String.fromEnvironment('deviceName'); final Color backgroundColor = theme.colorScheme.surface;
if (deviceName.isNotEmpty) { await binding.takeScreenshot(
final Color backgroundColor = theme.colorScheme.surface; ScreenshotArgs(
await binding.takeScreenshot( name: name,
ScreenshotArgs( deviceName: const String.fromEnvironment('deviceName'),
name: name, platformFolder: _platformFolder,
deviceName: deviceName, backgroundColor: backgroundColor.toInt().toRadixString(16),
platformFolder: _platformFolder, isDark: theme.brightness == Brightness.dark,
backgroundColor: backgroundColor.toInt().toRadixString(16), ).toString(),
isDark: theme.brightness == Brightness.dark, );
).toString(), await pumpAndSettle();
);
await pumpAndSettle();
}
} }
} }
extension on WidgetTester { extension on WidgetTester {
Future<void> scrollToExposurePair({ Future<void> scrollToExposurePair({
required List<ExposurePair> exposurePairs, double ev = mockPhotoEv100,
EquipmentProfile equipmentProfile = defaultEquipmentProfile,
required ExposurePair exposurePair, required ExposurePair exposurePair,
}) async { }) async {
final exposurePairs = MeteringContainerBuidler.buildExposureValues(
ev,
StopType.third,
equipmentProfile,
);
await scrollUntilVisible( await scrollUntilVisible(
find.byWidgetPredicate((widget) => widget is Row && widget.key == ValueKey(exposurePairs.indexOf(exposurePair))), find.byWidgetPredicate((widget) => widget is Row && widget.key == ValueKey(exposurePairs.indexOf(exposurePair))),
56, 56,