mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2024-11-22 07:20:39 +00:00
Moved EquipmentProfileProvider
& FilmsProvider
to the main repo
This commit is contained in:
parent
069a07214c
commit
e06ee35265
19 changed files with 424 additions and 132 deletions
|
@ -27,13 +27,11 @@ import 'package:lightmeter/screens/metering/components/shared/readings_container
|
|||
import 'package:lightmeter/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_container/widget_container_equipment_profile.dart';
|
||||
import 'package:lightmeter/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/screen_equipment_profile.dart';
|
||||
import 'package:lightmeter/screens/settings/screen_settings.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class _MockSharedPreferences extends Mock implements SharedPreferences {}
|
||||
import 'mocks/paid_features_mock.dart';
|
||||
|
||||
class _MockUserPreferencesService extends Mock implements UserPreferencesService {}
|
||||
|
||||
|
@ -112,28 +110,17 @@ void main() {
|
|||
|
||||
Future<void> pumpApplication(WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
IAPProviders(
|
||||
sharedPreferences: _MockSharedPreferences(),
|
||||
child: EquipmentProfiles(
|
||||
selected: _mockEquipmentProfiles[0],
|
||||
values: _mockEquipmentProfiles,
|
||||
child: Films(
|
||||
selected: const Film('Ilford HP5+', 400),
|
||||
values: const [Film.other(), Film('Ilford HP5+', 400)],
|
||||
filmsInUse: const [Film.other(), Film('Ilford HP5+', 400)],
|
||||
child: ServicesProvider(
|
||||
environment: const Environment.prod().copyWith(hasLightSensor: true),
|
||||
userPreferencesService: mockUserPreferencesService,
|
||||
caffeineService: mockCaffeineService,
|
||||
hapticsService: mockHapticsService,
|
||||
permissionsService: mockPermissionsService,
|
||||
lightSensorService: mockLightSensorService,
|
||||
volumeEventsService: mockVolumeEventsService,
|
||||
child: const UserPreferencesProvider(
|
||||
child: Application(),
|
||||
),
|
||||
),
|
||||
),
|
||||
MockIAPProviders.purchased(
|
||||
selectedFilm: mockFilms.first,
|
||||
child: ServicesProvider(
|
||||
environment: const Environment.prod().copyWith(hasLightSensor: true),
|
||||
userPreferencesService: mockUserPreferencesService,
|
||||
caffeineService: mockCaffeineService,
|
||||
hapticsService: mockHapticsService,
|
||||
permissionsService: mockPermissionsService,
|
||||
lightSensorService: mockLightSensorService,
|
||||
volumeEventsService: mockVolumeEventsService,
|
||||
child: const UserPreferencesProvider(child: Application()),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -1,65 +1,81 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/providers/equipment_profile_provider.dart';
|
||||
import 'package:lightmeter/providers/films_provider.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class _MockSharedPreferences extends Mock implements SharedPreferences {}
|
||||
class _MockIAPStorageService extends Mock implements IAPStorageService {}
|
||||
|
||||
class MockIAPProviders extends StatelessWidget {
|
||||
class MockIAPProviders extends StatefulWidget {
|
||||
final IAPProductStatus purchaseStatus;
|
||||
final String selectedEquipmentProfileId;
|
||||
final Film selectedFilm;
|
||||
final Widget child;
|
||||
|
||||
const MockIAPProviders({
|
||||
this.selectedEquipmentProfileId = '',
|
||||
this.selectedFilm = const Film.other(),
|
||||
required this.purchaseStatus,
|
||||
required this.child,
|
||||
super.key,
|
||||
});
|
||||
|
||||
const MockIAPProviders.purchasable({
|
||||
this.selectedEquipmentProfileId = '',
|
||||
this.selectedFilm = const Film.other(),
|
||||
required this.child,
|
||||
super.key,
|
||||
}) : purchaseStatus = IAPProductStatus.purchasable;
|
||||
|
||||
const MockIAPProviders.purchased({
|
||||
this.selectedEquipmentProfileId = '',
|
||||
this.selectedFilm = const Film.other(),
|
||||
required this.child,
|
||||
super.key,
|
||||
}) : purchaseStatus = IAPProductStatus.purchased;
|
||||
|
||||
@override
|
||||
State<MockIAPProviders> createState() => _MockIAPProvidersState();
|
||||
}
|
||||
|
||||
class _MockIAPProvidersState extends State<MockIAPProviders> {
|
||||
late final _MockIAPStorageService mockIAPStorageService;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
mockIAPStorageService = _MockIAPStorageService();
|
||||
when(() => mockIAPStorageService.equipmentProfiles).thenReturn(mockEquipmentProfiles);
|
||||
when(() => mockIAPStorageService.selectedEquipmentProfileId)
|
||||
.thenReturn(widget.selectedEquipmentProfileId);
|
||||
when(() => mockIAPStorageService.filmsInUse).thenReturn(mockFilms);
|
||||
when(() => mockIAPStorageService.selectedFilm).thenReturn(widget.selectedFilm);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (purchaseStatus == IAPProductStatus.purchased) {
|
||||
return IAPProviders(
|
||||
sharedPreferences: _MockSharedPreferences(),
|
||||
child: EquipmentProfiles(
|
||||
selected: _mockEquipmentProfiles[0],
|
||||
values: _mockEquipmentProfiles,
|
||||
child: Films(
|
||||
selected: const Film('Ilford HP5+', 400),
|
||||
values: const [Film.other(), Film('Ilford HP5+', 400)],
|
||||
filmsInUse: const [Film.other(), Film('Ilford HP5+', 400)],
|
||||
child: child,
|
||||
return IAPProductsProvider(
|
||||
child: IAPProducts(
|
||||
products: [
|
||||
IAPProduct(
|
||||
storeId: IAPProductType.paidFeatures.storeId,
|
||||
status: widget.purchaseStatus,
|
||||
)
|
||||
],
|
||||
child: EquipmentProfileProvider(
|
||||
storageService: mockIAPStorageService,
|
||||
child: FilmsProvider(
|
||||
storageService: mockIAPStorageService,
|
||||
child: widget.child,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return IAPProviders(
|
||||
sharedPreferences: _MockSharedPreferences(),
|
||||
child: EquipmentProfiles(
|
||||
selected: _defaultEquipmentProfile,
|
||||
values: const [_defaultEquipmentProfile],
|
||||
child: Films(
|
||||
selected: const Film.other(),
|
||||
values: const [Film.other()],
|
||||
filmsInUse: const [Film.other()],
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const _defaultEquipmentProfile = EquipmentProfile(
|
||||
const defaultEquipmentProfile = EquipmentProfile(
|
||||
id: '',
|
||||
name: '',
|
||||
apertureValues: ApertureValue.values,
|
||||
|
@ -68,8 +84,7 @@ const _defaultEquipmentProfile = EquipmentProfile(
|
|||
isoValues: IsoValue.values,
|
||||
);
|
||||
|
||||
final _mockEquipmentProfiles = [
|
||||
_defaultEquipmentProfile,
|
||||
final mockEquipmentProfiles = [
|
||||
EquipmentProfile(
|
||||
id: '1',
|
||||
name: 'Praktica + Zenitar',
|
||||
|
@ -103,3 +118,5 @@ final _mockEquipmentProfiles = [
|
|||
isoValues: IsoValue.values,
|
||||
),
|
||||
];
|
||||
|
||||
const mockFilms = [Film('Ilford HP5+', 400)];
|
||||
|
|
|
@ -6,6 +6,8 @@ import 'package:lightmeter/data/permissions_service.dart';
|
|||
import 'package:lightmeter/data/shared_prefs_service.dart';
|
||||
import 'package:lightmeter/data/volume_events_service.dart';
|
||||
import 'package:lightmeter/environment.dart';
|
||||
import 'package:lightmeter/providers/equipment_profile_provider.dart';
|
||||
import 'package:lightmeter/providers/films_provider.dart';
|
||||
import 'package:lightmeter/providers/services_provider.dart';
|
||||
import 'package:lightmeter/providers/user_preferences_provider.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
|
@ -27,8 +29,8 @@ class ApplicationWrapper extends StatelessWidget {
|
|||
]),
|
||||
builder: (_, snapshot) {
|
||||
if (snapshot.data != null) {
|
||||
return IAPProviders(
|
||||
sharedPreferences: snapshot.data![0] as SharedPreferences,
|
||||
final iapService = IAPStorageService(snapshot.data![0] as SharedPreferences);
|
||||
return IAPProductsProvider(
|
||||
child: ServicesProvider(
|
||||
caffeineService: const CaffeineService(),
|
||||
environment: env.copyWith(hasLightSensor: snapshot.data![1] as bool),
|
||||
|
@ -38,8 +40,14 @@ class ApplicationWrapper extends StatelessWidget {
|
|||
userPreferencesService:
|
||||
UserPreferencesService(snapshot.data![0] as SharedPreferences),
|
||||
volumeEventsService: const VolumeEventsService(LocalPlatform()),
|
||||
child: UserPreferencesProvider(
|
||||
child: child,
|
||||
child: EquipmentProfileProvider(
|
||||
storageService: iapService,
|
||||
child: FilmsProvider(
|
||||
storageService: iapService,
|
||||
child: UserPreferencesProvider(
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
130
lib/providers/equipment_profile_provider.dart
Normal file
130
lib/providers/equipment_profile_provider.dart
Normal file
|
@ -0,0 +1,130 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/utils/selectable_provider.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
class EquipmentProfileProvider extends StatefulWidget {
|
||||
final IAPStorageService storageService;
|
||||
final Widget child;
|
||||
|
||||
const EquipmentProfileProvider({
|
||||
required this.storageService,
|
||||
required this.child,
|
||||
super.key,
|
||||
});
|
||||
|
||||
static EquipmentProfileProviderState of(BuildContext context) {
|
||||
return context.findAncestorStateOfType<EquipmentProfileProviderState>()!;
|
||||
}
|
||||
|
||||
@override
|
||||
State<EquipmentProfileProvider> createState() => EquipmentProfileProviderState();
|
||||
}
|
||||
|
||||
class EquipmentProfileProviderState extends State<EquipmentProfileProvider> {
|
||||
static const EquipmentProfile _defaultProfile = EquipmentProfile(
|
||||
id: '',
|
||||
name: '',
|
||||
apertureValues: ApertureValue.values,
|
||||
ndValues: NdValue.values,
|
||||
shutterSpeedValues: ShutterSpeedValue.values,
|
||||
isoValues: IsoValue.values,
|
||||
);
|
||||
|
||||
List<EquipmentProfile> _customProfiles = [];
|
||||
String _selectedId = '';
|
||||
|
||||
EquipmentProfile get _selectedProfile => _customProfiles.firstWhere(
|
||||
(e) => e.id == _selectedId,
|
||||
orElse: () => _defaultProfile,
|
||||
);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_selectedId = widget.storageService.selectedEquipmentProfileId;
|
||||
_customProfiles = widget.storageService.equipmentProfiles;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return EquipmentProfiles(
|
||||
values: [
|
||||
_defaultProfile,
|
||||
if (IAPProducts.isPurchased(context, IAPProductType.paidFeatures)) ..._customProfiles,
|
||||
],
|
||||
selected: IAPProducts.isPurchased(context, IAPProductType.paidFeatures)
|
||||
? _selectedProfile
|
||||
: _defaultProfile,
|
||||
child: widget.child,
|
||||
);
|
||||
}
|
||||
|
||||
void setProfile(EquipmentProfile data) {
|
||||
if (_selectedId != data.id) {
|
||||
setState(() {
|
||||
_selectedId = data.id;
|
||||
});
|
||||
widget.storageService.selectedEquipmentProfileId = _selectedProfile.id;
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a default equipment profile
|
||||
void addProfile(String name, [EquipmentProfile? copyFrom]) {
|
||||
_customProfiles.add(
|
||||
EquipmentProfile(
|
||||
id: const Uuid().v1(),
|
||||
name: name,
|
||||
apertureValues: copyFrom?.apertureValues ?? ApertureValue.values,
|
||||
ndValues: copyFrom?.ndValues ?? NdValue.values,
|
||||
shutterSpeedValues: copyFrom?.shutterSpeedValues ?? ShutterSpeedValue.values,
|
||||
isoValues: copyFrom?.isoValues ?? IsoValue.values,
|
||||
),
|
||||
);
|
||||
_refreshSavedProfiles();
|
||||
}
|
||||
|
||||
void updateProdile(EquipmentProfile data) {
|
||||
final indexToUpdate = _customProfiles.indexWhere((element) => element.id == data.id);
|
||||
if (indexToUpdate >= 0) {
|
||||
_customProfiles[indexToUpdate] = data;
|
||||
_refreshSavedProfiles();
|
||||
}
|
||||
}
|
||||
|
||||
void deleteProfile(EquipmentProfile data) {
|
||||
if (data.id == _selectedId) {
|
||||
_selectedId = _defaultProfile.id;
|
||||
widget.storageService.selectedEquipmentProfileId = _defaultProfile.id;
|
||||
}
|
||||
_customProfiles.remove(data);
|
||||
_refreshSavedProfiles();
|
||||
}
|
||||
|
||||
void _refreshSavedProfiles() {
|
||||
widget.storageService.equipmentProfiles = _customProfiles;
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
|
||||
class EquipmentProfiles extends SelectableInheritedModel<EquipmentProfile> {
|
||||
const EquipmentProfiles({
|
||||
super.key,
|
||||
required super.values,
|
||||
required super.selected,
|
||||
required super.child,
|
||||
});
|
||||
|
||||
/// [_defaultProfile] + profiles created by the user
|
||||
static List<EquipmentProfile> of(BuildContext context) {
|
||||
return InheritedModel.inheritFrom<EquipmentProfiles>(context, aspect: SelectableAspect.list)!
|
||||
.values;
|
||||
}
|
||||
|
||||
static EquipmentProfile selectedOf(BuildContext context) {
|
||||
return InheritedModel.inheritFrom<EquipmentProfiles>(context,
|
||||
aspect: SelectableAspect.selected,)!
|
||||
.selected;
|
||||
}
|
||||
}
|
102
lib/providers/films_provider.dart
Normal file
102
lib/providers/films_provider.dart
Normal file
|
@ -0,0 +1,102 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/utils/selectable_provider.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
class FilmsProvider extends StatefulWidget {
|
||||
final IAPStorageService storageService;
|
||||
final Widget child;
|
||||
|
||||
const FilmsProvider({
|
||||
required this.storageService,
|
||||
required this.child,
|
||||
super.key,
|
||||
});
|
||||
|
||||
static FilmsProviderState of(BuildContext context) {
|
||||
return context.findAncestorStateOfType<FilmsProviderState>()!;
|
||||
}
|
||||
|
||||
@override
|
||||
State<FilmsProvider> createState() => FilmsProviderState();
|
||||
}
|
||||
|
||||
class FilmsProviderState extends State<FilmsProvider> {
|
||||
late List<Film> _filmsInUse;
|
||||
late Film _selected;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_filmsInUse = widget.storageService.filmsInUse;
|
||||
_selected = widget.storageService.selectedFilm;
|
||||
_discardSelectedIfNotIncluded();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Films(
|
||||
values: films,
|
||||
filmsInUse: [
|
||||
const Film.other(),
|
||||
if (IAPProducts.isPurchased(context, IAPProductType.paidFeatures)) ..._filmsInUse,
|
||||
],
|
||||
selected: IAPProducts.isPurchased(context, IAPProductType.paidFeatures)
|
||||
? _selected
|
||||
: const Film.other(),
|
||||
child: widget.child,
|
||||
);
|
||||
}
|
||||
|
||||
void setFilm(Film film) {
|
||||
if (_selected != film) {
|
||||
_selected = film;
|
||||
widget.storageService.selectedFilm = film;
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
|
||||
void saveFilms(List<Film> films) {
|
||||
_filmsInUse = films;
|
||||
widget.storageService.filmsInUse = films;
|
||||
_discardSelectedIfNotIncluded();
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
void _discardSelectedIfNotIncluded() {
|
||||
if (_selected != const Film.other() && !_filmsInUse.contains(_selected)) {
|
||||
_selected = const Film.other();
|
||||
widget.storageService.selectedFilm = const Film.other();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Films extends SelectableInheritedModel<Film> {
|
||||
final List<Film> filmsInUse;
|
||||
|
||||
const Films({
|
||||
super.key,
|
||||
required super.values,
|
||||
required this.filmsInUse,
|
||||
required super.selected,
|
||||
required super.child,
|
||||
});
|
||||
|
||||
/// [Film.other()] + all the custom fields with actual reciprocity formulas
|
||||
static List<Film> of(BuildContext context) {
|
||||
return InheritedModel.inheritFrom<Films>(context)!.values;
|
||||
}
|
||||
|
||||
/// [Film.other()] + films in use selected by user
|
||||
static List<Film> inUseOf<T>(BuildContext context) {
|
||||
return InheritedModel.inheritFrom<Films>(
|
||||
context,
|
||||
aspect: SelectableAspect.list,
|
||||
)!
|
||||
.filmsInUse;
|
||||
}
|
||||
|
||||
static Film selectedOf(BuildContext context) {
|
||||
return InheritedModel.inheritFrom<Films>(context, aspect: SelectableAspect.selected)!.selected;
|
||||
}
|
||||
}
|
|
@ -1,11 +1,10 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/data/models/exposure_pair.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/providers/films_provider.dart';
|
||||
import 'package:lightmeter/res/dimens.dart';
|
||||
|
||||
import 'package:lightmeter/screens/metering/components/shared/exposure_pairs_list/components/exposure_pairs_list_item/widget_item_list_exposure_pairs.dart';
|
||||
import 'package:lightmeter/screens/shared/icon_placeholder/widget_icon_placeholder.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
|
||||
class ExposurePairsList extends StatelessWidget {
|
||||
final List<ExposurePair> exposurePairs;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/providers/equipment_profile_provider.dart';
|
||||
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/widget_picker_dialog_animated.dart';
|
||||
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/reading_value_container/widget_container_reading_value.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
class EquipmentProfilePicker extends StatelessWidget {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/data/models/exposure_pair.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/providers/films_provider.dart';
|
||||
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/reading_value_container/widget_container_reading_value.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
|
||||
class ExtremeExposurePairsContainer extends StatelessWidget {
|
||||
final ExposurePair? fastest;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/providers/films_provider.dart';
|
||||
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/widget_picker_dialog_animated.dart';
|
||||
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/reading_value_container/widget_container_reading_value.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
class FilmPicker extends StatelessWidget {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/data/models/exposure_pair.dart';
|
||||
import 'package:lightmeter/data/models/metering_screen_layout_config.dart';
|
||||
import 'package:lightmeter/providers/equipment_profile_provider.dart';
|
||||
import 'package:lightmeter/providers/user_preferences_provider.dart';
|
||||
import 'package:lightmeter/res/dimens.dart';
|
||||
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/equipment_profile_picker/widget_picker_equipment_profiles.dart';
|
||||
|
@ -8,7 +9,6 @@ import 'package:lightmeter/screens/metering/components/shared/readings_container
|
|||
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/iso_picker/widget_picker_iso.dart';
|
||||
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/nd_picker/widget_picker_nd.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
class ReadingsContainer extends StatelessWidget {
|
||||
|
|
|
@ -5,6 +5,8 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||
import 'package:lightmeter/data/models/ev_source_type.dart';
|
||||
import 'package:lightmeter/data/models/exposure_pair.dart';
|
||||
import 'package:lightmeter/data/models/metering_screen_layout_config.dart';
|
||||
import 'package:lightmeter/providers/equipment_profile_provider.dart';
|
||||
import 'package:lightmeter/providers/films_provider.dart';
|
||||
import 'package:lightmeter/providers/services_provider.dart';
|
||||
import 'package:lightmeter/providers/user_preferences_provider.dart';
|
||||
import 'package:lightmeter/screens/metering/bloc_metering.dart';
|
||||
|
@ -15,7 +17,6 @@ import 'package:lightmeter/screens/metering/event_metering.dart';
|
|||
import 'package:lightmeter/screens/metering/state_metering.dart';
|
||||
import 'package:lightmeter/screens/metering/utils/listener_metering_layout_feature.dart';
|
||||
import 'package:lightmeter/screens/metering/utils/listsner_equipment_profiles.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
class MeteringScreen extends StatelessWidget {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
import 'package:lightmeter/providers/equipment_profile_provider.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
class EquipmentProfileListener extends StatefulWidget {
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
|
||||
import 'package:lightmeter/providers/equipment_profile_provider.dart';
|
||||
import 'package:lightmeter/res/dimens.dart';
|
||||
import 'package:lightmeter/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_container/widget_container_equipment_profile.dart';
|
||||
import 'package:lightmeter/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_name_dialog/widget_dialog_equipment_profile_name.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_iap/m3_lightmeter_iap.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
class EquipmentProfilesScreen extends StatefulWidget {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/providers/films_provider.dart';
|
||||
import 'package:lightmeter/screens/settings/components/shared/dialog_filter/widget_dialog_filter.dart';
|
||||
import 'package:lightmeter/screens/settings/components/shared/iap_list_tile/widget_list_tile_iap.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
class FilmsListTile extends StatelessWidget {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/data/models/metering_screen_layout_config.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/providers/equipment_profile_provider.dart';
|
||||
import 'package:lightmeter/providers/user_preferences_provider.dart';
|
||||
import 'package:lightmeter/res/dimens.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
|
||||
class MeteringScreenLayoutFeaturesDialog extends StatefulWidget {
|
||||
const MeteringScreenLayoutFeaturesDialog({super.key});
|
||||
|
|
32
lib/utils/selectable_provider.dart
Normal file
32
lib/utils/selectable_provider.dart
Normal file
|
@ -0,0 +1,32 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
enum SelectableAspect { list, selected }
|
||||
|
||||
class SelectableInheritedModel<T> extends InheritedModel<SelectableAspect> {
|
||||
const SelectableInheritedModel({
|
||||
super.key,
|
||||
required this.values,
|
||||
required this.selected,
|
||||
required super.child,
|
||||
});
|
||||
|
||||
final List<T> values;
|
||||
final T selected;
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(SelectableInheritedModel oldWidget) => true;
|
||||
|
||||
@override
|
||||
bool updateShouldNotifyDependent(
|
||||
SelectableInheritedModel oldWidget,
|
||||
Set<SelectableAspect> dependencies,
|
||||
) {
|
||||
if (dependencies.contains(SelectableAspect.list)) {
|
||||
return true;
|
||||
} else if (dependencies.contains(SelectableAspect.selected)) {
|
||||
return selected != oldWidget.selected;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,7 +26,7 @@ dependencies:
|
|||
m3_lightmeter_iap:
|
||||
git:
|
||||
url: "https://github.com/vodemn/m3_lightmeter_iap"
|
||||
ref: v0.4.0
|
||||
ref: v0.5.0
|
||||
m3_lightmeter_resources:
|
||||
git:
|
||||
url: "https://github.com/vodemn/m3_lightmeter_resources"
|
||||
|
|
|
@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:lightmeter/data/models/exposure_pair.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/providers/films_provider.dart';
|
||||
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/extreme_exposure_pairs_container/widget_container_extreme_exposure_pairs.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
import '../../../../../application_mock.dart';
|
||||
|
|
|
@ -1,75 +1,37 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/providers/films_provider.dart';
|
||||
import 'package:lightmeter/res/dimens.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/shared/reading_value_container/widget_container_reading_value.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
|
||||
import '../../../../../application_mock.dart';
|
||||
|
||||
class _MockIAPStorageService extends Mock implements IAPStorageService {}
|
||||
|
||||
void main() {
|
||||
group('Film push/pull label', () {
|
||||
testWidgets(
|
||||
'Film.other()',
|
||||
(tester) async {
|
||||
await tester.pumpApplication(_films[0]);
|
||||
_expectReadingValueContainerText(S.current.film);
|
||||
_expectReadingValueContainerText(S.current.none);
|
||||
},
|
||||
);
|
||||
late final _MockIAPStorageService mockIAPStorageService;
|
||||
|
||||
testWidgets(
|
||||
'Film with the same ISO',
|
||||
(tester) async {
|
||||
await tester.pumpApplication(_films[2]);
|
||||
_expectReadingValueContainerText(S.current.film);
|
||||
_expectReadingValueContainerText(_films[2].name);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'Film with greater ISO',
|
||||
(tester) async {
|
||||
await tester.pumpApplication(_films[3]);
|
||||
_expectReadingValueContainerText(S.current.filmPull);
|
||||
_expectReadingValueContainerText(_films[3].name);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'Film with lower ISO',
|
||||
(tester) async {
|
||||
await tester.pumpApplication(_films[1]);
|
||||
_expectReadingValueContainerText(S.current.filmPush);
|
||||
_expectReadingValueContainerText(_films[1].name);
|
||||
},
|
||||
);
|
||||
setUpAll(() {
|
||||
mockIAPStorageService = _MockIAPStorageService();
|
||||
when(() => mockIAPStorageService.filmsInUse).thenReturn(_films);
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'Film picker shows only films in use',
|
||||
(tester) async {
|
||||
await tester.pumpApplication(_films[1]);
|
||||
await tester.tap(find.byType(FilmPicker));
|
||||
await tester.pumpAndSettle(Dimens.durationL);
|
||||
_expectRadioListTile(S.current.none);
|
||||
_expectRadioListTile(_films[1].name);
|
||||
_expectRadioListTile(_films[2].name);
|
||||
_expectRadioListTile(_films[3].name);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
extension WidgetTesterActions on WidgetTester {
|
||||
Future<void> pumpApplication(Film selectedFilm) async {
|
||||
await pumpWidget(
|
||||
FilmsProvider(
|
||||
child: Films(
|
||||
values: _films,
|
||||
filmsInUse: _films.sublist(0, _films.length - 1),
|
||||
selected: selectedFilm,
|
||||
Future<void> pumpApplication(WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
IAPProducts(
|
||||
products: [
|
||||
IAPProduct(
|
||||
storeId: IAPProductType.paidFeatures.storeId,
|
||||
status: IAPProductStatus.purchased,
|
||||
)
|
||||
],
|
||||
child: FilmsProvider(
|
||||
storageService: mockIAPStorageService,
|
||||
child: const WidgetTestApplicationMock(
|
||||
child: Row(
|
||||
children: [
|
||||
|
@ -82,12 +44,67 @@ extension WidgetTesterActions on WidgetTester {
|
|||
),
|
||||
),
|
||||
);
|
||||
await pumpAndSettle();
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
group('Film push/pull label', () {
|
||||
testWidgets(
|
||||
'Film.other()',
|
||||
(tester) async {
|
||||
when(() => mockIAPStorageService.selectedFilm).thenReturn(const Film.other());
|
||||
await pumpApplication(tester);
|
||||
_expectReadingValueContainerText(S.current.film);
|
||||
_expectReadingValueContainerText(S.current.none);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'Film with the same ISO',
|
||||
(tester) async {
|
||||
when(() => mockIAPStorageService.selectedFilm).thenReturn(_films[1]);
|
||||
await pumpApplication(tester);
|
||||
_expectReadingValueContainerText(S.current.film);
|
||||
_expectReadingValueContainerText(_films[1].name);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'Film with greater ISO',
|
||||
(tester) async {
|
||||
when(() => mockIAPStorageService.selectedFilm).thenReturn(_films[2]);
|
||||
await pumpApplication(tester);
|
||||
_expectReadingValueContainerText(S.current.filmPull);
|
||||
_expectReadingValueContainerText(_films[2].name);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'Film with lower ISO',
|
||||
(tester) async {
|
||||
when(() => mockIAPStorageService.selectedFilm).thenReturn(_films[0]);
|
||||
await pumpApplication(tester);
|
||||
_expectReadingValueContainerText(S.current.filmPush);
|
||||
_expectReadingValueContainerText(_films[0].name);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'Film picker shows only films in use',
|
||||
(tester) async {
|
||||
when(() => mockIAPStorageService.selectedFilm).thenReturn(_films[0]);
|
||||
await pumpApplication(tester);
|
||||
await tester.tap(find.byType(FilmPicker));
|
||||
await tester.pumpAndSettle(Dimens.durationL);
|
||||
_expectRadioListTile(S.current.none);
|
||||
_expectRadioListTile(_films[1].name);
|
||||
_expectRadioListTile(_films[2].name);
|
||||
_expectRadioListTile(_films[3].name);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const _films = [
|
||||
Film.other(),
|
||||
Film('ISO 100 Film', 100),
|
||||
Film('ISO 400 Film', 400),
|
||||
Film('ISO 800 Film', 800),
|
||||
|
|
Loading…
Reference in a new issue