Compare commits
No commits in common. "524afa6018c46f7ec46923c1491d2964547b7781" and "df4a847b57e3cf5441bbe2bf3801aef0799a766a" have entirely different histories.
524afa6018
...
df4a847b57
2
.github/workflows/pr_check.yml
vendored
|
@ -15,7 +15,7 @@ jobs:
|
|||
analyze_and_test:
|
||||
name: Analyze & test
|
||||
runs-on: macos-11
|
||||
timeout-minutes: 10
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: 8BitJonny/gh-get-current-pr@2.2.0
|
||||
id: PR
|
||||
|
|
3
.gitignore
vendored
|
@ -60,5 +60,4 @@ ios/Runner/GoogleService-Info.plist
|
|||
/lib/firebase_options.dart
|
||||
|
||||
coverage/
|
||||
test/coverage_helper_test.dart
|
||||
screenshots/*.png
|
||||
screenshots/
|
3
.vscode/settings.json
vendored
|
@ -7,9 +7,10 @@
|
|||
"files.watcherExclude": {
|
||||
"**/.fvm": true
|
||||
},
|
||||
"dart.lineLength": 120,
|
||||
"dart.lineLength": 100,
|
||||
"[dart]": {
|
||||
"editor.rulers": [
|
||||
100,
|
||||
120,
|
||||
],
|
||||
"editor.selectionHighlight": true,
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
<img src="resources/social_preview.png" width="100%" />
|
||||
|
||||
![](https://github.com/vodemn/m3_lightmeter/actions/workflows/pr_check.yml/badge.svg)
|
||||
![](https://github.com/vodemn/m3_lightmeter/actions/workflows/create_release.yml/badge.svg)
|
||||
|
||||
# Table of contents
|
||||
|
||||
- [Table of contents](#table-of-contents)
|
||||
|
|
|
@ -75,13 +75,12 @@ android {
|
|||
flavorDimensions "app"
|
||||
productFlavors {
|
||||
dev {
|
||||
resValue "string", "app_name", "Lightmeter (DEV)"
|
||||
applicationId "com.vodemn.lightmeter.dev"
|
||||
dimension "app"
|
||||
signingConfig signingConfigs.release
|
||||
applicationIdSuffix ".dev"
|
||||
}
|
||||
prod {
|
||||
resValue "string", "app_name", "Lightmeter"
|
||||
applicationId "com.vodemn.lightmeter"
|
||||
dimension "app"
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 2 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 12 KiB |
|
@ -1,4 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#212121</color>
|
||||
</resources>
|
|
@ -3,7 +3,7 @@
|
|||
package="com.vodemn.lightmeter">
|
||||
|
||||
<application
|
||||
android:label="@string/app_name"
|
||||
android:label="Lightmeter"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 3 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 784 B |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 2 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 8.3 KiB |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 13 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 15 KiB |
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 3 KiB |
Before Width: | Height: | Size: 787 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 2 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 10 KiB |
|
@ -1,4 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#212121</color>
|
||||
</resources>
|
|
@ -1,11 +0,0 @@
|
|||
# Assets
|
||||
|
||||
## Launcher icons
|
||||
|
||||
### Android
|
||||
|
||||
Resources for Android are generated in Android Studio from the 512x512 source image as described in this [guide](https://developer.android.com/studio/write/create-app-icons).
|
||||
|
||||
### iOS
|
||||
|
||||
Resources for iOS are generated in XCode from the 1024x1024 source image as described in this [guide](https://developer.apple.com/documentation/xcode/configuring-your-app-icon).
|
BIN
assets/launcher_icon_circle.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 6 KiB |
BIN
assets/launcher_icon_square.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
|
@ -1,9 +1,34 @@
|
|||
library m3_lightmeter_iap;
|
||||
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:m3_lightmeter_iap/src/providers/equipment_profile_provider.dart';
|
||||
import 'package:m3_lightmeter_iap/src/providers/films_provider.dart';
|
||||
import 'package:m3_lightmeter_iap/src/providers/iap_products_provider.dart';
|
||||
|
||||
export 'src/data/models/iap_product.dart';
|
||||
export 'src/providers/iap_products_provider.dart';
|
||||
export 'src/data/iap_storage_service.dart';
|
||||
|
||||
const List<Film> films = [];
|
||||
export 'src/providers/equipment_profile_provider.dart';
|
||||
export 'src/providers/films_provider.dart';
|
||||
export 'src/providers/iap_products_provider.dart';
|
||||
|
||||
class IAPProviders extends StatelessWidget {
|
||||
final Object sharedPreferences;
|
||||
final Widget child;
|
||||
|
||||
const IAPProviders({
|
||||
required this.sharedPreferences,
|
||||
required this.child,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IAPProductsProvider(
|
||||
child: FilmsProvider(
|
||||
child: EquipmentProfileProvider(
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
class IAPStorageService {
|
||||
const IAPStorageService(Object _);
|
||||
|
||||
String get selectedEquipmentProfileId => '';
|
||||
set selectedEquipmentProfileId(String id) {}
|
||||
|
||||
List<EquipmentProfile> get equipmentProfiles => [];
|
||||
set equipmentProfiles(List<EquipmentProfile> profiles) {}
|
||||
|
||||
Film get selectedFilm => const Film.other();
|
||||
set selectedFilm(Film value) {}
|
||||
|
||||
List<Film> get filmsInUse => [];
|
||||
set filmsInUse(List<Film> profiles) {}
|
||||
}
|
61
iap/lib/src/providers/equipment_profile_provider.dart
Normal file
|
@ -0,0 +1,61 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:m3_lightmeter_iap/src/providers/selectable_provider.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
class EquipmentProfileProvider extends StatefulWidget {
|
||||
final Widget child;
|
||||
|
||||
const EquipmentProfileProvider({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,
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return EquipmentProfiles(
|
||||
values: const [_defaultProfile],
|
||||
selected: _defaultProfile,
|
||||
child: widget.child,
|
||||
);
|
||||
}
|
||||
|
||||
void setProfile(EquipmentProfile data) {}
|
||||
|
||||
void addProfile(String name, [EquipmentProfile? copyFrom]) {}
|
||||
|
||||
void updateProdile(EquipmentProfile data) {}
|
||||
|
||||
void deleteProfile(EquipmentProfile data) {}
|
||||
}
|
||||
|
||||
class EquipmentProfiles extends SelectableInheritedModel<EquipmentProfile> {
|
||||
const EquipmentProfiles({
|
||||
super.key,
|
||||
required super.values,
|
||||
required super.selected,
|
||||
required super.child,
|
||||
});
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
65
iap/lib/src/providers/films_provider.dart
Normal file
|
@ -0,0 +1,65 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:m3_lightmeter_iap/src/providers/selectable_provider.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
class FilmsProvider extends StatefulWidget {
|
||||
final Widget child;
|
||||
|
||||
const FilmsProvider({
|
||||
required this.child,
|
||||
super.key,
|
||||
});
|
||||
|
||||
static FilmsProviderState of(BuildContext context) {
|
||||
return context.findAncestorStateOfType<FilmsProviderState>()!;
|
||||
}
|
||||
|
||||
@override
|
||||
State<FilmsProvider> createState() => FilmsProviderState();
|
||||
}
|
||||
|
||||
class FilmsProviderState extends State<FilmsProvider> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Films(
|
||||
values: const [Film.other()],
|
||||
filmsInUse: const [Film.other()],
|
||||
selected: const Film.other(),
|
||||
child: widget.child,
|
||||
);
|
||||
}
|
||||
|
||||
void setFilm(Film film) {}
|
||||
|
||||
void saveFilms(List<Film> films) {}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -6,10 +6,8 @@ class IAPProductsProvider extends StatefulWidget {
|
|||
|
||||
const IAPProductsProvider({required this.child, super.key});
|
||||
|
||||
static IAPProductsProviderState of(BuildContext context) => IAPProductsProvider.maybeOf(context)!;
|
||||
|
||||
static IAPProductsProviderState? maybeOf(BuildContext context) {
|
||||
return context.findAncestorStateOfType<IAPProductsProviderState>();
|
||||
static IAPProductsProviderState of(BuildContext context) {
|
||||
return context.findAncestorStateOfType<IAPProductsProviderState>()!;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -56,7 +54,8 @@ class IAPProducts extends InheritedModel<IAPProductType> {
|
|||
bool updateShouldNotify(IAPProducts oldWidget) => false;
|
||||
|
||||
@override
|
||||
bool updateShouldNotifyDependent(IAPProducts oldWidget, Set<IAPProductType> dependencies) => false;
|
||||
bool updateShouldNotifyDependent(IAPProducts oldWidget, Set<IAPProductType> dependencies) =>
|
||||
false;
|
||||
|
||||
IAPProduct? _findProduct(IAPProductType type) {
|
||||
try {
|
||||
|
|
248
integration_test/generate_screenshots.dart
Normal file
|
@ -0,0 +1,248 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
import 'package:lightmeter/application.dart';
|
||||
import 'package:lightmeter/data/caffeine_service.dart';
|
||||
import 'package:lightmeter/data/haptics_service.dart';
|
||||
import 'package:lightmeter/data/light_sensor_service.dart';
|
||||
import 'package:lightmeter/data/models/ev_source_type.dart';
|
||||
import 'package:lightmeter/data/models/metering_screen_layout_config.dart';
|
||||
import 'package:lightmeter/data/models/supported_locale.dart';
|
||||
import 'package:lightmeter/data/models/theme_type.dart';
|
||||
import 'package:lightmeter/data/models/volume_action.dart';
|
||||
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/generated/l10n.dart';
|
||||
import 'package:lightmeter/providers/services_provider.dart';
|
||||
import 'package:lightmeter/providers/user_preferences_provider.dart';
|
||||
import 'package:lightmeter/res/dimens.dart';
|
||||
import 'package:lightmeter/res/theme.dart';
|
||||
import 'package:lightmeter/screens/metering/components/bottom_controls/components/measure_button/widget_button_measure.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/shared/animated_dialog_picker/components/dialog_picker/widget_picker_dialog.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/screen_equipment_profile.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';
|
||||
|
||||
import 'utils/widget_tester_extension.dart';
|
||||
|
||||
class _MockSharedPreferences extends Mock implements SharedPreferences {}
|
||||
|
||||
class _MockUserPreferencesService extends Mock implements UserPreferencesService {}
|
||||
|
||||
class _MockCaffeineService extends Mock implements CaffeineService {}
|
||||
|
||||
class _MockHapticsService extends Mock implements HapticsService {}
|
||||
|
||||
class _MockPermissionsService extends Mock implements PermissionsService {}
|
||||
|
||||
class _MockLightSensorService extends Mock implements LightSensorService {}
|
||||
|
||||
class _MockVolumeEventsService extends Mock implements VolumeEventsService {}
|
||||
|
||||
//https://stackoverflow.com/a/67186625/13167574
|
||||
void main() {
|
||||
late _MockUserPreferencesService mockUserPreferencesService;
|
||||
late _MockCaffeineService mockCaffeineService;
|
||||
late _MockHapticsService mockHapticsService;
|
||||
late _MockPermissionsService mockPermissionsService;
|
||||
late _MockLightSensorService mockLightSensorService;
|
||||
late _MockVolumeEventsService mockVolumeEventsService;
|
||||
|
||||
final binding = IntegrationTestWidgetsFlutterBinding();
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
setUpAll(() {
|
||||
mockUserPreferencesService = _MockUserPreferencesService();
|
||||
when(() => mockUserPreferencesService.evSourceType).thenReturn(EvSourceType.camera);
|
||||
when(() => mockUserPreferencesService.stopType).thenReturn(StopType.third);
|
||||
when(() => mockUserPreferencesService.locale).thenReturn(SupportedLocale.en);
|
||||
when(() => mockUserPreferencesService.caffeine).thenReturn(true);
|
||||
when(() => mockUserPreferencesService.volumeAction).thenReturn(VolumeAction.shutter);
|
||||
when(() => mockUserPreferencesService.cameraEvCalibration).thenReturn(0.0);
|
||||
when(() => mockUserPreferencesService.lightSensorEvCalibration).thenReturn(0.0);
|
||||
when(() => mockUserPreferencesService.iso).thenReturn(const IsoValue(400, StopType.full));
|
||||
when(() => mockUserPreferencesService.ndFilter).thenReturn(NdValue.values.first);
|
||||
when(() => mockUserPreferencesService.haptics).thenReturn(true);
|
||||
when(() => mockUserPreferencesService.meteringScreenLayout).thenReturn({
|
||||
MeteringScreenLayoutFeature.equipmentProfiles: true,
|
||||
MeteringScreenLayoutFeature.extremeExposurePairs: true,
|
||||
MeteringScreenLayoutFeature.filmPicker: true,
|
||||
MeteringScreenLayoutFeature.histogram: false,
|
||||
});
|
||||
when(() => mockUserPreferencesService.themeType).thenReturn(ThemeType.light);
|
||||
when(() => mockUserPreferencesService.dynamicColor).thenReturn(false);
|
||||
|
||||
mockCaffeineService = _MockCaffeineService();
|
||||
when(() => mockCaffeineService.isKeepScreenOn()).thenAnswer((_) async => false);
|
||||
when(() => mockCaffeineService.keepScreenOn(true)).thenAnswer((_) async => true);
|
||||
when(() => mockCaffeineService.keepScreenOn(false)).thenAnswer((_) async => false);
|
||||
|
||||
mockHapticsService = _MockHapticsService();
|
||||
when(() => mockHapticsService.quickVibration()).thenAnswer((_) async {});
|
||||
when(() => mockHapticsService.responseVibration()).thenAnswer((_) async {});
|
||||
when(() => mockHapticsService.errorVibration()).thenAnswer((_) async {});
|
||||
|
||||
mockPermissionsService = _MockPermissionsService();
|
||||
when(() => mockPermissionsService.requestCameraPermission())
|
||||
.thenAnswer((_) async => PermissionStatus.granted);
|
||||
when(() => mockPermissionsService.checkCameraPermission())
|
||||
.thenAnswer((_) async => PermissionStatus.granted);
|
||||
|
||||
mockLightSensorService = _MockLightSensorService();
|
||||
when(() => mockLightSensorService.hasSensor()).thenAnswer((_) async => true);
|
||||
when(() => mockLightSensorService.luxStream()).thenAnswer((_) => Stream.fromIterable([100]));
|
||||
|
||||
mockVolumeEventsService = _MockVolumeEventsService();
|
||||
when(() => mockVolumeEventsService.setVolumeHandling(true)).thenAnswer((_) async => true);
|
||||
when(() => mockVolumeEventsService.setVolumeHandling(false)).thenAnswer((_) async => false);
|
||||
when(() => mockVolumeEventsService.volumeButtonsEventStream())
|
||||
.thenAnswer((_) => const Stream<int>.empty());
|
||||
|
||||
when(() => mockHapticsService.quickVibration()).thenAnswer((_) async {});
|
||||
when(() => mockHapticsService.responseVibration()).thenAnswer((_) async {});
|
||||
});
|
||||
|
||||
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()),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
/// Generates several screenshots with the light theme
|
||||
/// and the additionally the first one with the dark theme
|
||||
void generateScreenshots(Color color) {
|
||||
testWidgets('${color.value}_light', (tester) async {
|
||||
when(() => mockUserPreferencesService.themeType).thenReturn(ThemeType.light);
|
||||
when(() => mockUserPreferencesService.primaryColor).thenReturn(color);
|
||||
await pumpApplication(tester);
|
||||
|
||||
await tester.takePhoto();
|
||||
await tester.takeScreenshot(binding, '${color.value}_metering_reflected');
|
||||
|
||||
await tester.tap(find.byTooltip(S.current.tooltipUseLightSensor));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.byType(MeteringMeasureButton));
|
||||
await tester.tap(find.byType(MeteringMeasureButton));
|
||||
await tester.takeScreenshot(binding, '${color.value}_metering_incident');
|
||||
|
||||
expect(find.byType(IsoValuePicker), findsOneWidget);
|
||||
await tester.tap(find.byType(IsoValuePicker));
|
||||
await tester.pumpAndSettle(Dimens.durationL);
|
||||
expect(find.byType(DialogPicker<IsoValue>), findsOneWidget);
|
||||
await tester.takeScreenshot(binding, '${color.value}_metering_iso_picker');
|
||||
|
||||
await tester.tapCancelButton();
|
||||
expect(find.byType(DialogPicker<IsoValue>), findsNothing);
|
||||
await tester.openSettings();
|
||||
await tester.takeScreenshot(binding, '${color.value}_settings');
|
||||
|
||||
await tester.tapListTile(S.current.meteringScreenLayout);
|
||||
await tester.takeScreenshot(binding, '${color.value}_settings_metering_screen_layout');
|
||||
|
||||
await tester.tapCancelButton();
|
||||
await tester.tapListTile(S.current.equipmentProfiles);
|
||||
expect(find.byType(EquipmentProfilesScreen), findsOneWidget);
|
||||
await tester.tap(find.byType(EquipmentProfileContainer).first);
|
||||
await tester.pumpAndSettle();
|
||||
await tester.takeScreenshot(binding, '${color.value}-equipment_profiles');
|
||||
|
||||
await tester.tap(find.byIcon(Icons.iso).first);
|
||||
await tester.pumpAndSettle();
|
||||
await tester.takeScreenshot(binding, '${color.value}_equipment_profiles_iso_picker');
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'${color.value}_dark',
|
||||
(tester) async {
|
||||
when(() => mockUserPreferencesService.themeType).thenReturn(ThemeType.dark);
|
||||
when(() => mockUserPreferencesService.primaryColor).thenReturn(color);
|
||||
await pumpApplication(tester);
|
||||
|
||||
await tester.takePhoto();
|
||||
await tester.takeScreenshot(binding, '${color.value}_metering_reflected_dark');
|
||||
|
||||
await tester.tap(find.byTooltip(S.current.tooltipUseLightSensor));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.byType(MeteringMeasureButton));
|
||||
await tester.tap(find.byType(MeteringMeasureButton));
|
||||
await tester.takeScreenshot(binding, '${color.value}_metering_incident_dark');
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
generateScreenshots(primaryColorsList[5]);
|
||||
generateScreenshots(primaryColorsList[3]);
|
||||
generateScreenshots(primaryColorsList[9]);
|
||||
}
|
||||
|
||||
final _mockEquipmentProfiles = [
|
||||
const EquipmentProfile(
|
||||
id: '',
|
||||
name: '',
|
||||
apertureValues: ApertureValue.values,
|
||||
ndValues: NdValue.values,
|
||||
shutterSpeedValues: ShutterSpeedValue.values,
|
||||
isoValues: IsoValue.values,
|
||||
),
|
||||
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(16, 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),
|
||||
],
|
||||
),
|
||||
const EquipmentProfile(
|
||||
id: '2',
|
||||
name: 'Praktica + Jupiter',
|
||||
apertureValues: ApertureValue.values,
|
||||
ndValues: NdValue.values,
|
||||
shutterSpeedValues: ShutterSpeedValue.values,
|
||||
isoValues: IsoValue.values,
|
||||
),
|
||||
];
|
|
@ -2,7 +2,7 @@ flutter drive \
|
|||
--dart-define="cameraPreviewAspectRatio=240/320" \
|
||||
--dart-define="cameraStubImage=assets/camera_stub_image.jpg" \
|
||||
--driver=test_driver/screenshot_driver.dart \
|
||||
--target=screenshots/generate_screenshots.dart \
|
||||
--target=integration_test/generate_screenshots.dart \
|
||||
--profile \
|
||||
--flavor=dev \
|
||||
--no-dds \
|
|
@ -1,105 +0,0 @@
|
|||
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';
|
||||
|
||||
class _MockIAPStorageService extends Mock implements IAPStorageService {}
|
||||
|
||||
class MockIAPProviders extends StatefulWidget {
|
||||
final String selectedEquipmentProfileId;
|
||||
final Film selectedFilm;
|
||||
final Widget child;
|
||||
|
||||
const MockIAPProviders({
|
||||
this.selectedEquipmentProfileId = '',
|
||||
this.selectedFilm = const Film.other(),
|
||||
required this.child,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@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) {
|
||||
return EquipmentProfileProvider(
|
||||
storageService: mockIAPStorageService,
|
||||
child: FilmsProvider(
|
||||
storageService: mockIAPStorageService,
|
||||
availableFilms: mockFilms,
|
||||
child: widget.child,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const defaultEquipmentProfile = EquipmentProfile(
|
||||
id: '',
|
||||
name: '',
|
||||
apertureValues: ApertureValue.values,
|
||||
ndValues: NdValue.values,
|
||||
shutterSpeedValues: ShutterSpeedValue.values,
|
||||
isoValues: IsoValue.values,
|
||||
);
|
||||
|
||||
final mockEquipmentProfiles = [
|
||||
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(16, 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),
|
||||
],
|
||||
),
|
||||
const EquipmentProfile(
|
||||
id: '2',
|
||||
name: 'Praktica + Jupiter',
|
||||
apertureValues: ApertureValue.values,
|
||||
ndValues: NdValue.values,
|
||||
shutterSpeedValues: ShutterSpeedValue.values,
|
||||
isoValues: IsoValue.values,
|
||||
),
|
||||
];
|
||||
|
||||
const mockFilms = [_MockFilm(100, 2), _MockFilm(400, 2), _MockFilm(3, 800), _MockFilm(400, 1.5)];
|
||||
|
||||
class _MockFilm extends Film {
|
||||
final double reciprocityMultiplier;
|
||||
|
||||
const _MockFilm(int iso, this.reciprocityMultiplier) : super('Mock film $iso x$reciprocityMultiplier', iso);
|
||||
|
||||
@override
|
||||
double reciprocityFormula(double t) => t * reciprocityMultiplier;
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:light_sensor/light_sensor.dart';
|
||||
|
||||
void setLightSensorAvilability({required bool hasSensor}) {
|
||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(
|
||||
LightSensor.methodChannel,
|
||||
(methodCall) async {
|
||||
switch (methodCall.method) {
|
||||
case "sensor":
|
||||
return hasSensor;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void resetLightSensorAvilability() {
|
||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(
|
||||
LightSensor.methodChannel,
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> sendMockIncidentEv(double ev) => sendMockLux((2.5 * pow(2, ev)).toInt());
|
||||
|
||||
Future<void> sendMockLux([int lux = 100]) async {
|
||||
await TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.handlePlatformMessage(
|
||||
LightSensor.eventChannel.name,
|
||||
const StandardMethodCodec().encodeSuccessEnvelope(lux),
|
||||
(ByteData? data) {},
|
||||
);
|
||||
}
|
||||
|
||||
void setupLightSensorStreamHandler() {
|
||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(
|
||||
MethodChannel(LightSensor.eventChannel.name),
|
||||
(methodCall) async {
|
||||
switch (methodCall.method) {
|
||||
case "listen":
|
||||
return;
|
||||
case "cancel":
|
||||
return;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void resetLightSensorStreamHandler() {
|
||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(
|
||||
MethodChannel(LightSensor.eventChannel.name),
|
||||
null,
|
||||
);
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:lightmeter/application.dart';
|
||||
import 'package:lightmeter/application_wrapper.dart';
|
||||
import 'package:lightmeter/environment.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/res/dimens.dart';
|
||||
import 'package:lightmeter/screens/metering/components/bottom_controls/components/measure_button/widget_button_measure.dart';
|
||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
import '../mocks/paid_features_mock.dart';
|
||||
import 'platform_channel_mock.dart';
|
||||
|
||||
extension WidgetTesterCommonActions on WidgetTester {
|
||||
Future<void> pumpApplication({
|
||||
IAPProductStatus productStatus = IAPProductStatus.purchased,
|
||||
String selectedEquipmentProfileId = '',
|
||||
Film selectedFilm = const Film.other(),
|
||||
}) async {
|
||||
await pumpWidget(
|
||||
IAPProducts(
|
||||
products: [
|
||||
IAPProduct(
|
||||
storeId: IAPProductType.paidFeatures.storeId,
|
||||
status: productStatus,
|
||||
),
|
||||
],
|
||||
child: ApplicationWrapper(
|
||||
const Environment.dev(),
|
||||
child: MockIAPProviders(
|
||||
selectedEquipmentProfileId: selectedEquipmentProfileId,
|
||||
selectedFilm: selectedFilm,
|
||||
child: const Application(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await pumpAndSettle();
|
||||
}
|
||||
|
||||
Future<void> takePhoto() async {
|
||||
await tap(find.byType(MeteringMeasureButton));
|
||||
await pump(const Duration(seconds: 2)); // wait for circular progress indicator
|
||||
await pump(const Duration(seconds: 1)); // wait for circular progress indicator
|
||||
await pumpAndSettle();
|
||||
}
|
||||
|
||||
Future<void> toggleIncidentMetering(double ev) async {
|
||||
await tap(find.byType(MeteringMeasureButton));
|
||||
await sendMockIncidentEv(ev);
|
||||
await tap(find.byType(MeteringMeasureButton));
|
||||
await pumpAndSettle();
|
||||
}
|
||||
|
||||
Future<void> openAnimatedPicker<T>() async {
|
||||
await tap(find.byType(T));
|
||||
await pumpAndSettle(Dimens.durationL);
|
||||
}
|
||||
}
|
||||
|
||||
extension WidgetTesterListTileActions on WidgetTester {
|
||||
/// Useful for tapping a specific [ListTile] inside a specific screen or dialog
|
||||
Future<void> tapDescendantTextOf<T>(String text) async {
|
||||
await tap(find.descendant(of: find.byType(T), matching: find.text(text)));
|
||||
}
|
||||
}
|
||||
|
||||
extension WidgetTesterTextButtonActions on WidgetTester {
|
||||
Future<void> tapSelectButton() => _tapTextButton(S.current.select);
|
||||
|
||||
Future<void> tapCancelButton() => _tapTextButton(S.current.cancel);
|
||||
|
||||
Future<void> tapSaveButton() => _tapTextButton(S.current.save);
|
||||
|
||||
Future<void> _tapTextButton(String text) async {
|
||||
final button = find.byWidgetPredicate(
|
||||
(widget) => widget is TextButton && widget.child is Text && (widget.child as Text?)?.data == text,
|
||||
);
|
||||
expect(button, findsOneWidget);
|
||||
await tap(button);
|
||||
await pumpAndSettle();
|
||||
}
|
||||
}
|
|
@ -40,12 +40,6 @@ post_install do |installer|
|
|||
|
||||
# Start of the permission_handler configuration
|
||||
target.build_configurations.each do |config|
|
||||
# https://github.com/CocoaPods/CocoaPods/issues/12012
|
||||
xcconfig_path = config.base_configuration_reference.real_path
|
||||
xcconfig = File.read(xcconfig_path)
|
||||
xcconfig_mod = xcconfig.gsub(/DT_TOOLCHAIN_DIR/, "TOOLCHAIN_DIR")
|
||||
File.open(xcconfig_path, "w") { |file| file << xcconfig_mod }
|
||||
|
||||
# Preprocessor definitions can be found in: https://github.com/Baseflow/flutter-permission-handler/blob/master/permission_handler_apple/ios/Classes/PermissionHandlerEnums.h
|
||||
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
|
||||
'$(inherited)',
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
8C539F8FF42AB22E298D5A5E /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||
97C146EE1CF9000F007C117D /* Lightmeter.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Lightmeter.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
|
@ -95,7 +95,7 @@
|
|||
97C146EF1CF9000F007C117D /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97C146EE1CF9000F007C117D /* Lightmeter.app */,
|
||||
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
|
@ -154,7 +154,6 @@
|
|||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
45F53C083F2EA48EF231DA16 /* [CP] Embed Pods Frameworks */,
|
||||
FF00F85CE432774850A0EDB7 /* [firebase_crashlytics] Crashlytics Upload Symbols */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
@ -162,7 +161,7 @@
|
|||
);
|
||||
name = Runner;
|
||||
productName = Runner;
|
||||
productReference = 97C146EE1CF9000F007C117D /* Lightmeter.app */;
|
||||
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
@ -243,7 +242,6 @@
|
|||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
|
||||
);
|
||||
name = "Thin Binary";
|
||||
outputPaths = (
|
||||
|
@ -284,29 +282,6 @@
|
|||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||
};
|
||||
FF00F85CE432774850A0EDB7 /* [firebase_crashlytics] Crashlytics Upload Symbols */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}\"",
|
||||
"\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/\"",
|
||||
"\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"",
|
||||
"\"$(TARGET_BUILD_DIR)/$(EXECUTABLE_PATH)\"",
|
||||
"\"$(PROJECT_DIR)/firebase_app_id_file.json\"",
|
||||
);
|
||||
name = "[firebase_crashlytics] Crashlytics Upload Symbols";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"$PODS_ROOT/FirebaseCrashlytics/upload-symbols\" --flutter-project \"$PROJECT_DIR/firebase_app_id_file.json\" ";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
|
@ -395,23 +370,18 @@
|
|||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-prod";
|
||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = 489Z6UQMGN;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Lightmeter;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter;
|
||||
PRODUCT_NAME = Lightmeter;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
|
@ -529,23 +499,18 @@
|
|||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-prod";
|
||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = 489Z6UQMGN;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Lightmeter;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter;
|
||||
PRODUCT_NAME = Lightmeter;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
|
@ -557,23 +522,18 @@
|
|||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-prod";
|
||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = 489Z6UQMGN;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Lightmeter;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter;
|
||||
PRODUCT_NAME = Lightmeter;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
|
@ -639,23 +599,18 @@
|
|||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-dev";
|
||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = 489Z6UQMGN;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "Lightmeter (DEV)";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter.dev;
|
||||
PRODUCT_NAME = "Lightmeter (DEV)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
|
@ -719,23 +674,18 @@
|
|||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-dev";
|
||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = 489Z6UQMGN;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "Lightmeter (DEV)";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter.dev;
|
||||
PRODUCT_NAME = "Lightmeter (DEV)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
|
@ -796,23 +746,18 @@
|
|||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-dev";
|
||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = 489Z6UQMGN;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "Lightmeter (DEV)";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter.dev;
|
||||
PRODUCT_NAME = "Lightmeter (DEV)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Icon square (dev).png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 21 KiB |
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Icon square.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 14 KiB |
122
ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
Normal file
|
@ -0,0 +1,122 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-20x20@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-20x20@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-40x40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-40x40@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-60x60@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-60x60@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-20x20@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-20x20@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-29x29@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-29x29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-40x40@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-40x40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-76x76@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-76x76@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-83.5x83.5@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "Icon-App-1024x1024@1x.png",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 323 B |
After Width: | Height: | Size: 626 B |
After Width: | Height: | Size: 1,008 B |
After Width: | Height: | Size: 476 B |
After Width: | Height: | Size: 964 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 626 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 785 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 942 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.7 KiB |