Merge branch 'main' of https://github.com/vodemn/m3_lightmeter into cd
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
@ -2,7 +2,7 @@
|
||||||
name: Bug report
|
name: Bug report
|
||||||
about: Create a bug report to help improve the app
|
about: Create a bug report to help improve the app
|
||||||
title: ''
|
title: ''
|
||||||
labels: bug
|
labels: bug, user feedback
|
||||||
assignees: vodemn
|
assignees: vodemn
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
@ -2,19 +2,16 @@
|
||||||
name: Feature request or improvement
|
name: Feature request or improvement
|
||||||
about: Suggest an idea for this project
|
about: Suggest an idea for this project
|
||||||
title: ''
|
title: ''
|
||||||
labels: feature
|
labels: feature, user feedback
|
||||||
assignees: vodemn
|
assignees: vodemn
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Is your feature request related to a problem? Please describe.**
|
**Describe the feature or the problem it solves**
|
||||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
A clear and concise description of what the problem is.
|
||||||
|
|
||||||
**Describe the solution you'd like**
|
**Describe the solution you'd like**
|
||||||
A clear and concise description of what you want to happen.
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
**Describe alternatives you've considered**
|
|
||||||
A clear and concise description of any alternative solutions or features you've considered.
|
|
||||||
|
|
||||||
**Additional context**
|
**Additional context**
|
||||||
Add any other context or screenshots about the feature request here.
|
Add any other context or screenshots about the feature request here.
|
||||||
|
|
14
.github/scripts/restore_from_base64.sh
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
content="$1"
|
||||||
|
filename="$2"
|
||||||
|
|
||||||
|
if [[ ! -n "$content" ]]; then
|
||||||
|
echo "Provide file content"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -n "$filename" ]]; then
|
||||||
|
echo "Provide a path to an output file"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "$content" | base64 --decode --output "$filename"
|
14
.github/workflows/build_apk.yml
vendored
|
@ -67,12 +67,10 @@ jobs:
|
||||||
cp $GOOGLE_SERVICES_JSON_ANDROID_PATH ./android/app
|
cp $GOOGLE_SERVICES_JSON_ANDROID_PATH ./android/app
|
||||||
|
|
||||||
- name: Restore firebase_options.dart
|
- name: Restore firebase_options.dart
|
||||||
env:
|
run: bash .github/scripts/restore_from_base64.sh "${{ secrets.FIREBASE_OPTIONS }}" "lib/firebase_options.dart"
|
||||||
FIREBASE_OPTIONS: ${{ secrets.FIREBASE_OPTIONS }}
|
|
||||||
run: |
|
- name: Restore constants.dart
|
||||||
FIREBASE_OPTIONS_PATH=$RUNNER_TEMP/firebase_options.dart
|
run: bash .github/scripts/restore_from_base64.sh "${{ secrets.CONSTANTS }}" "lib/constants.dart"
|
||||||
echo -n "$FIREBASE_OPTIONS" | base64 --decode --output $FIREBASE_OPTIONS_PATH
|
|
||||||
cp $FIREBASE_OPTIONS_PATH ./lib
|
|
||||||
|
|
||||||
- name: Install Flutter
|
- name: Install Flutter
|
||||||
uses: subosito/flutter-action@v2
|
uses: subosito/flutter-action@v2
|
||||||
|
@ -89,10 +87,10 @@ jobs:
|
||||||
- name: Build .apk
|
- name: Build .apk
|
||||||
env:
|
env:
|
||||||
FLAVOR: ${{ github.event.inputs.flavor }}
|
FLAVOR: ${{ github.event.inputs.flavor }}
|
||||||
run: flutter build apk --release --flavor $FLAVOR --dart-define cameraPreviewAspectRatio=240/320 -t lib/main_$FLAVOR.dart
|
run: flutter build apk --release --flavor $FLAVOR -t lib/main_$FLAVOR.dart
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: m3_lightmeter_${{ github.event.inputs.flavor }}
|
name: m3_lightmeter_${{ github.event.inputs.flavor }}_apk
|
||||||
path: build/app/outputs/flutter-apk/app-${{ github.event.inputs.flavor }}-release.apk
|
path: build/app/outputs/flutter-apk/app-${{ github.event.inputs.flavor }}-release.apk
|
||||||
|
|
97
.github/workflows/build_ipa.yml
vendored
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
# This workflow uses actions that are not certified by GitHub.
|
||||||
|
# They are provided by a third-party and are governed by
|
||||||
|
# separate terms of service, privacy policy, and support
|
||||||
|
# documentation.
|
||||||
|
|
||||||
|
name: Build Prod .ipa
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
FLAVOR: "prod"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build .ipa
|
||||||
|
runs-on: macos-11
|
||||||
|
timeout-minutes: 60
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Connect private iap package
|
||||||
|
uses: webfactory/ssh-agent@v0.8.0
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.M3_LIGHTMETER_IAP_KEY }}
|
||||||
|
|
||||||
|
- name: Install the Apple certificate and provisioning profile
|
||||||
|
env:
|
||||||
|
APP_STORE_P12: ${{ secrets.APP_STORE_P12 }}
|
||||||
|
APP_STORE_P12_PASSWORD: ${{ secrets.APP_STORE_P12_PASSWORD }}
|
||||||
|
APP_STORE_PROVISION_PROD: ${{ secrets.APP_STORE_PROVISION_PROD }}
|
||||||
|
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
||||||
|
run: |
|
||||||
|
# create variables
|
||||||
|
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
|
||||||
|
PROVISION_PATH=$RUNNER_TEMP/build_provision.mobileprovision
|
||||||
|
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
|
||||||
|
|
||||||
|
# import certificate and provisioning profile from secrets
|
||||||
|
echo -n "$APP_STORE_P12" | base64 --decode -o $CERTIFICATE_PATH
|
||||||
|
echo -n "$APP_STORE_PROVISION_PROD" | base64 --decode -o $PROVISION_PATH
|
||||||
|
|
||||||
|
# create temporary keychain
|
||||||
|
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
||||||
|
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
|
||||||
|
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
||||||
|
|
||||||
|
# import certificate to keychain
|
||||||
|
security import $CERTIFICATE_PATH -P "$APP_STORE_P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
||||||
|
security list-keychain -d user -s $KEYCHAIN_PATH
|
||||||
|
|
||||||
|
# apply provisioning profile
|
||||||
|
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
|
||||||
|
cp $PROVISION_PATH ~/Library/MobileDevice/Provisioning\ Profiles
|
||||||
|
|
||||||
|
- name: Restore ios/Runner/ExportOptions.plist
|
||||||
|
run: bash .github/scripts/restore_from_base64.sh "${{ secrets.APP_STORE_EXPORT_OPTIONS }}" "ios/Runner/ExportOptions.plist"
|
||||||
|
|
||||||
|
- name: Restore firebase_options.dart
|
||||||
|
run: bash .github/scripts/restore_from_base64.sh "${{ secrets.FIREBASE_OPTIONS }}" "lib/firebase_options.dart"
|
||||||
|
|
||||||
|
- name: Restore constants.dart
|
||||||
|
run: bash .github/scripts/restore_from_base64.sh "${{ secrets.CONSTANTS }}" "lib/constants.dart"
|
||||||
|
|
||||||
|
- name: Install Flutter
|
||||||
|
uses: subosito/flutter-action@v2
|
||||||
|
with:
|
||||||
|
channel: "stable"
|
||||||
|
flutter-version: "3.10.0"
|
||||||
|
|
||||||
|
- name: Prepare flutter project
|
||||||
|
run: |
|
||||||
|
flutter --version
|
||||||
|
flutter pub get
|
||||||
|
flutter pub run intl_utils:generate
|
||||||
|
|
||||||
|
- name: Build .ipa
|
||||||
|
run: |
|
||||||
|
flutter build ipa \
|
||||||
|
--release \
|
||||||
|
--flavor $FLAVOR \
|
||||||
|
--target lib/main_$FLAVOR.dart \
|
||||||
|
--export-options-plist=ios/Runner/ExportOptions.plist
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: m3_lightmeter_$FLAVOR_ipa
|
||||||
|
path: build/ios/ipa/lightmeter.ipa
|
||||||
|
|
||||||
|
- name: Clean up keychain and provisioning profile
|
||||||
|
if: ${{ always() }}
|
||||||
|
run: |
|
||||||
|
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
|
||||||
|
rm ~/Library/MobileDevice/Provisioning\ Profiles/build_provision.mobileprovision
|
12
.github/workflows/create_release.yml
vendored
|
@ -37,7 +37,7 @@ on:
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
env:
|
env:
|
||||||
BUILD_ARGS: --release --flavor prod --dart-define cameraPreviewAspectRatio=240/320 -t lib/main_prod.dart
|
BUILD_ARGS: --release --flavor prod -t lib/main_prod.dart
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
@ -86,12 +86,10 @@ jobs:
|
||||||
cp $GOOGLE_SERVICES_JSON_ANDROID_PATH ./android/app
|
cp $GOOGLE_SERVICES_JSON_ANDROID_PATH ./android/app
|
||||||
|
|
||||||
- name: Restore firebase_options.dart
|
- name: Restore firebase_options.dart
|
||||||
env:
|
run: bash .github/scripts/restore_from_base64.sh "${{ secrets.FIREBASE_OPTIONS }}" "lib/firebase_options.dart"
|
||||||
FIREBASE_OPTIONS: ${{ secrets.FIREBASE_OPTIONS }}
|
|
||||||
run: |
|
- name: Restore constants.dart
|
||||||
FIREBASE_OPTIONS_PATH=$RUNNER_TEMP/firebase_options.dart
|
run: bash .github/scripts/restore_from_base64.sh "${{ secrets.CONSTANTS }}" "lib/constants.dart"
|
||||||
echo -n "$FIREBASE_OPTIONS" | base64 --decode --output $FIREBASE_OPTIONS_PATH
|
|
||||||
cp $FIREBASE_OPTIONS_PATH ./lib
|
|
||||||
|
|
||||||
# This step makes sense when Github release is enabled because this release increments the build number.
|
# This step makes sense when Github release is enabled because this release increments the build number.
|
||||||
# Therefore here we have to increment it as well to build an apk with the same build number.
|
# Therefore here we have to increment it as well to build an apk with the same build number.
|
||||||
|
|
5
.github/workflows/pr_check.yml
vendored
|
@ -15,7 +15,7 @@ jobs:
|
||||||
analyze_and_test:
|
analyze_and_test:
|
||||||
name: Analyze & test
|
name: Analyze & test
|
||||||
runs-on: macos-11
|
runs-on: macos-11
|
||||||
timeout-minutes: 5
|
timeout-minutes: 10
|
||||||
steps:
|
steps:
|
||||||
- uses: 8BitJonny/gh-get-current-pr@2.2.0
|
- uses: 8BitJonny/gh-get-current-pr@2.2.0
|
||||||
id: PR
|
id: PR
|
||||||
|
@ -36,6 +36,9 @@ jobs:
|
||||||
if: steps.fetch-iap.conclusion != 'success'
|
if: steps.fetch-iap.conclusion != 'success'
|
||||||
run: bash ./.github/scripts/stub_iap.sh
|
run: bash ./.github/scripts/stub_iap.sh
|
||||||
|
|
||||||
|
- name: Restore constants.dart
|
||||||
|
run: bash .github/scripts/restore_from_base64.sh "${{ secrets.CONSTANTS }}" "lib/constants.dart"
|
||||||
|
|
||||||
- uses: subosito/flutter-action@v2
|
- uses: subosito/flutter-action@v2
|
||||||
with:
|
with:
|
||||||
channel: "stable"
|
channel: "stable"
|
||||||
|
|
5
.gitignore
vendored
|
@ -58,5 +58,8 @@ android/app/google-services.json
|
||||||
ios/firebase_app_id_file.json
|
ios/firebase_app_id_file.json
|
||||||
ios/Runner/GoogleService-Info.plist
|
ios/Runner/GoogleService-Info.plist
|
||||||
/lib/firebase_options.dart
|
/lib/firebase_options.dart
|
||||||
|
/lib/constants.dart
|
||||||
|
|
||||||
coverage/
|
coverage/
|
||||||
|
test/coverage_helper_test.dart
|
||||||
|
screenshots/generated/
|
37
.vscode/launch.json
vendored
|
@ -5,59 +5,51 @@
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "dev-debug (android)",
|
"name": "dev-debug",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"type": "dart",
|
"type": "dart",
|
||||||
"flutterMode": "debug",
|
"flutterMode": "debug",
|
||||||
"args": [
|
"args": [
|
||||||
"--flavor",
|
"--flavor",
|
||||||
"dev",
|
"dev",
|
||||||
"--dart-define",
|
|
||||||
"cameraPreviewAspectRatio=240/320",
|
|
||||||
],
|
],
|
||||||
"program": "${workspaceFolder}/lib/main_dev.dart",
|
"program": "${workspaceFolder}/lib/main_dev.dart",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "dev-profile (android)",
|
"name": "dev-profile",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"type": "dart",
|
"type": "dart",
|
||||||
"flutterMode": "profile",
|
"flutterMode": "profile",
|
||||||
"args": [
|
"args": [
|
||||||
"--flavor",
|
"--flavor",
|
||||||
"dev",
|
"dev",
|
||||||
"--dart-define",
|
|
||||||
"cameraPreviewAspectRatio=240/320",
|
|
||||||
],
|
],
|
||||||
"program": "${workspaceFolder}/lib/main_dev.dart",
|
"program": "${workspaceFolder}/lib/main_dev.dart",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "prod-debug (android)",
|
"name": "prod-debug",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"type": "dart",
|
"type": "dart",
|
||||||
"flutterMode": "debug",
|
"flutterMode": "debug",
|
||||||
"args": [
|
"args": [
|
||||||
"--flavor",
|
"--flavor",
|
||||||
"prod",
|
"prod",
|
||||||
"--dart-define",
|
|
||||||
"cameraPreviewAspectRatio=240/320",
|
|
||||||
],
|
],
|
||||||
"program": "${workspaceFolder}/lib/main_release.dart",
|
"program": "${workspaceFolder}/lib/main_prod.dart",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "prod-profile (android)",
|
"name": "prod-profile",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"type": "dart",
|
"type": "dart",
|
||||||
"flutterMode": "profile",
|
"flutterMode": "profile",
|
||||||
"args": [
|
"args": [
|
||||||
"--flavor",
|
"--flavor",
|
||||||
"prod",
|
"prod",
|
||||||
"--dart-define",
|
|
||||||
"cameraPreviewAspectRatio=240/320",
|
|
||||||
],
|
],
|
||||||
"program": "${workspaceFolder}/lib/main_release.dart",
|
"program": "${workspaceFolder}/lib/main_prod.dart",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "dev-debug (ios)",
|
"name": "dev-simulator",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"type": "dart",
|
"type": "dart",
|
||||||
"flutterMode": "debug",
|
"flutterMode": "debug",
|
||||||
|
@ -65,20 +57,7 @@
|
||||||
"--flavor",
|
"--flavor",
|
||||||
"dev",
|
"dev",
|
||||||
"--dart-define",
|
"--dart-define",
|
||||||
"cameraPreviewAspectRatio=3/4",
|
"cameraStubImage=assets/camera_stub_image.jpg"
|
||||||
],
|
|
||||||
"program": "${workspaceFolder}/lib/main_dev.dart",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "dev-profile (ios)",
|
|
||||||
"request": "launch",
|
|
||||||
"flutterMode": "profile",
|
|
||||||
"type": "dart",
|
|
||||||
"args": [
|
|
||||||
"--flavor",
|
|
||||||
"dev",
|
|
||||||
"--dart-define",
|
|
||||||
"cameraPreviewAspectRatio=3/4",
|
|
||||||
],
|
],
|
||||||
"program": "${workspaceFolder}/lib/main_dev.dart",
|
"program": "${workspaceFolder}/lib/main_dev.dart",
|
||||||
},
|
},
|
||||||
|
|
5
.vscode/settings.json
vendored
|
@ -7,17 +7,16 @@
|
||||||
"files.watcherExclude": {
|
"files.watcherExclude": {
|
||||||
"**/.fvm": true
|
"**/.fvm": true
|
||||||
},
|
},
|
||||||
"dart.lineLength": 100,
|
"dart.lineLength": 120,
|
||||||
"[dart]": {
|
"[dart]": {
|
||||||
"editor.rulers": [
|
"editor.rulers": [
|
||||||
100,
|
|
||||||
120,
|
120,
|
||||||
],
|
],
|
||||||
"editor.selectionHighlight": true,
|
"editor.selectionHighlight": true,
|
||||||
"editor.suggest.snippetsPreventQuickSuggestions": false,
|
"editor.suggest.snippetsPreventQuickSuggestions": false,
|
||||||
"editor.suggestSelection": "first",
|
"editor.suggestSelection": "first",
|
||||||
"editor.tabCompletion": "onlySnippets",
|
"editor.tabCompletion": "onlySnippets",
|
||||||
"editor.wordBasedSuggestions": false
|
"editor.wordBasedSuggestions": "off"
|
||||||
},
|
},
|
||||||
"dart.doNotFormat": [
|
"dart.doNotFormat": [
|
||||||
"**/generated/**",
|
"**/generated/**",
|
||||||
|
|
6
.vscode/tasks.json
vendored
|
@ -11,8 +11,6 @@
|
||||||
"--flavor",
|
"--flavor",
|
||||||
"dev",
|
"dev",
|
||||||
"--release",
|
"--release",
|
||||||
"--dart-define",
|
|
||||||
"cameraPreviewAspectRatio=240/320",
|
|
||||||
"-t",
|
"-t",
|
||||||
"lib/main_dev.dart",
|
"lib/main_dev.dart",
|
||||||
],
|
],
|
||||||
|
@ -27,8 +25,6 @@
|
||||||
"--flavor",
|
"--flavor",
|
||||||
"prod",
|
"prod",
|
||||||
"--release",
|
"--release",
|
||||||
"--dart-define",
|
|
||||||
"cameraPreviewAspectRatio=240/320",
|
|
||||||
"-t",
|
"-t",
|
||||||
"lib/main_prod.dart",
|
"lib/main_prod.dart",
|
||||||
],
|
],
|
||||||
|
@ -43,8 +39,6 @@
|
||||||
"--flavor",
|
"--flavor",
|
||||||
"prod",
|
"prod",
|
||||||
"--release",
|
"--release",
|
||||||
"--dart-define",
|
|
||||||
"cameraPreviewAspectRatio=240/320",
|
|
||||||
"-t",
|
"-t",
|
||||||
"lib/main_prod.dart",
|
"lib/main_prod.dart",
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
**Privacy Policy**
|
**Privacy Policy**
|
||||||
|
|
||||||
I, Vodemn, built the Material Lightmeter app as a Free app. This app is provided at no cost and is intended for use as is.
|
I, Vadim Turko, built the Material Lightmeter app as a Free app. This app is provided at no cost and is intended for use as is.
|
||||||
|
|
||||||
**Information Collection and Use**
|
**Information Collection and Use**
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ This app contains links to other sites. If you click on a third-party link, you
|
||||||
|
|
||||||
I may update our Privacy Policy from time to time. Thus, you are advised to review this page periodically for any changes. I will notify you of any changes by posting the new Privacy Policy on this page.
|
I may update our Privacy Policy from time to time. Thus, you are advised to review this page periodically for any changes. I will notify you of any changes by posting the new Privacy Policy on this page.
|
||||||
|
|
||||||
This policy is effective as of 2023-02-24
|
This policy is effective as of 2024-01-04
|
||||||
|
|
||||||
**Contact Us**
|
**Contact Us**
|
||||||
|
|
||||||
|
|
43
README.md
|
@ -1,12 +1,15 @@
|
||||||
<img src="resources/social_preview.png" width="100%" />
|
<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](#table-of-contents)
|
- [Table of contents](#table-of-contents)
|
||||||
- [Backstory](#backstory)
|
- [Backstory](#backstory)
|
||||||
- [Screenshots](#screenshots)
|
- [Screenshots](#screenshots)
|
||||||
- [Development](#development)
|
- [Development](#development)
|
||||||
- [Contribution](#contribution)
|
- [Support](#support)
|
||||||
- [iOS Limitations](#ios-limitations)
|
- [iOS Limitations](#ios-limitations)
|
||||||
|
|
||||||
# Backstory
|
# Backstory
|
||||||
|
@ -33,7 +36,20 @@ Without further delay behold my new Lightmeter app inspired by Material You (a.k
|
||||||
|
|
||||||
To build this app you need to install Flutter 3.10.0 stable. [How to install](https://docs.flutter.dev/get-started/install).
|
To build this app you need to install Flutter 3.10.0 stable. [How to install](https://docs.flutter.dev/get-started/install).
|
||||||
|
|
||||||
### 3. Project setup
|
### 2. Project setup
|
||||||
|
|
||||||
|
#### Restore _constants.dart_ file
|
||||||
|
|
||||||
|
Create a file _lib/constants.dart_ and paste the following content:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
const String contactEmail = '';
|
||||||
|
const String iapServerUrl = '';
|
||||||
|
const String issuesReportUrl = '';
|
||||||
|
const String sourceCodeUrl = '';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Stub IAP package
|
||||||
|
|
||||||
As part of the app's functionallity is in the private repo, you have to replace these lines in _pubspec.yaml_:
|
As part of the app's functionallity is in the private repo, you have to replace these lines in _pubspec.yaml_:
|
||||||
|
|
||||||
|
@ -66,29 +82,20 @@ flutter pub get
|
||||||
flutter pub run intl_utils:generate
|
flutter pub run intl_utils:generate
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4. (Optional) Install Firebase
|
### 3. (Optional) Install Firebase
|
||||||
|
|
||||||
Out of the box Firebase Crashlytics won't work. If you want to add Crashlytics to your local build please follow [this guide](https://firebase.google.com/docs/flutter/setup).
|
Out of the box Firebase Crashlytics won't work. If you want to add Crashlytics to your local build please follow [this guide](https://firebase.google.com/docs/flutter/setup).
|
||||||
|
|
||||||
### 5. Build
|
### 4. Build
|
||||||
|
|
||||||
#### Android
|
- Checkout [Build .apk](.github/workflows/build_apk.yml) workflow for Android
|
||||||
|
- Checkout [Build .ipa](.github/workflows/build_ipa.yml) workflow for iOS
|
||||||
|
|
||||||
You can build an apk by running the following command from the root of the repository:
|
# Support
|
||||||
|
|
||||||
```console
|
To report a bug or suggest a new feature open a new [issue](https://github.com/vodemn/m3_lightmeter/issues). To contribute to the project feel free to open a Pull Request, but you need to follow this [style guide](doc/style_guide.md).
|
||||||
flutter build apk --release --flavor dev --dart-define cameraPreviewAspectRatio=240/320 -t lib/main_dev.dart
|
|
||||||
```
|
|
||||||
|
|
||||||
### iOS
|
In case you have any other questions please contact me via [email](mailto:contact.vodemn@gmail.com?subject="Lightmeter").
|
||||||
|
|
||||||
TBD
|
|
||||||
|
|
||||||
# Contribution
|
|
||||||
|
|
||||||
To report a bug or suggest a new feature open a new [issue](https://github.com/vodemn/m3_lightmeter/issues).
|
|
||||||
|
|
||||||
In case you want to help develop this project feel free to open a Pull Request, but you need to follow this [style guide](doc/style_guide.md).
|
|
||||||
|
|
||||||
# iOS Limitations
|
# iOS Limitations
|
||||||
|
|
||||||
|
|
|
@ -75,12 +75,13 @@ android {
|
||||||
flavorDimensions "app"
|
flavorDimensions "app"
|
||||||
productFlavors {
|
productFlavors {
|
||||||
dev {
|
dev {
|
||||||
applicationId "com.vodemn.lightmeter.dev"
|
resValue "string", "app_name", "Lightmeter (DEV)"
|
||||||
dimension "app"
|
dimension "app"
|
||||||
signingConfig signingConfigs.release
|
signingConfig signingConfigs.release
|
||||||
|
applicationIdSuffix ".dev"
|
||||||
}
|
}
|
||||||
prod {
|
prod {
|
||||||
applicationId "com.vodemn.lightmeter"
|
resValue "string", "app_name", "Lightmeter"
|
||||||
dimension "app"
|
dimension "app"
|
||||||
signingConfig signingConfigs.release
|
signingConfig signingConfigs.release
|
||||||
}
|
}
|
||||||
|
|
BIN
android/app/src/dev/ic_launcher-playstore.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
android/app/src/dev/res/mipmap-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 2 KiB |
BIN
android/app/src/dev/res/mipmap-hdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
android/app/src/dev/res/mipmap-hdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
android/app/src/dev/res/mipmap-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
android/app/src/dev/res/mipmap-mdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
android/app/src/dev/res/mipmap-mdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
android/app/src/dev/res/mipmap-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
android/app/src/dev/res/mipmap-xhdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
android/app/src/dev/res/mipmap-xhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
android/app/src/dev/res/mipmap-xxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
android/app/src/dev/res/mipmap-xxhdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
android/app/src/dev/res/mipmap-xxhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 8.6 KiB |
BIN
android/app/src/dev/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
After Width: | Height: | Size: 11 KiB |
BIN
android/app/src/dev/res/mipmap-xxxhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="ic_launcher_background">#212121</color>
|
||||||
|
</resources>
|
|
@ -3,7 +3,7 @@
|
||||||
package="com.vodemn.lightmeter">
|
package="com.vodemn.lightmeter">
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:label="Lightmeter"
|
android:label="@string/app_name"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher">
|
||||||
<activity
|
<activity
|
||||||
|
@ -14,6 +14,7 @@
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
|
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||||
the Android process has started. This theme is visible to the user
|
the Android process has started. This theme is visible to the user
|
||||||
|
|
|
@ -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="@drawable/ic_launcher_foreground"/>
|
|
||||||
</adaptive-icon>
|
|
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 3 KiB |
Before Width: | Height: | Size: 784 B |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 2 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 8.3 KiB |
Before Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 10 KiB |
11
android/app/src/main/res/xml/data_extraction_rules.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<data-extraction-rules>
|
||||||
|
<cloud-backup>
|
||||||
|
<exclude domain="sharedpref" path="FlutterSecureStorage"/>
|
||||||
|
<exclude domain="sharedpref" path="FlutterSecureKeyStorage"/>
|
||||||
|
</cloud-backup>
|
||||||
|
<device-transfer>
|
||||||
|
<exclude domain="sharedpref" path="FlutterSecureStorage"/>
|
||||||
|
<exclude domain="sharedpref" path="FlutterSecureKeyStorage"/>
|
||||||
|
</device-transfer>
|
||||||
|
</data-extraction-rules>
|
BIN
android/app/src/prod/ic_launcher-playstore.png
Normal file
After Width: | Height: | Size: 15 KiB |
|
@ -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="@mipmap/ic_launcher_foreground"/>
|
||||||
|
</adaptive-icon>
|
|
@ -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="@mipmap/ic_launcher_foreground"/>
|
||||||
|
</adaptive-icon>
|
BIN
android/app/src/prod/res/mipmap-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
android/app/src/prod/res/mipmap-hdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
android/app/src/prod/res/mipmap-hdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 3 KiB |
BIN
android/app/src/prod/res/mipmap-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 787 B |
BIN
android/app/src/prod/res/mipmap-mdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
android/app/src/prod/res/mipmap-mdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
android/app/src/prod/res/mipmap-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 2 KiB |
BIN
android/app/src/prod/res/mipmap-xhdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
android/app/src/prod/res/mipmap-xhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
android/app/src/prod/res/mipmap-xxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 4.7 KiB |
BIN
android/app/src/prod/res/mipmap-xxhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
android/app/src/prod/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 7.1 KiB |
BIN
android/app/src/prod/res/mipmap-xxxhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 10 KiB |
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="ic_launcher_background">#212121</color>
|
||||||
|
</resources>
|
11
assets/README.md
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# 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/camera_stub_image.jpg
Normal file
After Width: | Height: | Size: 899 KiB |
Before Width: | Height: | Size: 3.9 KiB |
BIN
assets/launcher_icon_dev_1024.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
assets/launcher_icon_dev_512.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
assets/launcher_icon_prod_1024.png
Executable file
After Width: | Height: | Size: 14 KiB |
BIN
assets/launcher_icon_prod_512.png
Normal file
After Width: | Height: | Size: 6 KiB |
Before Width: | Height: | Size: 2.2 KiB |
|
@ -1,34 +1,9 @@
|
||||||
library m3_lightmeter_iap;
|
library m3_lightmeter_iap;
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.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/data/models/iap_product.dart';
|
||||||
|
|
||||||
export 'src/providers/equipment_profile_provider.dart';
|
|
||||||
export 'src/providers/films_provider.dart';
|
|
||||||
export 'src/providers/iap_products_provider.dart';
|
export 'src/providers/iap_products_provider.dart';
|
||||||
|
export 'src/data/iap_storage_service.dart';
|
||||||
|
|
||||||
class IAPProviders extends StatelessWidget {
|
const List<Film> films = [];
|
||||||
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,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
17
iap/lib/src/data/iap_storage_service.dart
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
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) {}
|
||||||
|
}
|
|
@ -6,8 +6,26 @@ enum IAPProductStatus {
|
||||||
|
|
||||||
enum IAPProductType { paidFeatures }
|
enum IAPProductType { paidFeatures }
|
||||||
|
|
||||||
abstract class IAPProduct {
|
class IAPProduct {
|
||||||
const IAPProduct._();
|
final String storeId;
|
||||||
|
final IAPProductStatus status;
|
||||||
|
|
||||||
IAPProductStatus get status => IAPProductStatus.purchasable;
|
const IAPProduct({
|
||||||
|
required this.storeId,
|
||||||
|
this.status = IAPProductStatus.purchasable,
|
||||||
|
});
|
||||||
|
|
||||||
|
IAPProduct copyWith({IAPProductStatus? status}) => IAPProduct(
|
||||||
|
storeId: storeId,
|
||||||
|
status: status ?? this.status,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
extension IAPProductTypeExtension on IAPProductType {
|
||||||
|
String get storeId {
|
||||||
|
switch (this) {
|
||||||
|
case IAPProductType.paidFeatures:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,12 +2,15 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:m3_lightmeter_iap/src/data/models/iap_product.dart';
|
import 'package:m3_lightmeter_iap/src/data/models/iap_product.dart';
|
||||||
|
|
||||||
class IAPProductsProvider extends StatefulWidget {
|
class IAPProductsProvider extends StatefulWidget {
|
||||||
|
final String apiUrl;
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
|
||||||
const IAPProductsProvider({required this.child, super.key});
|
const IAPProductsProvider({required this.apiUrl, required this.child, super.key});
|
||||||
|
|
||||||
static IAPProductsProviderState of(BuildContext context) {
|
static IAPProductsProviderState of(BuildContext context) => IAPProductsProvider.maybeOf(context)!;
|
||||||
return context.findAncestorStateOfType<IAPProductsProviderState>()!;
|
|
||||||
|
static IAPProductsProviderState? maybeOf(BuildContext context) {
|
||||||
|
return context.findAncestorStateOfType<IAPProductsProviderState>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -18,7 +21,12 @@ class IAPProductsProviderState extends State<IAPProductsProvider> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return IAPProducts(
|
return IAPProducts(
|
||||||
products: const [],
|
products: [
|
||||||
|
IAPProduct(
|
||||||
|
storeId: IAPProductType.paidFeatures.storeId,
|
||||||
|
status: IAPProductStatus.purchased,
|
||||||
|
)
|
||||||
|
],
|
||||||
child: widget.child,
|
child: widget.child,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -35,13 +43,27 @@ class IAPProducts extends InheritedModel<IAPProductType> {
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
static IAPProduct? productOf(BuildContext context, IAPProductType type) => null;
|
static IAPProduct? productOf(BuildContext context, IAPProductType type) {
|
||||||
|
final IAPProducts? result = InheritedModel.inheritFrom<IAPProducts>(context, aspect: type);
|
||||||
|
return result!._findProduct(type);
|
||||||
|
}
|
||||||
|
|
||||||
static bool isPurchased(BuildContext context, IAPProductType type) => false;
|
static bool isPurchased(BuildContext context, IAPProductType type) {
|
||||||
|
final IAPProducts? result = InheritedModel.inheritFrom<IAPProducts>(context, aspect: type);
|
||||||
|
return result!._findProduct(type)?.status == IAPProductStatus.purchased;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool updateShouldNotify(IAPProducts oldWidget) => false;
|
bool updateShouldNotify(IAPProducts oldWidget) => false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool updateShouldNotifyDependent(covariant IAPProducts oldWidget, Set<IAPProductType> dependencies) => false;
|
bool updateShouldNotifyDependent(IAPProducts oldWidget, Set<IAPProductType> dependencies) => false;
|
||||||
|
|
||||||
|
IAPProduct? _findProduct(IAPProductType type) {
|
||||||
|
try {
|
||||||
|
return products.firstWhere((element) => element.storeId == type.storeId);
|
||||||
|
} catch (_) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
114
integration_test/mocks/paid_features_mock.dart
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
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 List<EquipmentProfile> equipmentProfiles;
|
||||||
|
final String selectedEquipmentProfileId;
|
||||||
|
final List<Film> films;
|
||||||
|
final Film selectedFilm;
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
const MockIAPProviders({
|
||||||
|
this.equipmentProfiles = const [],
|
||||||
|
this.selectedEquipmentProfileId = '',
|
||||||
|
this.films = mockFilms,
|
||||||
|
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: const [
|
||||||
|
NdValue(0),
|
||||||
|
NdValue(2),
|
||||||
|
NdValue(4),
|
||||||
|
NdValue(8),
|
||||||
|
],
|
||||||
|
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;
|
||||||
|
}
|
59
integration_test/utils/platform_channel_mock.dart
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
85
integration_test/utils/widget_tester_actions.dart
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
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)));
|
||||||
|
await pumpAndSettle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
# Uncomment this line to define a global platform for your project
|
# Uncomment this line to define a global platform for your project
|
||||||
# platform :ios, '11.0'
|
platform :ios, '11.0'
|
||||||
|
|
||||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||||
|
@ -40,6 +40,12 @@ post_install do |installer|
|
||||||
|
|
||||||
# Start of the permission_handler configuration
|
# Start of the permission_handler configuration
|
||||||
target.build_configurations.each do |config|
|
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
|
# 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'] ||= [
|
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
|
||||||
'$(inherited)',
|
'$(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>"; };
|
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>"; };
|
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>"; };
|
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
97C146EE1CF9000F007C117D /* Lightmeter.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Lightmeter.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
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>"; };
|
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>"; };
|
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
|
@ -95,7 +95,7 @@
|
||||||
97C146EF1CF9000F007C117D /* Products */ = {
|
97C146EF1CF9000F007C117D /* Products */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
97C146EE1CF9000F007C117D /* Runner.app */,
|
97C146EE1CF9000F007C117D /* Lightmeter.app */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -154,6 +154,7 @@
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
45F53C083F2EA48EF231DA16 /* [CP] Embed Pods Frameworks */,
|
45F53C083F2EA48EF231DA16 /* [CP] Embed Pods Frameworks */,
|
||||||
|
FF00F85CE432774850A0EDB7 /* [firebase_crashlytics] Crashlytics Upload Symbols */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
|
@ -161,7 +162,7 @@
|
||||||
);
|
);
|
||||||
name = Runner;
|
name = Runner;
|
||||||
productName = Runner;
|
productName = Runner;
|
||||||
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
|
productReference = 97C146EE1CF9000F007C117D /* Lightmeter.app */;
|
||||||
productType = "com.apple.product-type.application";
|
productType = "com.apple.product-type.application";
|
||||||
};
|
};
|
||||||
/* End PBXNativeTarget section */
|
/* End PBXNativeTarget section */
|
||||||
|
@ -242,6 +243,7 @@
|
||||||
files = (
|
files = (
|
||||||
);
|
);
|
||||||
inputPaths = (
|
inputPaths = (
|
||||||
|
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
|
||||||
);
|
);
|
||||||
name = "Thin Binary";
|
name = "Thin Binary";
|
||||||
outputPaths = (
|
outputPaths = (
|
||||||
|
@ -282,6 +284,29 @@
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
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 */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
@ -370,18 +395,26 @@
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-prod";
|
||||||
|
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
DEVELOPMENT_TEAM = 489Z6UQMGN;
|
DEVELOPMENT_TEAM = "";
|
||||||
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 489Z6UQMGN;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = Lightmeter;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter;
|
PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = Lightmeter;
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Lightmeter Development";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
@ -499,18 +532,26 @@
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-prod";
|
||||||
|
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
DEVELOPMENT_TEAM = 489Z6UQMGN;
|
DEVELOPMENT_TEAM = "";
|
||||||
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 489Z6UQMGN;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = Lightmeter;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter;
|
PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = Lightmeter;
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Lightmeter Development";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
|
@ -522,18 +563,26 @@
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-prod";
|
||||||
|
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
DEVELOPMENT_TEAM = 489Z6UQMGN;
|
DEVELOPMENT_TEAM = "";
|
||||||
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 489Z6UQMGN;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = Lightmeter;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter;
|
PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = Lightmeter;
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Lightmeter Development";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
@ -599,18 +648,23 @@
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-dev";
|
||||||
|
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
DEVELOPMENT_TEAM = 489Z6UQMGN;
|
DEVELOPMENT_TEAM = 489Z6UQMGN;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = "Lightmeter (DEV)";
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter.dev;
|
PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter.dev;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "Lightmeter (DEV)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
|
@ -674,18 +728,23 @@
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-dev";
|
||||||
|
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
DEVELOPMENT_TEAM = 489Z6UQMGN;
|
DEVELOPMENT_TEAM = 489Z6UQMGN;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = "Lightmeter (DEV)";
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter.dev;
|
PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter.dev;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "Lightmeter (DEV)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
@ -746,18 +805,23 @@
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-dev";
|
||||||
|
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
DEVELOPMENT_TEAM = 489Z6UQMGN;
|
DEVELOPMENT_TEAM = 489Z6UQMGN;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = "Lightmeter (DEV)";
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter.dev;
|
PRODUCT_BUNDLE_IDENTIFIER = com.vodemn.lightmeter.dev;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "Lightmeter (DEV)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
BuildableName = "Runner.app"
|
BuildableName = "Lightmeter.app"
|
||||||
BlueprintName = "Runner"
|
BlueprintName = "Runner"
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
|
@ -45,7 +45,7 @@
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
BuildableName = "Runner.app"
|
BuildableName = "Lightmeter.app"
|
||||||
BlueprintName = "Runner"
|
BlueprintName = "Runner"
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
|
@ -62,7 +62,7 @@
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
BuildableName = "Runner.app"
|
BuildableName = "Lightmeter.app"
|
||||||
BlueprintName = "Runner"
|
BlueprintName = "Runner"
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
BuildableName = "Runner.app"
|
BuildableName = "Lightmeter.app"
|
||||||
BlueprintName = "Runner"
|
BlueprintName = "Runner"
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
|
@ -45,7 +45,7 @@
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
BuildableName = "Runner.app"
|
BuildableName = "Lightmeter.app"
|
||||||
BlueprintName = "Runner"
|
BlueprintName = "Runner"
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
|
@ -62,7 +62,7 @@
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
BuildableName = "Runner.app"
|
BuildableName = "Lightmeter.app"
|
||||||
BlueprintName = "Runner"
|
BlueprintName = "Runner"
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "Icon square (dev).png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
After Width: | Height: | Size: 21 KiB |
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "Icon square.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
After Width: | Height: | Size: 14 KiB |
|
@ -1,122 +0,0 @@
|
||||||
{
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 323 B |
Before Width: | Height: | Size: 626 B |
Before Width: | Height: | Size: 1,008 B |
Before Width: | Height: | Size: 476 B |