Compare commits

..

No commits in common. "a5f211ad4bb19c5d7f36194e3e887c6b8e4b3a09" and "960c2360d2ea2f7b126dc7b14aa2071a8fda7bb3" have entirely different histories.

16 changed files with 130 additions and 295 deletions

View file

@ -63,13 +63,23 @@ 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');
_expectPickerListTileValue(
S.current.equipmentProfile,
mockEquipmentProfiles.first.name,
expect(
find.descendant(
of: find.byWidgetPredicate(
(widget) => widget is PickerListTile && widget.title == S.current.equipmentProfile,
),
matching: find.text(mockEquipmentProfiles.first.name),
),
findsOneWidget,
);
_expectPickerListTileValue(
S.current.film,
mockFilms.first.name,
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();
@ -107,9 +117,14 @@ void testLogbook(String description) {
await tester.pumpAndSettle();
/// Verify the edits were saved
_expectPickerListTileValue(
S.current.equipmentProfile,
S.current.notSet,
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);
@ -126,138 +141,6 @@ void testLogbook(String description) {
);
}
@isTest
void testLogbookEquipmentProfileChanges(String description) {
setUp(() async {
SharedPreferences.setMockInitialValues({
UserPreferencesService.evSourceTypeKey: EvSourceType.camera.index,
UserPreferencesService.seenChangelogVersionKey: await const PlatformUtils().version,
});
});
testWidgets(
description,
(tester) async {
await tester.pumpApplication(
selectedEquipmentProfileId: mockEquipmentProfiles.first.id,
selectedFilmId: mockFilms.first.id,
customFilms: {},
);
await tester.takePhoto();
await tester.openSettings();
await tester.tapDescendantTextOf<SettingsScreen>(S.current.logbook);
await tester.tap(find.byType(LogbookPhotoGridTile).first);
await tester.pumpAndSettle();
await tester.ensureVisible(find.text(mockEquipmentProfiles.first.name));
_expectPickerListTileValue(
S.current.equipmentProfile,
mockEquipmentProfiles.first.name,
);
await tester.openPickerAndSelect<IEquipmentProfile>(S.current.equipmentProfile, mockEquipmentProfiles[1].name);
await tester.pumpAndSettle();
_expectPickerListTileValue(
S.current.equipmentProfile,
mockEquipmentProfiles[1].name,
);
await tester.openPickerAndSelect<IEquipmentProfile>(
S.current.equipmentProfile,
mockPinholeEquipmentProfiles.first.name,
);
await tester.pumpAndSettle();
_expectPickerListTileValue(
S.current.equipmentProfile,
mockPinholeEquipmentProfiles.first.name,
);
_expectPickerListTileValue(
S.current.apertureValue,
ApertureValue(mockPinholeEquipmentProfiles.first.aperture, StopType.full).toString(),
reason: 'Aperture value must be automatically set when selecting a pinhole profile',
);
final aperturePickerFinder = find.descendant(
of: find.byWidgetPredicate(
(widget) => widget is PickerListTile && widget.title == S.current.apertureValue,
),
matching: find.byType(PickerListTile),
);
expect(aperturePickerFinder, findsOneWidget);
await tester.tap(aperturePickerFinder);
await tester.pumpAndSettle();
expect(
find.byType(DialogPicker<Optional<ApertureValue>>),
findsNothing,
reason: 'Aperture picker dialog must not open when pinhole profile is selected',
);
await tester.openPickerAndSelect<IEquipmentProfile>(
S.current.equipmentProfile,
mockPinholeEquipmentProfiles[1].name,
);
await tester.pumpAndSettle();
_expectPickerListTileValue(
S.current.equipmentProfile,
mockPinholeEquipmentProfiles[1].name,
);
_expectPickerListTileValue(
S.current.apertureValue,
ApertureValue(mockPinholeEquipmentProfiles[1].aperture, StopType.full).toString(),
reason: 'Aperture value must be updated when switching to a different pinhole profile',
);
await tester.tap(aperturePickerFinder);
await tester.pumpAndSettle();
expect(
find.byType(DialogPicker<Optional<ApertureValue>>),
findsNothing,
reason: 'Aperture picker dialog must not open when switching between pinhole profiles',
);
await tester.openPickerAndSelect<IEquipmentProfile>(S.current.equipmentProfile, mockEquipmentProfiles.first.name);
await tester.pumpAndSettle();
_expectPickerListTileValue(
S.current.equipmentProfile,
mockEquipmentProfiles.first.name,
);
_expectPickerListTileValue(
S.current.apertureValue,
S.current.notSet,
reason: 'Aperture value must be cleared when switching from pinhole to regular profile',
);
await tester.tap(aperturePickerFinder);
await tester.pumpAndSettle();
expect(
find.byType(DialogPicker<Optional<ApertureValue>>),
findsOneWidget,
reason: 'Aperture picker dialog must open when regular profile is selected',
);
await tester.tap(find.text('Cancel'));
await tester.pumpAndSettle();
await tester.openPickerAndSelect<IEquipmentProfile>(S.current.equipmentProfile, S.current.notSet);
await tester.pumpAndSettle();
_expectPickerListTileValue(
S.current.equipmentProfile,
S.current.notSet,
);
await tester.tap(find.byIcon(Icons.save_outlined));
await tester.pumpAndSettle();
await tester.tap(find.byType(LogbookPhotoGridTile).first);
await tester.pumpAndSettle();
_expectPickerListTileValue(
S.current.equipmentProfile,
S.current.notSet,
);
},
);
}
extension on WidgetTester {
Future<void> openPickerAndSelect<V>(String title, String valueToSelect) async {
await tap(find.text(title));
@ -273,16 +156,3 @@ extension on WidgetTester {
await tapSelectButton();
}
}
void _expectPickerListTileValue(String title, String value, {String? reason}) {
expect(
find.descendant(
of: find.byWidgetPredicate(
(widget) => widget is PickerListTile && widget.title == title,
),
matching: find.text(value),
),
findsOneWidget,
reason: reason,
);
}

View file

@ -59,7 +59,7 @@ void testToggleLayoutFeatures(String description) {
);
expectExtremeExposurePairs(
'f/1.0 - 1/320',
'f/45 - 6s',
'f/45 - 6"',
reason: 'Aperture and shutter speed ranges must be reset to default values when equipment profile is reset',
);
expectExposurePairsListItem(
@ -73,7 +73,7 @@ void testToggleLayoutFeatures(String description) {
expectExposurePairsListItem(
tester,
'f/45',
'6s',
'6"',
reason:
'Aperture and shutter speed ranges must be reset to default values when equipment profile is reset.',
);
@ -92,10 +92,10 @@ void testToggleLayoutFeatures(String description) {
(tester) async {
await tester.pumpApplication();
await tester.takePhoto();
expectExtremeExposurePairs('f/1.0 - 1/320', 'f/45 - 6s');
expectExtremeExposurePairs('f/1.0 - 1/320', 'f/45 - 6"');
expectExposurePairsListItem(tester, 'f/1.0', '1/320');
await tester.scrollToTheLastExposurePair();
expectExposurePairsListItem(tester, 'f/45', '6s');
expectExposurePairsListItem(tester, 'f/45', '6"');
// Disable layout feature
await tester.toggleLayoutFeature(S.current.meteringScreenFeatureExtremeExposurePairs);
@ -116,7 +116,7 @@ void testToggleLayoutFeatures(String description) {
expectExposurePairsListItem(
tester,
'f/45',
'6s',
'6"',
reason:
'Exposure pairs list must not be affected by the visibility of the extreme exposure pairs container.',
);
@ -125,7 +125,7 @@ void testToggleLayoutFeatures(String description) {
await tester.toggleLayoutFeature(S.current.meteringScreenFeatureExtremeExposurePairs);
expectExtremeExposurePairs(
'f/1.0 - 1/320',
'f/45 - 6s',
'f/45 - 6"',
reason:
'Exposure pairs list must not be affected by the visibility of the extreme exposure pairs container.',
);
@ -138,10 +138,10 @@ void testToggleLayoutFeatures(String description) {
await tester.pumpApplication(selectedFilmId: mockFilms.first.id);
await tester.takePhoto();
expectPickerTitle<FilmPicker>(mockFilms.first.name);
expectExtremeExposurePairs('f/1.0 - 1/320', 'f/45 - 12s');
expectExtremeExposurePairs('f/1.0 - 1/320', 'f/45 - 12"');
expectExposurePairsListItem(tester, 'f/1.0', '1/320');
await tester.scrollToTheLastExposurePair();
expectExposurePairsListItem(tester, 'f/45', '12s');
expectExposurePairsListItem(tester, 'f/45', '12"');
// Disable layout feature
await tester.toggleLayoutFeature(S.current.meteringScreenFeatureFilmPicker);
@ -153,7 +153,7 @@ void testToggleLayoutFeatures(String description) {
);
expectExtremeExposurePairs(
'f/1.0 - 1/320',
'f/45 - 6s',
'f/45 - 6"',
reason: 'Shutter speed must not be affected by reciprocity when film is discarded.',
);
expectExposurePairsListItem(
@ -166,7 +166,7 @@ void testToggleLayoutFeatures(String description) {
expectExposurePairsListItem(
tester,
'f/45',
'6s',
'6"',
reason: 'Shutter speed must not be affected by reciprocity when film is discarded.',
);

View file

@ -19,10 +19,9 @@ void main() {
mockCameraFocalLength();
});
testPurchases('Purchase & refund premium features test');
testGuardProTap('Guard Pro tap test');
testToggleLayoutFeatures('Toggle metering screen layout features test');
testLogbook('Logbook test');
testLogbookEquipmentProfileChanges('Logbook equipment profile changes test');
testE2E('e2e test');
testPurchases('Purchase & refund premium features');
testGuardProTap('Guard Pro tap');
testToggleLayoutFeatures('Toggle metering screen layout features');
testLogbook('Logbook');
testE2E('e2e');
}

View file

@ -1,4 +1,3 @@
import 'dart:collection';
import 'dart:io';
import 'package:collection/collection.dart';
@ -35,7 +34,7 @@ class LogbookPhotosProvider extends StatefulWidget {
}
class LogbookPhotosProviderState extends State<LogbookPhotosProvider> {
final LinkedHashMap<String, LogbookPhoto> _photos = LinkedHashMap();
final Map<String, LogbookPhoto> _photos = {};
bool _isEnabled = true;
@override
@ -91,9 +90,6 @@ class LogbookPhotosProviderState extends State<LogbookPhotosProvider> {
name: path,
timestamp: DateTime.timestamp(),
ev: ev100,
apertureValue: equipmentProfile is PinholeEquipmentProfile
? ApertureValue(equipmentProfile.aperture, StopType.full)
: null,
iso: iso,
nd: nd,
coordinates: coordinates,

View file

@ -12,15 +12,8 @@ class LogbookPhotoEditBloc extends Bloc<LogbookPhotoEditEvent, LogbookPhotoEditS
LogbookPhotoEditBloc(
this.photosProvider,
LogbookPhoto photo,
IEquipmentProfile? equipmentProfile,
) : _originalPhoto = photo,
_newPhoto = photo,
assert(
equipmentProfile == null ||
equipmentProfile is! PinholeEquipmentProfile ||
photo.apertureValue != null && equipmentProfile.aperture == photo.apertureValue!.rawValue,
"Aperture value must be the same as the equipment profile's aperture value if the equipment profile is a pinhole profile",
),
super(
LogbookPhotoEditState(
id: photo.id,
@ -32,7 +25,7 @@ class LogbookPhotoEditBloc extends Bloc<LogbookPhotoEditEvent, LogbookPhotoEditS
coordinates: photo.coordinates,
aperture: photo.apertureValue,
shutterSpeed: photo.shutterSpeedValue,
equipmentProfile: equipmentProfile,
equipmentProfileId: photo.equipmentProfileId,
filmId: photo.filmId,
note: photo.note,
canSave: false,
@ -81,22 +74,10 @@ class LogbookPhotoEditBloc extends Bloc<LogbookPhotoEditEvent, LogbookPhotoEditS
}
Future<void> _onEquipmentProfileChanged(LogbookPhotoEquipmentProfileChangedEvent event, Emitter emit) async {
final equipmentProfile = event.equipmentProfile;
Optional<ApertureValue>? apertureValue;
if (state.equipmentProfile is PinholeEquipmentProfile &&
(equipmentProfile == null || equipmentProfile is EquipmentProfile)) {
apertureValue = const Optional(null);
} else if (equipmentProfile is PinholeEquipmentProfile) {
apertureValue = Optional(ApertureValue(equipmentProfile.aperture, StopType.full));
}
_newPhoto = _newPhoto.copyWith(
apertureValue: apertureValue,
equipmentProfileId: Optional(equipmentProfile?.id),
);
_newPhoto = _newPhoto.copyWith(equipmentProfileId: Optional(event.equipmentProfileId));
emit(
state.copyWith(
aperture: apertureValue,
equipmentProfile: Optional(event.equipmentProfile),
equipmentProfileId: Optional(event.equipmentProfileId),
canSave: _canSave(),
),
);

View file

@ -9,7 +9,7 @@ class PickerListTile<T> extends StatelessWidget {
final T? selectedValue;
final List<T> values;
final String Function(T) titleAdapter;
final ValueChanged<Optional<T>>? onChanged;
final ValueChanged<Optional<T>> onChanged;
const PickerListTile({
required this.icon,
@ -27,29 +27,27 @@ class PickerListTile<T> extends StatelessWidget {
leading: Icon(icon),
title: Text(title),
trailing: Text(_titleAdapter(context, selectedValue)),
onTap: onChanged != null
? () {
showDialog<Optional<T>>(
context: context,
builder: (_) => DialogPicker<Optional<T>>(
icon: icon,
title: title,
selectedValue: Optional(selectedValue),
values: [
/// `const Optional(null)` for some reason is not equal to a non-const `Optional(null)`
// ignore: prefer_const_constructors
Optional(null),
...values.toSet().map((e) => Optional(e)),
],
titleAdapter: (context, value) => _titleAdapter(context, value.value),
),
).then((value) {
if (value != null) {
onChanged!(value);
}
});
}
: null,
onTap: () {
showDialog<Optional<T>>(
context: context,
builder: (_) => DialogPicker<Optional<T>>(
icon: icon,
title: title,
selectedValue: Optional(selectedValue),
values: [
/// `const Optional(null)` for some reason is not equal to a non-const `Optional(null)`
// ignore: prefer_const_constructors
Optional(null),
...values.toSet().map((e) => Optional(e)),
],
titleAdapter: (context, value) => _titleAdapter(context, value.value),
),
).then((value) {
if (value != null) {
onChanged(value);
}
});
},
);
}

View file

@ -23,9 +23,9 @@ class LogbookPhotoNoteChangedEvent extends LogbookPhotoEditEvent {
}
class LogbookPhotoEquipmentProfileChangedEvent extends LogbookPhotoEditEvent {
final IEquipmentProfile? equipmentProfile;
final String? equipmentProfileId;
const LogbookPhotoEquipmentProfileChangedEvent(this.equipmentProfile);
const LogbookPhotoEquipmentProfileChangedEvent(this.equipmentProfileId);
}
class LogbookPhotoFilmChangedEvent extends LogbookPhotoEditEvent {

View file

@ -1,7 +1,5 @@
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:lightmeter/providers/equipment_profile_provider.dart';
import 'package:lightmeter/providers/logbook_photos_provider.dart';
import 'package:lightmeter/screens/logbook_photo_edit/bloc_logbook_photo_edit.dart';
import 'package:lightmeter/screens/logbook_photo_edit/screen_logbook_photo_edit.dart';
@ -27,7 +25,6 @@ class LogbookPhotoEditFlow extends StatelessWidget {
create: (_) => LogbookPhotoEditBloc(
LogbookPhotosProvider.of(context),
args.photo,
EquipmentProfiles.of(context).firstWhereOrNull((e) => e.id == args.photo.equipmentProfileId),
),
child: const LogbookPhotoEditScreen(),
);

View file

@ -224,17 +224,15 @@ class _AperturePickerListTile extends StatelessWidget {
Widget build(BuildContext context) {
return BlocBuilder<LogbookPhotoEditBloc, LogbookPhotoEditState>(
buildWhen: (previous, current) => previous.aperture != current.aperture,
builder: (context, state) => PickerListTile<ApertureValue>(
builder: (context, state) => PickerListTile(
icon: Icons.camera_outlined,
title: S.of(context).apertureValue,
values: ApertureValue.values,
selectedValue: state.aperture,
titleAdapter: (value) => value.toString(),
onChanged: state.equipmentProfile is PinholeEquipmentProfile
? null
: (value) {
context.read<LogbookPhotoEditBloc>().add(LogbookPhotoApertureChangedEvent(value.value));
},
onChanged: (value) {
context.read<LogbookPhotoEditBloc>().add(LogbookPhotoApertureChangedEvent(value.value));
},
),
);
}
@ -267,15 +265,15 @@ class _EquipmentProfilePickerListTile extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocBuilder<LogbookPhotoEditBloc, LogbookPhotoEditState>(
buildWhen: (previous, current) => previous.equipmentProfile != current.equipmentProfile,
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: state.equipmentProfile,
selectedValue: EquipmentProfiles.of(context).firstWhereOrNull((e) => e.id == state.equipmentProfileId),
titleAdapter: (value) => value.name,
onChanged: (value) {
context.read<LogbookPhotoEditBloc>().add(LogbookPhotoEquipmentProfileChangedEvent(value.value));
context.read<LogbookPhotoEditBloc>().add(LogbookPhotoEquipmentProfileChangedEvent(value.value?.id));
},
),
);

View file

@ -10,7 +10,7 @@ class LogbookPhotoEditState {
final Coordinates? coordinates;
final ApertureValue? aperture;
final ShutterSpeedValue? shutterSpeed;
final IEquipmentProfile? equipmentProfile;
final String? equipmentProfileId;
final String? filmId;
final String? note;
final bool canSave;
@ -26,7 +26,7 @@ class LogbookPhotoEditState {
this.coordinates,
this.aperture,
this.shutterSpeed,
this.equipmentProfile,
this.equipmentProfileId,
this.filmId,
this.note,
required this.canSave,
@ -37,7 +37,7 @@ class LogbookPhotoEditState {
String? name,
Optional<ApertureValue>? aperture,
Optional<ShutterSpeedValue>? shutterSpeed,
Optional<IEquipmentProfile>? equipmentProfile,
Optional<String>? equipmentProfileId,
Optional<String>? filmId,
String? note,
bool? canSave,
@ -52,7 +52,7 @@ class LogbookPhotoEditState {
nd: nd,
aperture: aperture != null ? aperture.value : this.aperture,
shutterSpeed: shutterSpeed != null ? shutterSpeed.value : this.shutterSpeed,
equipmentProfile: equipmentProfile != null ? equipmentProfile.value : this.equipmentProfile,
equipmentProfileId: equipmentProfileId != null ? equipmentProfileId.value : this.equipmentProfileId,
filmId: filmId != null ? filmId.value : this.filmId,
note: note ?? this.note,
canSave: canSave ?? this.canSave,

View file

@ -126,13 +126,11 @@ class CameraContainer extends StatelessWidget {
enabledFeaturesHeight += Dimens.readingContainerSingleValueHeight;
enabledFeaturesHeight += Dimens.paddingS;
}
if (context.meteringFeature(MeteringScreenLayoutFeature.extremeExposurePairs)) {
if (EquipmentProfiles.selectedOf(context) is PinholeEquipmentProfile) {
enabledFeaturesHeight += Dimens.readingContainerSingleValueHeight;
} else {
enabledFeaturesHeight += Dimens.readingContainerDoubleValueHeight;
}
if (EquipmentProfiles.selectedOf(context) is PinholeEquipmentProfile) {
enabledFeaturesHeight += Dimens.readingContainerSingleValueHeight;
enabledFeaturesHeight += Dimens.paddingS;
} else if (context.meteringFeature(MeteringScreenLayoutFeature.extremeExposurePairs)) {
enabledFeaturesHeight += Dimens.readingContainerDoubleValueHeight;
enabledFeaturesHeight += Dimens.paddingS;
}

View file

@ -65,27 +65,26 @@ class ExposurePairsList extends StatelessWidget {
],
),
),
if (exposurePairs.length > 1)
Positioned(
top: 0,
bottom: 0,
child: LayoutBuilder(
builder: (context, constraints) => Align(
alignment: index == 0
? Alignment.bottomCenter
: (index == exposurePairs.length - 1 ? Alignment.topCenter : Alignment.center),
child: SizedBox(
height: index == 0 || index == exposurePairs.length - 1
? constraints.maxHeight / 2
: constraints.maxHeight,
child: ColoredBox(
color: Theme.of(context).colorScheme.onSurface,
child: const SizedBox(width: 1),
),
Positioned(
top: 0,
bottom: 0,
child: LayoutBuilder(
builder: (context, constraints) => Align(
alignment: index == 0
? Alignment.bottomCenter
: (index == exposurePairs.length - 1 ? Alignment.topCenter : Alignment.center),
child: SizedBox(
height: index == 0 || index == exposurePairs.length - 1
? constraints.maxHeight / 2
: constraints.maxHeight,
child: ColoredBox(
color: Theme.of(context).colorScheme.onSurface,
child: const SizedBox(width: 1),
),
),
),
),
),
],
);
},

View file

@ -46,14 +46,14 @@ class ReadingsContainer extends StatelessWidget {
const EquipmentProfilePicker(),
const _InnerPadding(),
],
if (context.meteringFeature(MeteringScreenLayoutFeature.extremeExposurePairs)) ...[
if (EquipmentProfiles.selectedOf(context) is PinholeEquipmentProfile)
ShutterSpeedContainer(shutterSpeedValue: fastest?.shutterSpeed)
else
ExtremeExposurePairsContainer(
fastest: fastest,
slowest: slowest,
),
if (EquipmentProfiles.selectedOf(context) is PinholeEquipmentProfile) ...[
ShutterSpeedContainer(shutterSpeedValue: fastest?.shutterSpeed),
const _InnerPadding(),
] else if (context.meteringFeature(MeteringScreenLayoutFeature.extremeExposurePairs)) ...[
ExtremeExposurePairsContainer(
fastest: fastest,
slowest: slowest,
),
const _InnerPadding(),
],
if (context.meteringFeature(MeteringScreenLayoutFeature.filmPicker)) ...[

View file

@ -24,19 +24,18 @@ class DialogPicker<T> extends StatefulWidget {
}
class _DialogPickerState<T> extends State<DialogPicker<T>> {
T? _selected;
late T _selected = widget.selectedValue;
final ScrollController _scrollController = ScrollController();
@override
void initState() {
super.initState();
final selectedIndex = widget.values.indexOf(widget.selectedValue);
if (selectedIndex >= 0) {
_selected = widget.selectedValue;
SchedulerBinding.instance.addPostFrameCallback((_) {
SchedulerBinding.instance.addPostFrameCallback((_) {
final selectedIndex = widget.values.indexOf(_selected);
if (selectedIndex >= 0) {
_scrollController.jumpTo((Dimens.grid56 * selectedIndex).clamp(0, _scrollController.position.maxScrollExtent));
});
}
}
});
}
@override
@ -94,7 +93,7 @@ class _DialogPickerState<T> extends State<DialogPicker<T>> {
child: Text(S.of(context).cancel),
),
TextButton(
onPressed: _selected != null ? () => Navigator.of(context).pop(_selected) : null,
onPressed: () => Navigator.of(context).pop(_selected),
child: Text(S.of(context).select),
),
],

View file

@ -170,10 +170,10 @@ packages:
dependency: transitive
description:
name: built_value
sha256: a30f0a0e38671e89a492c44d005b5545b830a961575bbd8336d42869ff71066d
sha256: "082001b5c3dc495d4a42f1d5789990505df20d8547d42507c29050af6933ee27"
url: "https://pub.dev"
source: hosted
version: "8.12.0"
version: "8.10.1"
camera:
dependency: "direct main"
description:
@ -861,8 +861,8 @@ packages:
dependency: "direct main"
description:
path: "."
ref: main
resolved-ref: "3f5bae6d2500a746fb83ab345919095a815244d1"
ref: "feature/MLI-48"
resolved-ref: "4a169640bff3d3a3206a2c352a75cbcea4871b1c"
url: "https://github.com/vodemn/m3_lightmeter_iap"
source: git
version: "4.1.2+37"
@ -870,11 +870,11 @@ packages:
dependency: "direct main"
description:
path: "."
ref: "v2.5.0"
resolved-ref: "680affb45c5d03ed4fe61c30ee0d6e6fab0f2c12"
ref: "feature/MLR-18"
resolved-ref: "61bb3f8a9164d19f6e47c96fbea1cbe3aaf39fc3"
url: "https://github.com/vodemn/m3_lightmeter_resources"
source: git
version: "2.5.0+14"
version: "2.4.0+13"
macros:
dependency: transitive
description:
@ -967,10 +967,10 @@ packages:
dependency: transitive
description:
name: package_info_plus_platform_interface
sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086"
sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c"
url: "https://pub.dev"
source: hosted
version: "3.2.1"
version: "3.2.0"
path:
dependency: transitive
description:
@ -1119,10 +1119,10 @@ packages:
dependency: transitive
description:
name: provider
sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272"
sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84"
url: "https://pub.dev"
source: hosted
version: "6.1.5+1"
version: "6.1.5"
pub_semver:
dependency: transitive
description:
@ -1524,10 +1524,10 @@ packages:
dependency: transitive
description:
name: watcher
sha256: "5bf046f41320ac97a469d506261797f35254fa61c641741ef32dacda98b7d39c"
sha256: "0b7fd4a0bbc4b92641dbf20adfd7e3fd1398fe17102d94b674234563e110088a"
url: "https://pub.dev"
source: hosted
version: "1.1.3"
version: "1.1.2"
web:
dependency: transitive
description:

View file

@ -33,11 +33,11 @@ dependencies:
m3_lightmeter_iap:
git:
url: "https://github.com/vodemn/m3_lightmeter_iap"
ref: main
ref: feature/MLI-48
m3_lightmeter_resources:
git:
url: "https://github.com/vodemn/m3_lightmeter_resources"
ref: v2.5.0
ref: feature/MLR-18
map_launcher: 3.2.0
material_color_utilities: 0.12.0
package_info_plus: 8.1.3