This commit is contained in:
Vadim 2024-11-11 13:00:09 +01:00
parent 57fbeeb88f
commit 7d1c1ebc9f
13 changed files with 47 additions and 51 deletions

View file

@ -1,7 +1,7 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
typedef SelectableFilm<T extends Film> = ({T film, bool isUsed}); typedef SelectableValue<T extends Film> = ({T film, bool isUsed});
class FilmsStorageService { class FilmsStorageService {
FilmsStorageService(); FilmsStorageService();
@ -22,11 +22,11 @@ class FilmsStorageService {
Future<void> deleteFilm(FilmExponential _) async {} Future<void> deleteFilm(FilmExponential _) async {}
Future<Map<String, SelectableFilm<Film>>> getPredefinedFilms() async { Future<Map<String, SelectableValue<Film>>> getPredefinedFilms() async {
return const {}; return const {};
} }
Future<Map<String, SelectableFilm<FilmExponential>>> getCustomFilms() async { Future<Map<String, SelectableValue<FilmExponential>>> getCustomFilms() async {
return const {}; return const {};
} }
} }

View file

@ -18,6 +18,7 @@ import 'package:lightmeter/screens/settings/components/shared/dialog_range_picke
import 'package:lightmeter/screens/settings/screen_settings.dart'; import 'package:lightmeter/screens/settings/screen_settings.dart';
import 'package:lightmeter/utils/double_to_zoom.dart'; import 'package:lightmeter/utils/double_to_zoom.dart';
import 'package:lightmeter/utils/platform_utils.dart'; import 'package:lightmeter/utils/platform_utils.dart';
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@ -49,7 +50,7 @@ void testE2E(String description) {
(tester) async { (tester) async {
await tester.pumpApplication( await tester.pumpApplication(
equipmentProfiles: {}, equipmentProfiles: {},
predefinedFilms: mockFilms.toFilmsMap(isUsed: true), predefinedFilms: mockFilms.toSelectableMap(),
customFilms: {}, customFilms: {},
); );

View file

@ -10,24 +10,24 @@ class _MockEquipmentProfilesStorageService extends Mock implements EquipmentProf
class _MockFilmsStorageService extends Mock implements FilmsStorageService {} class _MockFilmsStorageService extends Mock implements FilmsStorageService {}
class MockIAPProviders extends StatefulWidget { class MockIAPProviders extends StatefulWidget {
final Map<String, EquipmentProfile> equipmentProfiles; final SelectableMap<EquipmentProfile> equipmentProfiles;
final String selectedEquipmentProfileId; final String selectedEquipmentProfileId;
final Map<String, SelectableFilm<Film>> predefinedFilms; final Map<String, SelectableValue<Film>> predefinedFilms;
final Map<String, SelectableFilm<FilmExponential>> customFilms; final Map<String, SelectableValue<FilmExponential>> customFilms;
final String selectedFilmId; final String selectedFilmId;
final Widget child; final Widget child;
MockIAPProviders({ MockIAPProviders({
Map<String, EquipmentProfile>? equipmentProfiles, SelectableMap<EquipmentProfile>? equipmentProfiles,
this.selectedEquipmentProfileId = '', this.selectedEquipmentProfileId = '',
Map<String, SelectableFilm<Film>>? predefinedFilms, Map<String, SelectableValue<Film>>? predefinedFilms,
Map<String, SelectableFilm<FilmExponential>>? customFilms, Map<String, SelectableValue<FilmExponential>>? customFilms,
String? selectedFilmId, String? selectedFilmId,
required this.child, required this.child,
super.key, super.key,
}) : equipmentProfiles = equipmentProfiles ?? mockEquipmentProfiles.toProfilesMap(), }) : equipmentProfiles = equipmentProfiles ?? mockEquipmentProfiles.toSelectableMap(),
predefinedFilms = predefinedFilms ?? mockFilms.toFilmsMap(), predefinedFilms = predefinedFilms ?? mockFilms.toSelectableMap(),
customFilms = customFilms ?? mockFilms.toFilmsMap(), customFilms = customFilms ?? mockFilms.toSelectableMap(),
selectedFilmId = selectedFilmId ?? const FilmStub().id; selectedFilmId = selectedFilmId ?? const FilmStub().id;
@override @override
@ -155,15 +155,6 @@ const mockFilms = [
_FilmMultiplying(id: '4', name: 'Mock film 4', iso: 1200, reciprocityMultiplier: 1.5), _FilmMultiplying(id: '4', name: 'Mock film 4', iso: 1200, reciprocityMultiplier: 1.5),
]; ];
extension EquipmentProfileMapper on List<EquipmentProfile> {
Map<String, EquipmentProfile> toProfilesMap() => Map.fromEntries(map((e) => MapEntry(e.id, e)));
}
extension FilmMapper on List<Film> {
Map<String, ({T film, bool isUsed})> toFilmsMap<T extends Film>({bool isUsed = true}) =>
Map.fromEntries(map((e) => MapEntry(e.id, (film: e as T, isUsed: isUsed))));
}
class _FilmMultiplying extends FilmExponential { class _FilmMultiplying extends FilmExponential {
final double reciprocityMultiplier; final double reciprocityMultiplier;

View file

@ -20,10 +20,10 @@ const mockPhotoEv100 = 8.3;
extension WidgetTesterCommonActions on WidgetTester { extension WidgetTesterCommonActions on WidgetTester {
Future<void> pumpApplication({ Future<void> pumpApplication({
IAPProductStatus productStatus = IAPProductStatus.purchased, IAPProductStatus productStatus = IAPProductStatus.purchased,
Map<String, EquipmentProfile>? equipmentProfiles, SelectableMap<EquipmentProfile>? equipmentProfiles,
String selectedEquipmentProfileId = '', String selectedEquipmentProfileId = '',
Map<String, SelectableFilm<Film>>? predefinedFilms, Map<String, SelectableValue<Film>>? predefinedFilms,
Map<String, SelectableFilm<FilmExponential>>? customFilms, Map<String, SelectableValue<FilmExponential>>? customFilms,
String selectedFilmId = '', String selectedFilmId = '',
}) async { }) async {
await pumpWidget( await pumpWidget(

View file

@ -34,7 +34,7 @@ class EquipmentProfilesProvider extends StatefulWidget {
} }
class EquipmentProfilesProviderState extends State<EquipmentProfilesProvider> { class EquipmentProfilesProviderState extends State<EquipmentProfilesProvider> {
final Map<String, EquipmentProfile> _customProfiles = {}; final SelectableMap<EquipmentProfile> _customProfiles = {};
String _selectedId = ''; String _selectedId = '';
EquipmentProfile get _selectedProfile => _customProfiles[_selectedId] ?? EquipmentProfilesProvider.defaultProfile; EquipmentProfile get _selectedProfile => _customProfiles[_selectedId] ?? EquipmentProfilesProvider.defaultProfile;

View file

@ -25,11 +25,11 @@ class FilmsProvider extends StatefulWidget {
} }
class FilmsProviderState extends State<FilmsProvider> { class FilmsProviderState extends State<FilmsProvider> {
final Map<String, SelectableFilm<Film>> predefinedFilms = {}; final Map<String, SelectableValue<Film>> predefinedFilms = {};
final Map<String, SelectableFilm<FilmExponential>> customFilms = {}; final Map<String, SelectableValue<FilmExponential>> customFilms = {};
String _selectedId = ''; String _selectedId = '';
Film get _selectedFilm => customFilms[_selectedId]?.film ?? predefinedFilms[_selectedId]?.film ?? const FilmStub(); Film get _selectedFilm => customFilms[_selectedId]?.value ?? predefinedFilms[_selectedId]?.value ?? const FilmStub();
@override @override
void initState() { void initState() {
@ -60,9 +60,9 @@ class FilmsProviderState extends State<FilmsProvider> {
Future<void> toggleFilm(Film film, bool enabled) async { Future<void> toggleFilm(Film film, bool enabled) async {
if (predefinedFilms.containsKey(film.id)) { if (predefinedFilms.containsKey(film.id)) {
predefinedFilms[film.id] = (film: film, isUsed: enabled); predefinedFilms[film.id] = (value: film, isUsed: enabled);
} else if (customFilms.containsKey(film.id)) { } else if (customFilms.containsKey(film.id)) {
customFilms[film.id] = (film: film as FilmExponential, isUsed: enabled); customFilms[film.id] = (value: film as FilmExponential, isUsed: enabled);
} else { } else {
return; return;
} }
@ -84,13 +84,13 @@ class FilmsProviderState extends State<FilmsProvider> {
Future<void> addCustomFilm(FilmExponential film) async { Future<void> addCustomFilm(FilmExponential film) async {
// ignore: avoid_redundant_argument_values // ignore: avoid_redundant_argument_values
await widget.storageService.addFilm(film, isUsed: true); await widget.storageService.addFilm(film, isUsed: true);
customFilms[film.id] = (film: film, isUsed: true); customFilms[film.id] = (value: film, isUsed: true);
setState(() {}); setState(() {});
} }
Future<void> updateCustomFilm(FilmExponential film) async { Future<void> updateCustomFilm(FilmExponential film) async {
await widget.storageService.updateFilm(film); await widget.storageService.updateFilm(film);
customFilms[film.id] = (film: film, isUsed: customFilms[film.id]!.isUsed); customFilms[film.id] = (value: film, isUsed: customFilms[film.id]!.isUsed);
setState(() {}); setState(() {});
} }
@ -121,10 +121,10 @@ enum _FilmsModelAspect {
} }
class Films extends InheritedModel<_FilmsModelAspect> { class Films extends InheritedModel<_FilmsModelAspect> {
final Map<String, SelectableFilm<Film>> predefinedFilms; final Map<String, SelectableValue<Film>> predefinedFilms;
@protected @protected
final Map<String, SelectableFilm<FilmExponential>> customFilms; final Map<String, SelectableValue<FilmExponential>> customFilms;
final Film selected; final Film selected;
const Films({ const Films({
@ -138,7 +138,7 @@ class Films extends InheritedModel<_FilmsModelAspect> {
return InheritedModel.inheritFrom<Films>(context, aspect: _FilmsModelAspect.predefinedFilms)! return InheritedModel.inheritFrom<Films>(context, aspect: _FilmsModelAspect.predefinedFilms)!
.predefinedFilms .predefinedFilms
.values .values
.map((value) => value.film) .map((value) => value.value)
.toList(); .toList();
} }
@ -146,7 +146,7 @@ class Films extends InheritedModel<_FilmsModelAspect> {
return InheritedModel.inheritFrom<Films>(context, aspect: _FilmsModelAspect.customFilms)! return InheritedModel.inheritFrom<Films>(context, aspect: _FilmsModelAspect.customFilms)!
.customFilms .customFilms
.values .values
.map((value) => value.film) .map((value) => value.value)
.toList(); .toList();
} }
@ -155,8 +155,8 @@ class Films extends InheritedModel<_FilmsModelAspect> {
final model = InheritedModel.inheritFrom<Films>(context, aspect: _FilmsModelAspect.filmsInUse)!; final model = InheritedModel.inheritFrom<Films>(context, aspect: _FilmsModelAspect.filmsInUse)!;
return [ return [
const FilmStub(), const FilmStub(),
...model.customFilms.values.where((e) => e.isUsed).map((e) => e.film), ...model.customFilms.values.where((e) => e.isUsed).map((e) => e.value),
...model.predefinedFilms.values.where((e) => e.isUsed).map((e) => e.film), ...model.predefinedFilms.values.where((e) => e.isUsed).map((e) => e.value),
]; ];
} }

View file

@ -89,9 +89,12 @@ class _EquipmentProfilesListBuilder extends StatelessWidget {
top: index == 0 ? Dimens.paddingM : 0.0, top: index == 0 ? Dimens.paddingM : 0.0,
bottom: index == values.length - 1 ? Dimens.paddingM : 0.0, bottom: index == values.length - 1 ? Dimens.paddingM : 0.0,
), ),
child: ListTile( child: CheckboxListTile(
title: Text(values[index].name), title: Text(values[index].name),
trailing: IconButton( controlAffinity: ListTileControlAffinity.leading,
value: false,
onChanged: (value) {},
secondary: IconButton(
onPressed: () => onEdit(values[index]), onPressed: () => onEdit(values[index]),
icon: const Icon(Icons.edit), icon: const Icon(Icons.edit),
), ),

View file

@ -23,6 +23,7 @@ import 'package:lightmeter/screens/settings/screen_settings.dart';
import 'package:lightmeter/screens/shared/animated_circular_button/widget_button_circular_animated.dart'; import 'package:lightmeter/screens/shared/animated_circular_button/widget_button_circular_animated.dart';
import 'package:lightmeter/screens/timer/screen_timer.dart'; import 'package:lightmeter/screens/timer/screen_timer.dart';
import 'package:lightmeter/utils/platform_utils.dart'; import 'package:lightmeter/utils/platform_utils.dart';
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@ -92,7 +93,7 @@ void main() {
testWidgets('Generate light theme screenshots', (tester) async { testWidgets('Generate light theme screenshots', (tester) async {
await mockSharedPrefs(theme: ThemeType.light, color: _lightThemeColor); await mockSharedPrefs(theme: ThemeType.light, color: _lightThemeColor);
await tester.pumpApplication( await tester.pumpApplication(
predefinedFilms: [_mockFilm].toFilmsMap(), predefinedFilms: [_mockFilm].toSelectableMap(),
customFilms: {}, customFilms: {},
selectedFilmId: _mockFilm.id, selectedFilmId: _mockFilm.id,
); );
@ -132,7 +133,7 @@ void main() {
(tester) async { (tester) async {
await mockSharedPrefs(theme: ThemeType.dark, color: _darkThemeColor); await mockSharedPrefs(theme: ThemeType.dark, color: _darkThemeColor);
await tester.pumpApplication( await tester.pumpApplication(
predefinedFilms: [_mockFilm].toFilmsMap(), predefinedFilms: [_mockFilm].toSelectableMap(),
customFilms: {}, customFilms: {},
selectedFilmId: _mockFilm.id, selectedFilmId: _mockFilm.id,
); );
@ -157,7 +158,7 @@ void main() {
color: _lightThemeColor, color: _lightThemeColor,
); );
await tester.pumpApplication( await tester.pumpApplication(
predefinedFilms: [_mockFilm].toFilmsMap(), predefinedFilms: [_mockFilm].toSelectableMap(),
customFilms: {}, customFilms: {},
selectedFilmId: _mockFilm.id, selectedFilmId: _mockFilm.id,
); );

View file

@ -27,7 +27,7 @@ void main() {
), ),
).thenAnswer((_) async {}); ).thenAnswer((_) async {});
when(() => storageService.deleteProfile(any<String>())).thenAnswer((_) async {}); when(() => storageService.deleteProfile(any<String>())).thenAnswer((_) async {});
when(() => storageService.getProfiles()).thenAnswer((_) => Future.value(_customProfiles.toProfilesMap())); when(() => storageService.getProfiles()).thenAnswer((_) => Future.value(_customProfiles.toSelectableMap()));
}); });
tearDown(() { tearDown(() {
@ -66,7 +66,7 @@ void main() {
() { () {
setUp(() { setUp(() {
when(() => storageService.selectedEquipmentProfileId).thenReturn(_customProfiles.first.id); when(() => storageService.selectedEquipmentProfileId).thenReturn(_customProfiles.first.id);
when(() => storageService.getProfiles()).thenAnswer((_) => Future.value(_customProfiles.toProfilesMap())); when(() => storageService.getProfiles()).thenAnswer((_) => Future.value(_customProfiles.toSelectableMap()));
}); });
testWidgets( testWidgets(

View file

@ -305,6 +305,6 @@ const mockCustomFilms = [
]; ];
extension on List<Film> { extension on List<Film> {
Map<String, ({T film, bool isUsed})> toFilmsMap<T extends Film>() => Map<String, ({T value, bool isUsed})> toFilmsMap<T extends Film>() =>
Map.fromEntries(map((e) => MapEntry(e.id, (film: e as T, isUsed: true)))); Map.fromEntries(map((e) => MapEntry(e.id, (value: e as T, isUsed: true))));
} }

View file

@ -18,7 +18,7 @@ void main() {
setUpAll(() { setUpAll(() {
storageService = _MockEquipmentProfilesStorageService(); storageService = _MockEquipmentProfilesStorageService();
when(() => storageService.getProfiles()).thenAnswer((_) async => _mockEquipmentProfiles.toProfilesMap()); when(() => storageService.getProfiles()).thenAnswer((_) async => _mockEquipmentProfiles.toSelectableMap());
when(() => storageService.selectedEquipmentProfileId).thenReturn(''); when(() => storageService.selectedEquipmentProfileId).thenReturn('');
}); });

View file

@ -18,7 +18,7 @@ void main() {
setUpAll(() { setUpAll(() {
mockFilmsStorageService = _MockFilmsStorageService(); mockFilmsStorageService = _MockFilmsStorageService();
when(() => mockFilmsStorageService.getPredefinedFilms()).thenAnswer( when(() => mockFilmsStorageService.getPredefinedFilms()).thenAnswer(
(_) => Future.value(Map.fromEntries(_films.map((e) => MapEntry(e.id, (film: e, isUsed: true))))), (_) => Future.value(Map.fromEntries(_films.map((e) => MapEntry(e.id, (value: e, isUsed: true))))),
); );
when(() => mockFilmsStorageService.getCustomFilms()).thenAnswer( when(() => mockFilmsStorageService.getCustomFilms()).thenAnswer(
(_) => Future.value({}), (_) => Future.value({}),

View file

@ -26,7 +26,7 @@ void main() {
), ),
).thenAnswer((_) async {}); ).thenAnswer((_) async {});
when(() => storageService.deleteProfile(any<String>())).thenAnswer((_) async {}); when(() => storageService.deleteProfile(any<String>())).thenAnswer((_) async {});
when(() => storageService.getProfiles()).thenAnswer((_) => Future.value(_customProfiles.toProfilesMap())); when(() => storageService.getProfiles()).thenAnswer((_) => Future.value(_customProfiles.toSelectableMap()));
}); });
tearDown(() { tearDown(() {