mirror of
https://github.com/chenasraf/pantry-flutter.git
synced 2026-05-17 17:28:03 +00:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4e53481cdf | |||
| 116eb18693 | |||
| bbdc71c72f | |||
| cf2388db2b | |||
|
|
9fdee69cb9 | ||
| 4a0832a359 | |||
| 88e153b96f | |||
| cf9135e069 | |||
| db7cc6ffab | |||
| ec689d2940 | |||
| 00241b8ace | |||
| eb4d8d3c50 | |||
| ddf0c365a1 | |||
| eafc267e92 | |||
| 291d8c3bb5 | |||
|
|
903fd823d8 | ||
| bca375d701 | |||
| 28f8a269f8 | |||
| c944ec5140 | |||
| 550027e1bc | |||
| 41e8ac13a0 | |||
| d8802690c0 | |||
| 60b16aad30 | |||
| 689e4d6cad | |||
| db3bbc0f17 | |||
|
|
504da80c09 | ||
| 0c575eaa26 | |||
| 38b5d8b464 | |||
| ef2bc851de | |||
|
|
448d85834b | ||
| 7b5f9c1518 | |||
| 67581d04f0 | |||
| be83067fb7 | |||
| ea4590f0ed | |||
|
|
721f32e1ea | ||
| 36a74b39e1 | |||
| 08159faec2 | |||
| 346bfb9d92 | |||
|
|
0b9cda92ca | ||
| 9f45b2344e | |||
|
|
4ae96c37d1 | ||
| 852e9c47f3 |
29
.github/workflows/release.yml
vendored
29
.github/workflows/release.yml
vendored
@@ -93,9 +93,14 @@ jobs:
|
|||||||
uses: chenasraf/workflows/.github/workflows/release-please-fastlane-changelog.yml@master
|
uses: chenasraf/workflows/.github/workflows/release-please-fastlane-changelog.yml@master
|
||||||
with:
|
with:
|
||||||
release-type: dart
|
release-type: dart
|
||||||
fastlane-changelog-dirs: |
|
scopes: |
|
||||||
fastlane/metadata/android/en-US/changelogs
|
ios: fastlane/metadata/ios/en-US/changelogs
|
||||||
fastlane/metadata/ios/en-US/changelogs
|
macos: fastlane/metadata/macos/en-US/changelogs
|
||||||
|
desktop: fastlane/metadata/macos/en-US/changelogs
|
||||||
|
apple: |
|
||||||
|
fastlane/metadata/ios/en-US/changelogs
|
||||||
|
fastlane/metadata/macos/en-US/changelogs
|
||||||
|
android: fastlane/metadata/android/en-US/changelogs
|
||||||
|
|
||||||
build-android:
|
build-android:
|
||||||
needs: [setup, release-please]
|
needs: [setup, release-please]
|
||||||
@@ -105,13 +110,15 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{ needs.release-please.outputs.tag_name }}
|
||||||
|
|
||||||
- name: Setup Java
|
- name: Setup Java
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: "temurin"
|
||||||
java-version: '17'
|
java-version: "17"
|
||||||
cache: 'gradle'
|
cache: "gradle"
|
||||||
|
|
||||||
- name: Setup Flutter
|
- name: Setup Flutter
|
||||||
uses: subosito/flutter-action@v2
|
uses: subosito/flutter-action@v2
|
||||||
@@ -155,14 +162,6 @@ jobs:
|
|||||||
- name: Build split APKs
|
- name: Build split APKs
|
||||||
run: flutter build apk --release --split-per-abi
|
run: flutter build apk --release --split-per-abi
|
||||||
|
|
||||||
- name: Strip dependency metadata from APKs
|
|
||||||
run: |
|
|
||||||
pip install apksigtool
|
|
||||||
APK_DIR=build/app/outputs/flutter-apk
|
|
||||||
for apk in $APK_DIR/app-*-release.apk; do
|
|
||||||
python3 -m apksigtool remove-signing-block --block-id 0x504b4453 "$apk"
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Build App Bundle
|
- name: Build App Bundle
|
||||||
run: flutter build appbundle --release --obfuscate --split-debug-info=build/debug-info-aab
|
run: flutter build appbundle --release --obfuscate --split-debug-info=build/debug-info-aab
|
||||||
- name: Rename artifacts
|
- name: Rename artifacts
|
||||||
@@ -198,6 +197,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{ needs.release-please.outputs.tag_name }}
|
||||||
|
|
||||||
- name: Setup Flutter
|
- name: Setup Flutter
|
||||||
uses: subosito/flutter-action@v2
|
uses: subosito/flutter-action@v2
|
||||||
|
|||||||
67
CHANGELOG.md
67
CHANGELOG.md
@@ -1,5 +1,72 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [0.13.0](https://github.com/chenasraf/pantry-flutter/compare/v0.12.0...v0.13.0) (2026-05-15)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add trash view ([eb4d8d3](https://github.com/chenasraf/pantry-flutter/commit/eb4d8d3c509e6fe1c6ef998caaa58f6bd9a55a53))
|
||||||
|
* add undo action for checking items ([ddf0c36](https://github.com/chenasraf/pantry-flutter/commit/ddf0c365a1ea4fb27f66fc19a7c5ffd7d72f6de7))
|
||||||
|
* improve ui for larger devices ([eafc267](https://github.com/chenasraf/pantry-flutter/commit/eafc267e92b275796e1edb746c3c3b9dc75925e7))
|
||||||
|
* **ios:** open full file picker when running on macOS ([00241b8](https://github.com/chenasraf/pantry-flutter/commit/00241b8aceeda5175e0989f017031a94b6c53581))
|
||||||
|
* **macos:** go back by using Esc key ([88e153b](https://github.com/chenasraf/pantry-flutter/commit/88e153b96f249f4a8d8f19465a31cde7aa3ac8e0))
|
||||||
|
* switch between photos in photo view ([cf9135e](https://github.com/chenasraf/pantry-flutter/commit/cf9135e0695f70b8c8c658421306f6cda610b6b4))
|
||||||
|
|
||||||
|
## [0.12.0](https://github.com/chenasraf/pantry-flutter/compare/v0.11.0...v0.12.0) (2026-05-15)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add setting to show spacing between categories in checklist items ([689e4d6](https://github.com/chenasraf/pantry-flutter/commit/689e4d6cad89a84621b77e300198d12ac43131ff))
|
||||||
|
* create new lists from the list selector ([41e8ac1](https://github.com/chenasraf/pantry-flutter/commit/41e8ac13a0ab78436bc2674220ed282f8410862d))
|
||||||
|
* share photos, links, and text to Pantry from other apps ([60b16aa](https://github.com/chenasraf/pantry-flutter/commit/60b16aad309ec0f02b542c53a7bfafb9f9652da3))
|
||||||
|
* take photos directly from the photo board ([d880269](https://github.com/chenasraf/pantry-flutter/commit/d8802690c0a3ab80346f84ea1df4b3774ba6e4ee))
|
||||||
|
|
||||||
|
## [0.11.0](https://github.com/chenasraf/pantry-flutter/compare/v0.10.1...v0.11.0) (2026-05-12)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add setting to require checkbox tap to complete checklist items ([ef2bc85](https://github.com/chenasraf/pantry-flutter/commit/ef2bc851deedc180dda51fbfb7378aef7145cf5f))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* preserve subpath for Nextcloud instances hosted on sub-paths ([0c575ea](https://github.com/chenasraf/pantry-flutter/commit/0c575eaa2601dc8c83c6b874f2d81b54a0f6bf01))
|
||||||
|
|
||||||
|
## [0.10.1](https://github.com/chenasraf/pantry-flutter/compare/v0.10.0...v0.10.1) (2026-04-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* make markdown links clickable ([7b5f9c1](https://github.com/chenasraf/pantry-flutter/commit/7b5f9c151845dde90275a8289b3114483d2b214d))
|
||||||
|
|
||||||
|
## [0.10.0](https://github.com/chenasraf/pantry-flutter/compare/v0.9.10...v0.10.0) (2026-04-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* update notes view & edit ui ([36a74b3](https://github.com/chenasraf/pantry-flutter/commit/36a74b39e1beb37fc2f1446f8d45945a22289c6b))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* bug where note grid would not clip correctly ([08159fa](https://github.com/chenasraf/pantry-flutter/commit/08159faec22422da983f23685c53b45088d74b2a))
|
||||||
|
|
||||||
|
## [0.9.10](https://github.com/chenasraf/pantry-flutter/compare/v0.9.9...v0.9.10) (2026-04-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Build System
|
||||||
|
|
||||||
|
* fix signing ([9f45b23](https://github.com/chenasraf/pantry-flutter/commit/9f45b2344ef87708d55889e8fb80f465808fb0c7))
|
||||||
|
|
||||||
|
## [0.9.9](https://github.com/chenasraf/pantry-flutter/compare/v0.9.8...v0.9.9) (2026-04-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Build System
|
||||||
|
|
||||||
|
* re-sign with stripping ([852e9c4](https://github.com/chenasraf/pantry-flutter/commit/852e9c47f3cf11145a72ed78b6415ecd0da2b111))
|
||||||
|
|
||||||
## [0.9.8](https://github.com/chenasraf/pantry-flutter/compare/v0.9.7...v0.9.8) (2026-04-19)
|
## [0.9.8](https://github.com/chenasraf/pantry-flutter/compare/v0.9.7...v0.9.8) (2026-04-19)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
75
Gemfile.lock
75
Gemfile.lock
@@ -8,8 +8,8 @@ GEM
|
|||||||
artifactory (3.0.17)
|
artifactory (3.0.17)
|
||||||
atomos (0.1.3)
|
atomos (0.1.3)
|
||||||
aws-eventstream (1.4.0)
|
aws-eventstream (1.4.0)
|
||||||
aws-partitions (1.1237.0)
|
aws-partitions (1.1246.0)
|
||||||
aws-sdk-core (3.244.0)
|
aws-sdk-core (3.246.0)
|
||||||
aws-eventstream (~> 1, >= 1.3.0)
|
aws-eventstream (~> 1, >= 1.3.0)
|
||||||
aws-partitions (~> 1, >= 1.992.0)
|
aws-partitions (~> 1, >= 1.992.0)
|
||||||
aws-sigv4 (~> 1.9)
|
aws-sigv4 (~> 1.9)
|
||||||
@@ -17,19 +17,19 @@ GEM
|
|||||||
bigdecimal
|
bigdecimal
|
||||||
jmespath (~> 1, >= 1.6.1)
|
jmespath (~> 1, >= 1.6.1)
|
||||||
logger
|
logger
|
||||||
aws-sdk-kms (1.123.0)
|
aws-sdk-kms (1.124.0)
|
||||||
aws-sdk-core (~> 3, >= 3.244.0)
|
aws-sdk-core (~> 3, >= 3.244.0)
|
||||||
aws-sigv4 (~> 1.5)
|
aws-sigv4 (~> 1.5)
|
||||||
aws-sdk-s3 (1.219.0)
|
aws-sdk-s3 (1.221.0)
|
||||||
aws-sdk-core (~> 3, >= 3.244.0)
|
aws-sdk-core (~> 3, >= 3.244.0)
|
||||||
aws-sdk-kms (~> 1)
|
aws-sdk-kms (~> 1)
|
||||||
aws-sigv4 (~> 1.5)
|
aws-sigv4 (~> 1.5)
|
||||||
aws-sigv4 (1.12.1)
|
aws-sigv4 (1.12.1)
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
babosa (1.0.4)
|
babosa (1.0.4)
|
||||||
base64 (0.2.0)
|
base64 (0.3.0)
|
||||||
benchmark (0.5.0)
|
benchmark (0.5.0)
|
||||||
bigdecimal (4.1.1)
|
bigdecimal (4.1.2)
|
||||||
claide (1.1.0)
|
claide (1.1.0)
|
||||||
colored (1.2)
|
colored (1.2)
|
||||||
colored2 (3.1.2)
|
colored2 (3.1.2)
|
||||||
@@ -72,14 +72,14 @@ GEM
|
|||||||
faraday_middleware (1.2.1)
|
faraday_middleware (1.2.1)
|
||||||
faraday (~> 1.0)
|
faraday (~> 1.0)
|
||||||
fastimage (2.4.1)
|
fastimage (2.4.1)
|
||||||
fastlane (2.232.2)
|
fastlane (2.234.0)
|
||||||
CFPropertyList (>= 2.3, < 4.0.0)
|
CFPropertyList (>= 2.3, < 5.0.0)
|
||||||
abbrev (~> 0.1.2)
|
abbrev (~> 0.1)
|
||||||
addressable (>= 2.8, < 3.0.0)
|
addressable (>= 2.8, < 3.0.0)
|
||||||
artifactory (~> 3.0)
|
artifactory (~> 3.0)
|
||||||
aws-sdk-s3 (~> 1.197)
|
aws-sdk-s3 (~> 1.197)
|
||||||
babosa (>= 1.0.3, < 2.0.0)
|
babosa (>= 1.0.3, < 2.0.0)
|
||||||
base64 (~> 0.2.0)
|
base64 (~> 0.2)
|
||||||
benchmark (>= 0.1.0)
|
benchmark (>= 0.1.0)
|
||||||
bundler (>= 1.17.3, < 5.0.0)
|
bundler (>= 1.17.3, < 5.0.0)
|
||||||
colored (~> 1.2)
|
colored (~> 1.2)
|
||||||
@@ -92,7 +92,7 @@ GEM
|
|||||||
faraday-cookie_jar (~> 0.0.6)
|
faraday-cookie_jar (~> 0.0.6)
|
||||||
faraday_middleware (~> 1.0)
|
faraday_middleware (~> 1.0)
|
||||||
fastimage (>= 2.1.0, < 3.0.0)
|
fastimage (>= 2.1.0, < 3.0.0)
|
||||||
fastlane-sirp (>= 1.0.0)
|
fastlane-sirp (>= 1.1.0)
|
||||||
gh_inspector (>= 1.1.2, < 2.0.0)
|
gh_inspector (>= 1.1.2, < 2.0.0)
|
||||||
google-apis-androidpublisher_v3 (~> 0.3)
|
google-apis-androidpublisher_v3 (~> 0.3)
|
||||||
google-apis-playcustomapp_v1 (~> 0.1)
|
google-apis-playcustomapp_v1 (~> 0.1)
|
||||||
@@ -105,9 +105,9 @@ GEM
|
|||||||
logger (>= 1.6, < 2.0)
|
logger (>= 1.6, < 2.0)
|
||||||
mini_magick (>= 4.9.4, < 5.0.0)
|
mini_magick (>= 4.9.4, < 5.0.0)
|
||||||
multipart-post (>= 2.0.0, < 3.0.0)
|
multipart-post (>= 2.0.0, < 3.0.0)
|
||||||
mutex_m (~> 0.3.0)
|
mutex_m (~> 0.3)
|
||||||
naturally (~> 2.2)
|
naturally (~> 2.2)
|
||||||
nkf (~> 0.2.0)
|
nkf (~> 0.2)
|
||||||
optparse (>= 0.1.1, < 1.0.0)
|
optparse (>= 0.1.1, < 1.0.0)
|
||||||
ostruct (>= 0.1.0)
|
ostruct (>= 0.1.0)
|
||||||
plist (>= 3.1.0, < 4.0.0)
|
plist (>= 3.1.0, < 4.0.0)
|
||||||
@@ -122,10 +122,9 @@ GEM
|
|||||||
xcodeproj (>= 1.13.0, < 2.0.0)
|
xcodeproj (>= 1.13.0, < 2.0.0)
|
||||||
xcpretty (~> 0.4.1)
|
xcpretty (~> 0.4.1)
|
||||||
xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
|
xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
|
||||||
fastlane-sirp (1.0.0)
|
fastlane-sirp (1.1.0)
|
||||||
sysrandom (~> 1.0)
|
|
||||||
gh_inspector (1.1.3)
|
gh_inspector (1.1.3)
|
||||||
google-apis-androidpublisher_v3 (0.98.0)
|
google-apis-androidpublisher_v3 (0.100.0)
|
||||||
google-apis-core (>= 0.15.0, < 2.a)
|
google-apis-core (>= 0.15.0, < 2.a)
|
||||||
google-apis-core (0.18.0)
|
google-apis-core (0.18.0)
|
||||||
addressable (~> 2.5, >= 2.5.1)
|
addressable (~> 2.5, >= 2.5.1)
|
||||||
@@ -135,11 +134,11 @@ GEM
|
|||||||
mutex_m
|
mutex_m
|
||||||
representable (~> 3.0)
|
representable (~> 3.0)
|
||||||
retriable (>= 2.0, < 4.a)
|
retriable (>= 2.0, < 4.a)
|
||||||
google-apis-iamcredentials_v1 (0.26.0)
|
google-apis-iamcredentials_v1 (0.27.0)
|
||||||
google-apis-core (>= 0.15.0, < 2.a)
|
google-apis-core (>= 0.15.0, < 2.a)
|
||||||
google-apis-playcustomapp_v1 (0.17.0)
|
google-apis-playcustomapp_v1 (0.17.0)
|
||||||
google-apis-core (>= 0.15.0, < 2.a)
|
google-apis-core (>= 0.15.0, < 2.a)
|
||||||
google-apis-storage_v1 (0.61.0)
|
google-apis-storage_v1 (0.62.0)
|
||||||
google-apis-core (>= 0.15.0, < 2.a)
|
google-apis-core (>= 0.15.0, < 2.a)
|
||||||
google-cloud-core (1.8.0)
|
google-cloud-core (1.8.0)
|
||||||
google-cloud-env (>= 1.0, < 3.a)
|
google-cloud-env (>= 1.0, < 3.a)
|
||||||
@@ -147,7 +146,7 @@ GEM
|
|||||||
google-cloud-env (2.1.1)
|
google-cloud-env (2.1.1)
|
||||||
faraday (>= 1.0, < 3.a)
|
faraday (>= 1.0, < 3.a)
|
||||||
google-cloud-errors (1.6.0)
|
google-cloud-errors (1.6.0)
|
||||||
google-cloud-storage (1.59.0)
|
google-cloud-storage (1.60.0)
|
||||||
addressable (~> 2.8)
|
addressable (~> 2.8)
|
||||||
digest-crc (~> 0.4)
|
digest-crc (~> 0.4)
|
||||||
google-apis-core (>= 0.18, < 2)
|
google-apis-core (>= 0.18, < 2)
|
||||||
@@ -169,13 +168,13 @@ GEM
|
|||||||
httpclient (2.9.0)
|
httpclient (2.9.0)
|
||||||
mutex_m
|
mutex_m
|
||||||
jmespath (1.6.2)
|
jmespath (1.6.2)
|
||||||
json (2.19.3)
|
json (2.19.5)
|
||||||
jwt (2.10.2)
|
jwt (2.10.2)
|
||||||
base64
|
base64
|
||||||
logger (1.7.0)
|
logger (1.7.0)
|
||||||
mini_magick (4.13.2)
|
mini_magick (4.13.2)
|
||||||
mini_mime (1.1.5)
|
mini_mime (1.1.5)
|
||||||
multi_json (1.19.1)
|
multi_json (1.21.1)
|
||||||
multipart-post (2.4.1)
|
multipart-post (2.4.1)
|
||||||
mutex_m (0.3.0)
|
mutex_m (0.3.0)
|
||||||
nanaimo (0.4.0)
|
nanaimo (0.4.0)
|
||||||
@@ -186,7 +185,7 @@ GEM
|
|||||||
ostruct (0.6.3)
|
ostruct (0.6.3)
|
||||||
plist (3.7.2)
|
plist (3.7.2)
|
||||||
public_suffix (7.0.5)
|
public_suffix (7.0.5)
|
||||||
rake (13.3.1)
|
rake (13.4.2)
|
||||||
representable (3.2.0)
|
representable (3.2.0)
|
||||||
declarative (< 0.1.0)
|
declarative (< 0.1.0)
|
||||||
trailblazer-option (>= 0.1.1, < 0.2.0)
|
trailblazer-option (>= 0.1.1, < 0.2.0)
|
||||||
@@ -205,7 +204,6 @@ GEM
|
|||||||
simctl (1.6.10)
|
simctl (1.6.10)
|
||||||
CFPropertyList
|
CFPropertyList
|
||||||
naturally
|
naturally
|
||||||
sysrandom (1.0.5)
|
|
||||||
terminal-notifier (2.0.0)
|
terminal-notifier (2.0.0)
|
||||||
terminal-table (3.0.2)
|
terminal-table (3.0.2)
|
||||||
unicode-display_width (>= 1.1.1, < 3)
|
unicode-display_width (>= 1.1.1, < 3)
|
||||||
@@ -243,15 +241,15 @@ CHECKSUMS
|
|||||||
artifactory (3.0.17) sha256=3023d5c964c31674090d655a516f38ca75665c15084140c08b7f2841131af263
|
artifactory (3.0.17) sha256=3023d5c964c31674090d655a516f38ca75665c15084140c08b7f2841131af263
|
||||||
atomos (0.1.3) sha256=7d43b22f2454a36bace5532d30785b06de3711399cb1c6bf932573eda536789f
|
atomos (0.1.3) sha256=7d43b22f2454a36bace5532d30785b06de3711399cb1c6bf932573eda536789f
|
||||||
aws-eventstream (1.4.0) sha256=116bf85c436200d1060811e6f5d2d40c88f65448f2125bc77ffce5121e6e183b
|
aws-eventstream (1.4.0) sha256=116bf85c436200d1060811e6f5d2d40c88f65448f2125bc77ffce5121e6e183b
|
||||||
aws-partitions (1.1237.0) sha256=9b82f529b69ad83a8e4c5e123038924ed5e8f59bd6064a293ef20efc63364841
|
aws-partitions (1.1246.0) sha256=809cd7d38b7ba4ea651c9879248ecf9fd0f8289412e76f26478d2b37064faa1d
|
||||||
aws-sdk-core (3.244.0) sha256=3e458c078b0c5bdee95bc370c3a483374b3224cf730c1f9f0faf849a5d9a18ea
|
aws-sdk-core (3.246.0) sha256=393864ec8948560e69fcccc2e4d256b40c7028eb98930608dd295279e3c4ddcc
|
||||||
aws-sdk-kms (1.123.0) sha256=d405f37e82f8fa32045ca8980be266c0b45b37aaf2012afe0254321a1e811f20
|
aws-sdk-kms (1.124.0) sha256=40d00ab706d7e49fd620270bd0dcb546f266295abdd49b54fec2611e2a41f37c
|
||||||
aws-sdk-s3 (1.219.0) sha256=6a755d7377978525758b3c29185ca6a10128ce2b07555ca37c4549de10c2f1c7
|
aws-sdk-s3 (1.221.0) sha256=a05488eab2083a1e90b02e18479d8f65e401081d671b2d138992a2c5fef85491
|
||||||
aws-sigv4 (1.12.1) sha256=6973ff95cb0fd0dc58ba26e90e9510a2219525d07620c8babeb70ef831826c00
|
aws-sigv4 (1.12.1) sha256=6973ff95cb0fd0dc58ba26e90e9510a2219525d07620c8babeb70ef831826c00
|
||||||
babosa (1.0.4) sha256=18dea450f595462ed7cb80595abd76b2e535db8c91b350f6c4b3d73986c5bc99
|
babosa (1.0.4) sha256=18dea450f595462ed7cb80595abd76b2e535db8c91b350f6c4b3d73986c5bc99
|
||||||
base64 (0.2.0) sha256=0f25e9b21a02a0cc0cea8ef92b2041035d39350946e8789c562b2d1a3da01507
|
base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
|
||||||
benchmark (0.5.0) sha256=465df122341aedcb81a2a24b4d3bd19b6c67c1530713fd533f3ff034e419236c
|
benchmark (0.5.0) sha256=465df122341aedcb81a2a24b4d3bd19b6c67c1530713fd533f3ff034e419236c
|
||||||
bigdecimal (4.1.1) sha256=1c09efab961da45203c8316b0cdaec0ff391dfadb952dd459584b63ebf8054ca
|
bigdecimal (4.1.2) sha256=53d217666027eab4280346fba98e7d5b66baaae1b9c3c1c0ffe89d48188a3fbd
|
||||||
claide (1.1.0) sha256=6d3c5c089dde904d96aa30e73306d0d4bd444b1accb9b3125ce14a3c0183f82e
|
claide (1.1.0) sha256=6d3c5c089dde904d96aa30e73306d0d4bd444b1accb9b3125ce14a3c0183f82e
|
||||||
colored (1.2) sha256=9d82b47ac589ce7f6cab64b1f194a2009e9fd00c326a5357321f44afab2c1d2c
|
colored (1.2) sha256=9d82b47ac589ce7f6cab64b1f194a2009e9fd00c326a5357321f44afab2c1d2c
|
||||||
colored2 (3.1.2) sha256=b13c2bd7eeae2cf7356a62501d398e72fde78780bd26aec6a979578293c28b4a
|
colored2 (3.1.2) sha256=b13c2bd7eeae2cf7356a62501d398e72fde78780bd26aec6a979578293c28b4a
|
||||||
@@ -277,29 +275,29 @@ CHECKSUMS
|
|||||||
faraday-retry (1.0.4) sha256=dc659233777fabf96c69c2ffe56c0a5d2c102af90321a42cc6c90157bcd716aa
|
faraday-retry (1.0.4) sha256=dc659233777fabf96c69c2ffe56c0a5d2c102af90321a42cc6c90157bcd716aa
|
||||||
faraday_middleware (1.2.1) sha256=d45b78c8ee864c4783fbc276f845243d4a7918a67301c052647bacabec0529e9
|
faraday_middleware (1.2.1) sha256=d45b78c8ee864c4783fbc276f845243d4a7918a67301c052647bacabec0529e9
|
||||||
fastimage (2.4.1) sha256=c64bebd46b6fd8943ab70c1e6e85ff728f970f2e48f92ecd249b6bc3a540ad20
|
fastimage (2.4.1) sha256=c64bebd46b6fd8943ab70c1e6e85ff728f970f2e48f92ecd249b6bc3a540ad20
|
||||||
fastlane (2.232.2) sha256=978689f60f0fc3d54699de86ef12be4eda9f5b52217c1798965257c390d2b112
|
fastlane (2.234.0) sha256=b74835681ad9a8e9c0931a5727dad1bab433895ac534c864a1ed5749625d26e9
|
||||||
fastlane-sirp (1.0.0) sha256=66478f25bcd039ec02ccf65625373fca29646fa73d655eb533c915f106c5e641
|
fastlane-sirp (1.1.0) sha256=10bc94f9682efd8e1badfb31452a76dd8981f1f3a33717c765fde6d75b54d847
|
||||||
gh_inspector (1.1.3) sha256=04cca7171b87164e053aa43147971d3b7f500fcb58177698886b48a9fc4a1939
|
gh_inspector (1.1.3) sha256=04cca7171b87164e053aa43147971d3b7f500fcb58177698886b48a9fc4a1939
|
||||||
google-apis-androidpublisher_v3 (0.98.0) sha256=094fb952419c1131c16c4dfa66e0c96e6a2fa33adbe266f614b84b22cbc8c5cb
|
google-apis-androidpublisher_v3 (0.100.0) sha256=7a82935bee985190e8fe23bf5e53df3a27d65dd084114bb71b846b617de16489
|
||||||
google-apis-core (0.18.0) sha256=96b057816feeeab448139ed5b5c78eab7fc2a9d8958f0fbc8217dedffad054ee
|
google-apis-core (0.18.0) sha256=96b057816feeeab448139ed5b5c78eab7fc2a9d8958f0fbc8217dedffad054ee
|
||||||
google-apis-iamcredentials_v1 (0.26.0) sha256=3ff70a10a1d6cddf2554e95b7c5df2c26afdeaeb64100048a355194da19e48a3
|
google-apis-iamcredentials_v1 (0.27.0) sha256=9289f29968610754ef11d98b9ec627f0153f3e2616fef839aef096de529f6d1e
|
||||||
google-apis-playcustomapp_v1 (0.17.0) sha256=d5bc90b705f3f862bab4998086449b0abe704ee1685a84821daa90ca7fa95a78
|
google-apis-playcustomapp_v1 (0.17.0) sha256=d5bc90b705f3f862bab4998086449b0abe704ee1685a84821daa90ca7fa95a78
|
||||||
google-apis-storage_v1 (0.61.0) sha256=b330e599b58e6a01533c189525398d6dbdbaf101ffb0c60145940b57e1c982e8
|
google-apis-storage_v1 (0.62.0) sha256=f62467c36df53287fb0252ebb4da85f9e25d7b4c5809d045c2aab1fc307760c1
|
||||||
google-cloud-core (1.8.0) sha256=e572edcbf189cfcab16590628a516cec3f4f63454b730e59f0b36575120281cf
|
google-cloud-core (1.8.0) sha256=e572edcbf189cfcab16590628a516cec3f4f63454b730e59f0b36575120281cf
|
||||||
google-cloud-env (2.1.1) sha256=cf4bb8c7d517ee1ea692baedf06e0b56ce68007549d8d5a66481aa9f97f46999
|
google-cloud-env (2.1.1) sha256=cf4bb8c7d517ee1ea692baedf06e0b56ce68007549d8d5a66481aa9f97f46999
|
||||||
google-cloud-errors (1.6.0) sha256=1da8476dd706ad04b9d32e3c4b90d07d3463b37d6407cb56d41342ea7647d0a1
|
google-cloud-errors (1.6.0) sha256=1da8476dd706ad04b9d32e3c4b90d07d3463b37d6407cb56d41342ea7647d0a1
|
||||||
google-cloud-storage (1.59.0) sha256=b8c9a5661d775d65ccb279bb1d6be07fd8152576eb0146c2026bd023c4b186b9
|
google-cloud-storage (1.60.0) sha256=b21b752d37945d678a4533be5ef4303f15d33a964d8bc709c7c41c3600f650db
|
||||||
googleauth (1.11.2) sha256=7e6bacaeed7aea3dd66dcea985266839816af6633e9f5983c3c2e0e40a44731e
|
googleauth (1.11.2) sha256=7e6bacaeed7aea3dd66dcea985266839816af6633e9f5983c3c2e0e40a44731e
|
||||||
highline (2.0.3) sha256=2ddd5c127d4692721486f91737307236fe005352d12a4202e26c48614f719479
|
highline (2.0.3) sha256=2ddd5c127d4692721486f91737307236fe005352d12a4202e26c48614f719479
|
||||||
http-cookie (1.0.8) sha256=b14fe0445cf24bf9ae098633e9b8d42e4c07c3c1f700672b09fbfe32ffd41aa6
|
http-cookie (1.0.8) sha256=b14fe0445cf24bf9ae098633e9b8d42e4c07c3c1f700672b09fbfe32ffd41aa6
|
||||||
httpclient (2.9.0) sha256=4b645958e494b2f86c2f8a2f304c959baa273a310e77a2931ddb986d83e498c8
|
httpclient (2.9.0) sha256=4b645958e494b2f86c2f8a2f304c959baa273a310e77a2931ddb986d83e498c8
|
||||||
jmespath (1.6.2) sha256=238d774a58723d6c090494c8879b5e9918c19485f7e840f2c1c7532cf84ebcb1
|
jmespath (1.6.2) sha256=238d774a58723d6c090494c8879b5e9918c19485f7e840f2c1c7532cf84ebcb1
|
||||||
json (2.19.3) sha256=289b0bb53052a1fa8c34ab33cc750b659ba14a5c45f3fcf4b18762dc67c78646
|
json (2.19.5) sha256=218a18553e4801d579ca7e0f5bc72bafd776d7397238a1fb4e74db5b0a812c59
|
||||||
jwt (2.10.2) sha256=31e1ee46f7359883d5e622446969fe9c118c3da87a0b1dca765ce269c3a0c4f4
|
jwt (2.10.2) sha256=31e1ee46f7359883d5e622446969fe9c118c3da87a0b1dca765ce269c3a0c4f4
|
||||||
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
|
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
|
||||||
mini_magick (4.13.2) sha256=71d6258e0e8a3d04a9a0a09784d5d857b403a198a51dd4f882510435eb95ddd9
|
mini_magick (4.13.2) sha256=71d6258e0e8a3d04a9a0a09784d5d857b403a198a51dd4f882510435eb95ddd9
|
||||||
mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef
|
mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef
|
||||||
multi_json (1.19.1) sha256=7aefeff8f2c854bf739931a238e4aea64592845e0c0395c8a7d2eea7fdd631b7
|
multi_json (1.21.1) sha256=e6126a31808e3b4d19f483c775ceac34df190dffa62adfb63a165ee14ba68080
|
||||||
multipart-post (2.4.1) sha256=9872d03a8e552020ca096adadbf5e3cb1cd1cdd6acd3c161136b8a5737cdb4a8
|
multipart-post (2.4.1) sha256=9872d03a8e552020ca096adadbf5e3cb1cd1cdd6acd3c161136b8a5737cdb4a8
|
||||||
mutex_m (0.3.0) sha256=cfcb04ac16b69c4813777022fdceda24e9f798e48092a2b817eb4c0a782b0751
|
mutex_m (0.3.0) sha256=cfcb04ac16b69c4813777022fdceda24e9f798e48092a2b817eb4c0a782b0751
|
||||||
nanaimo (0.4.0) sha256=faf069551bab17f15169c1f74a1c73c220657e71b6e900919897a10d991d0723
|
nanaimo (0.4.0) sha256=faf069551bab17f15169c1f74a1c73c220657e71b6e900919897a10d991d0723
|
||||||
@@ -310,7 +308,7 @@ CHECKSUMS
|
|||||||
ostruct (0.6.3) sha256=95a2ed4a4bd1d190784e666b47b2d3f078e4a9efda2fccf18f84ddc6538ed912
|
ostruct (0.6.3) sha256=95a2ed4a4bd1d190784e666b47b2d3f078e4a9efda2fccf18f84ddc6538ed912
|
||||||
plist (3.7.2) sha256=d37a4527cc1116064393df4b40e1dbbc94c65fa9ca2eec52edf9a13616718a42
|
plist (3.7.2) sha256=d37a4527cc1116064393df4b40e1dbbc94c65fa9ca2eec52edf9a13616718a42
|
||||||
public_suffix (7.0.5) sha256=1a8bb08f1bbea19228d3bed6e5ed908d1cb4f7c2726d18bd9cadf60bc676f623
|
public_suffix (7.0.5) sha256=1a8bb08f1bbea19228d3bed6e5ed908d1cb4f7c2726d18bd9cadf60bc676f623
|
||||||
rake (13.3.1) sha256=8c9e89d09f66a26a01264e7e3480ec0607f0c497a861ef16063604b1b08eb19c
|
rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
|
||||||
representable (3.2.0) sha256=cc29bf7eebc31653586849371a43ffe36c60b54b0a6365b5f7d95ec34d1ebace
|
representable (3.2.0) sha256=cc29bf7eebc31653586849371a43ffe36c60b54b0a6365b5f7d95ec34d1ebace
|
||||||
retriable (3.4.1) sha256=fb3f114b7d492121c158c01f3d5152b5a615c5b70d5877d0bc08c7ec3725c3bc
|
retriable (3.4.1) sha256=fb3f114b7d492121c158c01f3d5152b5a615c5b70d5877d0bc08c7ec3725c3bc
|
||||||
rexml (3.4.4) sha256=19e0a2c3425dfbf2d4fc1189747bdb2f849b6c5e74180401b15734bc97b5d142
|
rexml (3.4.4) sha256=19e0a2c3425dfbf2d4fc1189747bdb2f849b6c5e74180401b15734bc97b5d142
|
||||||
@@ -320,7 +318,6 @@ CHECKSUMS
|
|||||||
security (0.1.5) sha256=3a977a0eca7706e804c96db0dd9619e0a94969fe3aac9680fcfc2bf9b8a833b7
|
security (0.1.5) sha256=3a977a0eca7706e804c96db0dd9619e0a94969fe3aac9680fcfc2bf9b8a833b7
|
||||||
signet (0.21.0) sha256=d617e9fbf24928280d39dcfefba9a0372d1c38187ffffd0a9283957a10a8cd5b
|
signet (0.21.0) sha256=d617e9fbf24928280d39dcfefba9a0372d1c38187ffffd0a9283957a10a8cd5b
|
||||||
simctl (1.6.10) sha256=b99077f4d13ad81eace9f86bf5ba4df1b0b893a4d1b368bd3ed59b5b27f9236b
|
simctl (1.6.10) sha256=b99077f4d13ad81eace9f86bf5ba4df1b0b893a4d1b368bd3ed59b5b27f9236b
|
||||||
sysrandom (1.0.5) sha256=5ac1ac3c2ec64ef76ac91018059f541b7e8f437fbda1ccddb4f2c56a9ccf1e75
|
|
||||||
terminal-notifier (2.0.0) sha256=7a0d2b2212ab9835c07f4b2e22a94cff64149dba1eed203c04835f7991078cea
|
terminal-notifier (2.0.0) sha256=7a0d2b2212ab9835c07f4b2e22a94cff64149dba1eed203c04835f7991078cea
|
||||||
terminal-table (3.0.2) sha256=f951b6af5f3e00203fb290a669e0a85c5dd5b051b3b023392ccfd67ba5abae91
|
terminal-table (3.0.2) sha256=f951b6af5f3e00203fb290a669e0a85c5dd5b051b3b023392ccfd67ba5abae91
|
||||||
trailblazer-option (0.1.2) sha256=20e4f12ea4e1f718c8007e7944ca21a329eee4eed9e0fa5dde6e8ad8ac4344a3
|
trailblazer-option (0.1.2) sha256=20e4f12ea4e1f718c8007e7944ca21a329eee4eed9e0fa5dde6e8ad8ac4344a3
|
||||||
|
|||||||
98
Makefile
98
Makefile
@@ -18,7 +18,6 @@ help:
|
|||||||
@echo ""
|
@echo ""
|
||||||
@echo " Development:"
|
@echo " Development:"
|
||||||
@echo " run Run the app in debug mode"
|
@echo " run Run the app in debug mode"
|
||||||
@echo " webapp-run Run the web app in default browser"
|
|
||||||
@echo " format Format all Dart files"
|
@echo " format Format all Dart files"
|
||||||
@echo " analyze Analyze all Dart files"
|
@echo " analyze Analyze all Dart files"
|
||||||
@echo " check Check all files (format + analyze, no changes)"
|
@echo " check Check all files (format + analyze, no changes)"
|
||||||
@@ -41,20 +40,26 @@ help:
|
|||||||
@echo " android-build-aab Build Android App Bundle"
|
@echo " android-build-aab Build Android App Bundle"
|
||||||
@echo " android-push Build APK and push to device via adb"
|
@echo " android-push Build APK and push to device via adb"
|
||||||
@echo " ios-build Build iOS (no codesign)"
|
@echo " ios-build Build iOS (no codesign)"
|
||||||
@echo " web-build Build web app"
|
@echo " macos-build Build macOS app (.app bundle, no codesign)"
|
||||||
|
@echo " macos-build-pkg Build signed macOS .pkg for App Store"
|
||||||
@echo " build-all Build all platforms"
|
@echo " build-all Build all platforms"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo " Release:"
|
@echo " Release:"
|
||||||
@echo " android-release-apk Build APK and copy to build/release/"
|
@echo " android-release-apk Build APK and copy to build/release/"
|
||||||
@echo " android-release-aab Build AAB and copy to build/release/"
|
@echo " android-release-aab Build AAB and copy to build/release/"
|
||||||
@echo " ios-release Build iOS and create unsigned IPA in build/release/"
|
@echo " ios-release Build IPA and copy to build/release/"
|
||||||
@echo " web-release Build web and create zip in build/release/"
|
@echo " macos-release Build PKG and copy to build/release/"
|
||||||
@echo " release-all Build and release all platforms"
|
@echo " release-all Build and release all platforms"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo " Deploying:"
|
@echo " Deploying:"
|
||||||
@echo " android-deploy Build AAB and upload to Google Play (TRACK=internal|beta|production, STATUS=draft|completed)"
|
@echo " android-deploy Build AAB and upload to Google Play (TRACK=internal|beta|production, STATUS=draft|completed)"
|
||||||
@echo " android-promote Promote release between tracks (FROM=internal, TO=production, STATUS=draft|completed)"
|
@echo " android-promote Promote release between tracks (FROM=internal, TO=production, STATUS=draft|completed)"
|
||||||
@echo " ios-deploy Build IPA and upload (DEST=testflight|appstore, default: testflight)"
|
@echo " ios-deploy Build IPA and upload (DEST=testflight|appstore, default: testflight)"
|
||||||
|
@echo " ios-submit Submit the existing App Store build for review (no upload)"
|
||||||
|
@echo " macos-deploy Build PKG and upload (DEST=testflight|appstore, default: testflight)"
|
||||||
|
@echo " macos-submit Submit the existing Mac App Store build for review (no upload)"
|
||||||
|
@echo " deploy-production Build and deploy to production (Google Play + App Store)"
|
||||||
|
@echo " deploy-beta Build and deploy to beta (Google Play beta + TestFlight)"
|
||||||
|
|
||||||
# Setup
|
# Setup
|
||||||
.PHONY: get
|
.PHONY: get
|
||||||
@@ -84,9 +89,6 @@ i18n-watch:
|
|||||||
.PHONY: run
|
.PHONY: run
|
||||||
run:
|
run:
|
||||||
flutter run
|
flutter run
|
||||||
.PHONY: webapp-run
|
|
||||||
webapp-run:
|
|
||||||
open http://localhost:5111 & flutter run -d web-server --web-port=5111
|
|
||||||
.PHONY: format
|
.PHONY: format
|
||||||
format:
|
format:
|
||||||
dart format .
|
dart format .
|
||||||
@@ -104,12 +106,15 @@ check:
|
|||||||
.PHONY: test
|
.PHONY: test
|
||||||
test:
|
test:
|
||||||
ifdef FILES
|
ifdef FILES
|
||||||
flutter test $(FILES)else
|
flutter test $(FILES)
|
||||||
flutter testendif
|
else
|
||||||
|
flutter test
|
||||||
|
endif
|
||||||
|
|
||||||
.PHONY: test-coverage
|
.PHONY: test-coverage
|
||||||
test-coverage:
|
test-coverage:
|
||||||
flutter test --coverage @echo "Coverage report generated at coverage/lcov.info"
|
flutter test --coverage
|
||||||
|
@echo "Coverage report generated at coverage/lcov.info"
|
||||||
|
|
||||||
# Building
|
# Building
|
||||||
.PHONY: android-build-apk
|
.PHONY: android-build-apk
|
||||||
@@ -137,11 +142,28 @@ ios-build:
|
|||||||
ios-build-ipa:
|
ios-build-ipa:
|
||||||
flutter build ipa --release --obfuscate --split-debug-info=build/debug-info-ios --dart-define-from-file=.env --export-options-plist=ios/ExportOptions.plist
|
flutter build ipa --release --obfuscate --split-debug-info=build/debug-info-ios --dart-define-from-file=.env --export-options-plist=ios/ExportOptions.plist
|
||||||
|
|
||||||
.PHONY: web-build
|
.PHONY: macos-build
|
||||||
web-build:
|
macos-build:
|
||||||
flutter build web --release
|
flutter build macos --release --obfuscate --split-debug-info=build/debug-info-macos
|
||||||
|
|
||||||
|
.PHONY: macos-build-pkg
|
||||||
|
macos-build-pkg:
|
||||||
|
flutter build macos --config-only --obfuscate --split-debug-info=build/debug-info-macos
|
||||||
|
rm -rf build/macos/Runner.xcarchive build/macos/pkg
|
||||||
|
xcodebuild -workspace macos/Runner.xcworkspace \
|
||||||
|
-scheme Runner \
|
||||||
|
-configuration Release \
|
||||||
|
-archivePath build/macos/Runner.xcarchive \
|
||||||
|
-allowProvisioningUpdates \
|
||||||
|
archive
|
||||||
|
xcodebuild -exportArchive \
|
||||||
|
-archivePath build/macos/Runner.xcarchive \
|
||||||
|
-exportPath build/macos/pkg \
|
||||||
|
-exportOptionsPlist macos/ExportOptions.plist \
|
||||||
|
-allowProvisioningUpdates
|
||||||
|
|
||||||
.PHONY: build-all
|
.PHONY: build-all
|
||||||
build-all: android-build-apk android-build-aab web-build
|
build-all: android-build-apk android-build-aab
|
||||||
|
|
||||||
# Release (build + copy renamed artifacts to build/release/)
|
# Release (build + copy renamed artifacts to build/release/)
|
||||||
.PHONY: android-release-apk
|
.PHONY: android-release-apk
|
||||||
@@ -157,11 +179,17 @@ android-release-aab: android-build-aab
|
|||||||
@echo "-> build/release/pantry-$(VERSION).aab"
|
@echo "-> build/release/pantry-$(VERSION).aab"
|
||||||
|
|
||||||
.PHONY: ios-release
|
.PHONY: ios-release
|
||||||
ios-release: ios-build
|
ios-release: ios-build-ipa
|
||||||
mkdir -p build/release
|
mkdir -p build/release
|
||||||
cp build/ios/ipa/*.ipa build/release/pantry-$(VERSION).ipa
|
cp build/ios/ipa/*.ipa build/release/pantry-$(VERSION).ipa
|
||||||
@echo "-> build/release/pantry-$(VERSION).ipa"
|
@echo "-> build/release/pantry-$(VERSION).ipa"
|
||||||
|
|
||||||
|
.PHONY: macos-release
|
||||||
|
macos-release: macos-build-pkg
|
||||||
|
mkdir -p build/release
|
||||||
|
cp build/macos/pkg/*.pkg build/release/pantry-$(VERSION).pkg
|
||||||
|
@echo "-> build/release/pantry-$(VERSION).pkg"
|
||||||
|
|
||||||
.PHONY: android-upload
|
.PHONY: android-upload
|
||||||
android-upload:
|
android-upload:
|
||||||
@echo "$(or $(TRACK),beta)" | grep -qE '^(internal|alpha|beta|production)$$' || (echo "Error: Invalid TRACK '$(TRACK)'. Must be: internal, alpha, beta, production"; exit 1)
|
@echo "$(or $(TRACK),beta)" | grep -qE '^(internal|alpha|beta|production)$$' || (echo "Error: Invalid TRACK '$(TRACK)'. Must be: internal, alpha, beta, production"; exit 1)
|
||||||
@@ -193,14 +221,41 @@ ios-upload:
|
|||||||
.PHONY: ios-deploy
|
.PHONY: ios-deploy
|
||||||
ios-deploy: ios-build-ipa ios-upload
|
ios-deploy: ios-build-ipa ios-upload
|
||||||
|
|
||||||
.PHONY: web-release
|
.PHONY: ios-submit
|
||||||
web-release: web-build
|
ios-submit:
|
||||||
mkdir -p build/release
|
bundle exec fastlane ios submit
|
||||||
cd build/web && zip -r ../release/pantry-$(VERSION)-web.zip .
|
|
||||||
@echo "-> build/release/pantry-$(VERSION)-web.zip"
|
.PHONY: macos-upload
|
||||||
|
macos-upload:
|
||||||
|
@echo "$(or $(DEST),testflight)" | grep -qE '^(testflight|appstore)$$' || (echo "Error: Invalid DEST '$(DEST)'. Must be: testflight, appstore"; exit 1)
|
||||||
|
@echo "Destination: $(or $(DEST),testflight)"
|
||||||
|
@if [ "$(or $(DEST),testflight)" = "appstore" ]; then \
|
||||||
|
bundle exec fastlane mac release; \
|
||||||
|
else \
|
||||||
|
bundle exec fastlane mac beta; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
.PHONY: macos-deploy
|
||||||
|
macos-deploy: macos-build-pkg macos-upload
|
||||||
|
|
||||||
|
.PHONY: macos-submit
|
||||||
|
macos-submit:
|
||||||
|
bundle exec fastlane mac submit
|
||||||
|
|
||||||
.PHONY: release-all
|
.PHONY: release-all
|
||||||
release-all: build-clean android-release-apk android-release-aab web-release
|
release-all: android-release-apk android-release-aab
|
||||||
|
|
||||||
|
.PHONY: deploy-production
|
||||||
|
deploy-production:
|
||||||
|
$(MAKE) android-deploy TRACK=production STATUS=completed
|
||||||
|
$(MAKE) ios-deploy DEST=appstore
|
||||||
|
$(MAKE) macos-deploy DEST=appstore
|
||||||
|
|
||||||
|
.PHONY: deploy-beta
|
||||||
|
deploy-beta:
|
||||||
|
$(MAKE) android-deploy TRACK=beta STATUS=completed
|
||||||
|
$(MAKE) ios-deploy DEST=testflight
|
||||||
|
$(MAKE) macos-deploy DEST=testflight
|
||||||
|
|
||||||
# CocoaPods
|
# CocoaPods
|
||||||
.PHONY: pods
|
.PHONY: pods
|
||||||
@@ -239,6 +294,7 @@ icons:
|
|||||||
rsvg-convert -w 1024 -h 1024 assets/logo_icon_squircle.svg > assets/icon/icon.png
|
rsvg-convert -w 1024 -h 1024 assets/logo_icon_squircle.svg > assets/icon/icon.png
|
||||||
rsvg-convert -w 1024 -h 1024 assets/logo_icon_square.svg > assets/icon/icon_ios.png
|
rsvg-convert -w 1024 -h 1024 assets/logo_icon_square.svg > assets/icon/icon_ios.png
|
||||||
rsvg-convert -w 1024 -h 1024 assets/logo_icon_foreground.svg > assets/icon/icon_foreground.png
|
rsvg-convert -w 1024 -h 1024 assets/logo_icon_foreground.svg > assets/icon/icon_foreground.png
|
||||||
|
rsvg-convert -w 1024 -h 1024 assets/logo_icon_macos.svg > assets/icon/icon_macos.png
|
||||||
dart run flutter_launcher_icons
|
dart run flutter_launcher_icons
|
||||||
rsvg-convert -w 512 -h 512 assets/logo_icon_squircle.svg > fastlane/metadata/android/en-US/images/icon.png
|
rsvg-convert -w 512 -h 512 assets/logo_icon_squircle.svg > fastlane/metadata/android/en-US/images/icon.png
|
||||||
|
|
||||||
|
|||||||
@@ -43,9 +43,9 @@ It may take a few minutes for your tester status to propagate.
|
|||||||
Download the latest APK from the
|
Download the latest APK from the
|
||||||
[releases page](https://github.com/chenasraf/pantry-flutter/releases) and sideload onto your device.
|
[releases page](https://github.com/chenasraf/pantry-flutter/releases) and sideload onto your device.
|
||||||
|
|
||||||
### iOS
|
### App Store (iOS)
|
||||||
|
|
||||||
[Coming soon — TestFlight]
|
[Install from the App Store](https://apps.apple.com/us/app/pantry-for-nextcloud/id6762161619)
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,11 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependenciesInfo {
|
||||||
|
includeInApk = false
|
||||||
|
includeInBundle = false
|
||||||
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
debug {
|
debug {
|
||||||
applicationIdSuffix = ".debug"
|
applicationIdSuffix = ".debug"
|
||||||
|
|||||||
@@ -27,6 +27,21 @@
|
|||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="image/*" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="image/*" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="text/plain" />
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<!-- Don't delete the meta-data below.
|
<!-- Don't delete the meta-data below.
|
||||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||||
|
|||||||
@@ -17,6 +17,24 @@ subprojects {
|
|||||||
}
|
}
|
||||||
subprojects {
|
subprojects {
|
||||||
project.evaluationDependsOn(":app")
|
project.evaluationDependsOn(":app")
|
||||||
|
|
||||||
|
// Force any Flutter plugin subproject (e.g. receive_sharing_intent)
|
||||||
|
// that defaults to a different Kotlin jvmTarget to match this app's
|
||||||
|
// Java/Kotlin compatibility, avoiding "Inconsistent JVM Target
|
||||||
|
// Compatibility Between Java and Kotlin Tasks" build failures.
|
||||||
|
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile>().configureEach {
|
||||||
|
compilerOptions {
|
||||||
|
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
plugins.withId("com.android.library") {
|
||||||
|
extensions.configure<com.android.build.gradle.LibraryExtension>("android") {
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register<Delete>("clean") {
|
tasks.register<Delete>("clean") {
|
||||||
|
|||||||
BIN
assets/icon/icon_macos.png
Normal file
BIN
assets/icon/icon_macos.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
39
assets/logo_icon_macos.svg
Normal file
39
assets/logo_icon_macos.svg
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
|
||||||
|
<defs>
|
||||||
|
<clipPath id="squircle">
|
||||||
|
<path transform="translate(100 100) scale(1.609375)" d="
|
||||||
|
M256,0 C353,0 406,0 443,18 C468,30 482,44 494,69
|
||||||
|
C512,106 512,159 512,256 C512,353 512,406 494,443
|
||||||
|
C482,468 468,482 443,494 C406,512 353,512 256,512
|
||||||
|
C159,512 106,512 69,494 C44,482 30,468 18,443
|
||||||
|
C0,406 0,353 0,256 C0,159 0,106 18,69
|
||||||
|
C30,44 44,30 69,18 C106,0 159,0 256,0 Z"/>
|
||||||
|
</clipPath>
|
||||||
|
<filter id="dropShadow" x="-10%" y="-10%" width="120%" height="125%">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="14"/>
|
||||||
|
<feOffset dy="14"/>
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA type="linear" slope="0.35"/>
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode/>
|
||||||
|
<feMergeNode in="SourceGraphic"/>
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<linearGradient id="topLight" x1="0" y1="0" x2="0" y2="1">
|
||||||
|
<stop offset="0" stop-color="#FFFFFF" stop-opacity="0.22"/>
|
||||||
|
<stop offset="0.55" stop-color="#FFFFFF" stop-opacity="0"/>
|
||||||
|
<stop offset="1" stop-color="#000000" stop-opacity="0.12"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<g filter="url(#dropShadow)">
|
||||||
|
<g clip-path="url(#squircle)">
|
||||||
|
<rect width="1024" height="1024" fill="#0082C9"/>
|
||||||
|
<g transform="translate(100 100) scale(1.609375) translate(106 106) scale(12.5)">
|
||||||
|
<path fill="#FFFFFF" d="M12,3L2,12H5V20H19V12H22L12,3M12,8.75A2.25,2.25 0 0,1 14.25,11A2.25,2.25 0 0,1 12,13.25A2.25,2.25 0 0,1 9.75,11A2.25,2.25 0 0,1 12,8.75M12,15C13.5,15 16.5,15.75 16.5,17.25V18H7.5V17.25C7.5,15.75 10.5,15 12,15Z"/>
|
||||||
|
</g>
|
||||||
|
<rect width="1024" height="1024" fill="url(#topLight)"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -1,2 +1,2 @@
|
|||||||
metadata_path("./fastlane/metadata/ios")
|
metadata_path("./fastlane/metadata/ios")
|
||||||
screenshots_path("./fastlane/metadata/ios/screenshots")
|
screenshots_path("./fastlane/metadata/ios/en-US/screenshots")
|
||||||
|
|||||||
@@ -202,6 +202,7 @@ platform :ios do
|
|||||||
skip_screenshots: true,
|
skip_screenshots: true,
|
||||||
submit_for_review: true,
|
submit_for_review: true,
|
||||||
precheck_include_in_app_purchases: false,
|
precheck_include_in_app_purchases: false,
|
||||||
|
force: true,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -215,6 +216,108 @@ platform :ios do
|
|||||||
skip_screenshots: true,
|
skip_screenshots: true,
|
||||||
submit_for_review: false,
|
submit_for_review: false,
|
||||||
precheck_include_in_app_purchases: false,
|
precheck_include_in_app_purchases: false,
|
||||||
|
force: true,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "Submit existing App Store build for review (no IPA upload)"
|
||||||
|
lane :submit do
|
||||||
|
deliver(
|
||||||
|
api_key: api_key,
|
||||||
|
metadata_path: File.expand_path("metadata/ios", __dir__),
|
||||||
|
screenshots_path: File.expand_path("metadata/ios/en-US/screenshots", __dir__),
|
||||||
|
skip_binary_upload: true,
|
||||||
|
skip_screenshots: true,
|
||||||
|
submit_for_review: true,
|
||||||
|
precheck_include_in_app_purchases: false,
|
||||||
|
force: true,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# -- macOS --
|
||||||
|
|
||||||
|
platform :mac do
|
||||||
|
def api_key
|
||||||
|
key_id = ENV.fetch("APP_STORE_API_KEY")
|
||||||
|
app_store_connect_api_key(
|
||||||
|
key_id: key_id,
|
||||||
|
issuer_id: ENV.fetch("APP_STORE_ISSUER_ID"),
|
||||||
|
key_filepath: File.join(ENV.fetch("APP_STORE_KEY_PATH"), "AuthKey_#{key_id}.p8"),
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_pkg
|
||||||
|
pkg_path = Dir[File.expand_path("../build/macos/pkg/*.pkg", __dir__)].first
|
||||||
|
UI.user_error!("No PKG found in build/macos/pkg/. Run 'make macos-build-pkg' first.") unless pkg_path
|
||||||
|
pkg_path
|
||||||
|
end
|
||||||
|
|
||||||
|
def sync_release_notes
|
||||||
|
version_code = version_info[:build]
|
||||||
|
changelog_file = File.expand_path("metadata/macos/en-US/changelogs/#{version_code}.txt", __dir__)
|
||||||
|
notes = File.exist?(changelog_file) ? File.read(changelog_file).strip : changelog_notes
|
||||||
|
release_notes_path = File.expand_path("metadata/macos/en-US/release_notes.txt", __dir__)
|
||||||
|
File.write(release_notes_path, notes)
|
||||||
|
UI.message("Synced release notes from build #{version_code} (#{notes.length} chars)")
|
||||||
|
notes
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "Upload to TestFlight (macOS)"
|
||||||
|
lane :beta do
|
||||||
|
notes = sync_release_notes
|
||||||
|
upload_to_testflight(
|
||||||
|
api_key: api_key,
|
||||||
|
pkg: find_pkg,
|
||||||
|
app_platform: "osx",
|
||||||
|
changelog: notes,
|
||||||
|
skip_waiting_for_build_processing: true,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "Upload to Mac App Store"
|
||||||
|
lane :release do
|
||||||
|
sync_release_notes
|
||||||
|
deliver(
|
||||||
|
api_key: api_key,
|
||||||
|
pkg: find_pkg,
|
||||||
|
platform: "osx",
|
||||||
|
metadata_path: File.expand_path("metadata/macos", __dir__),
|
||||||
|
screenshots_path: File.expand_path("metadata/macos/en-US/screenshots", __dir__),
|
||||||
|
skip_screenshots: true,
|
||||||
|
submit_for_review: true,
|
||||||
|
precheck_include_in_app_purchases: false,
|
||||||
|
force: true,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "Sync macOS metadata only (no PKG upload)"
|
||||||
|
lane :metadata do
|
||||||
|
deliver(
|
||||||
|
api_key: api_key,
|
||||||
|
platform: "osx",
|
||||||
|
metadata_path: File.expand_path("metadata/macos", __dir__),
|
||||||
|
screenshots_path: File.expand_path("metadata/macos/en-US/screenshots", __dir__),
|
||||||
|
skip_binary_upload: true,
|
||||||
|
skip_screenshots: true,
|
||||||
|
submit_for_review: false,
|
||||||
|
precheck_include_in_app_purchases: false,
|
||||||
|
force: true,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "Submit existing Mac App Store build for review (no PKG upload)"
|
||||||
|
lane :submit do
|
||||||
|
deliver(
|
||||||
|
api_key: api_key,
|
||||||
|
platform: "osx",
|
||||||
|
metadata_path: File.expand_path("metadata/macos", __dir__),
|
||||||
|
screenshots_path: File.expand_path("metadata/macos/en-US/screenshots", __dir__),
|
||||||
|
skip_binary_upload: true,
|
||||||
|
skip_screenshots: true,
|
||||||
|
submit_for_review: true,
|
||||||
|
precheck_include_in_app_purchases: false,
|
||||||
|
force: true,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -68,6 +68,51 @@ Upload to App Store
|
|||||||
|
|
||||||
Sync iOS metadata only (no IPA upload)
|
Sync iOS metadata only (no IPA upload)
|
||||||
|
|
||||||
|
### ios submit
|
||||||
|
|
||||||
|
```sh
|
||||||
|
[bundle exec] fastlane ios submit
|
||||||
|
```
|
||||||
|
|
||||||
|
Submit existing App Store build for review (no IPA upload)
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
|
||||||
|
## Mac
|
||||||
|
|
||||||
|
### mac beta
|
||||||
|
|
||||||
|
```sh
|
||||||
|
[bundle exec] fastlane mac beta
|
||||||
|
```
|
||||||
|
|
||||||
|
Upload to TestFlight (macOS)
|
||||||
|
|
||||||
|
### mac release
|
||||||
|
|
||||||
|
```sh
|
||||||
|
[bundle exec] fastlane mac release
|
||||||
|
```
|
||||||
|
|
||||||
|
Upload to Mac App Store
|
||||||
|
|
||||||
|
### mac metadata
|
||||||
|
|
||||||
|
```sh
|
||||||
|
[bundle exec] fastlane mac metadata
|
||||||
|
```
|
||||||
|
|
||||||
|
Sync macOS metadata only (no PKG upload)
|
||||||
|
|
||||||
|
### mac submit
|
||||||
|
|
||||||
|
```sh
|
||||||
|
[bundle exec] fastlane mac submit
|
||||||
|
```
|
||||||
|
|
||||||
|
Submit existing Mac App Store build for review (no PKG upload)
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run.
|
This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run.
|
||||||
|
|||||||
2
fastlane/metadata/android/en-US/changelogs/21.txt
Normal file
2
fastlane/metadata/android/en-US/changelogs/21.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Build System
|
||||||
|
- re-sign with stripping
|
||||||
2
fastlane/metadata/android/en-US/changelogs/22.txt
Normal file
2
fastlane/metadata/android/en-US/changelogs/22.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Build System
|
||||||
|
- fix signing
|
||||||
4
fastlane/metadata/android/en-US/changelogs/23.txt
Normal file
4
fastlane/metadata/android/en-US/changelogs/23.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
Features
|
||||||
|
- update notes view & edit ui
|
||||||
|
Bug Fixes
|
||||||
|
- bug where note grid would not clip correctly
|
||||||
2
fastlane/metadata/android/en-US/changelogs/24.txt
Normal file
2
fastlane/metadata/android/en-US/changelogs/24.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Bug Fixes
|
||||||
|
- make markdown links clickable
|
||||||
4
fastlane/metadata/android/en-US/changelogs/25.txt
Normal file
4
fastlane/metadata/android/en-US/changelogs/25.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
Features
|
||||||
|
- add setting to require checkbox tap to complete checklist items
|
||||||
|
Bug Fixes
|
||||||
|
- preserve subpath for Nextcloud instances hosted on sub-paths
|
||||||
5
fastlane/metadata/android/en-US/changelogs/26.txt
Normal file
5
fastlane/metadata/android/en-US/changelogs/26.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Features
|
||||||
|
- add setting to show spacing between categories in checklist items
|
||||||
|
- create new lists from the list selector
|
||||||
|
- share photos, links, and text to Pantry from other apps
|
||||||
|
- take photos directly from the photo board
|
||||||
5
fastlane/metadata/android/en-US/changelogs/27.txt
Normal file
5
fastlane/metadata/android/en-US/changelogs/27.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Features
|
||||||
|
- add trash view
|
||||||
|
- add undo action for checking items
|
||||||
|
- improve ui for larger devices
|
||||||
|
- switch between photos in photo view
|
||||||
2
fastlane/metadata/ios/en-US/changelogs/21.txt
Normal file
2
fastlane/metadata/ios/en-US/changelogs/21.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Build System
|
||||||
|
- re-sign with stripping
|
||||||
2
fastlane/metadata/ios/en-US/changelogs/22.txt
Normal file
2
fastlane/metadata/ios/en-US/changelogs/22.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Build System
|
||||||
|
- fix signing
|
||||||
4
fastlane/metadata/ios/en-US/changelogs/23.txt
Normal file
4
fastlane/metadata/ios/en-US/changelogs/23.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
Features
|
||||||
|
- update notes view & edit ui
|
||||||
|
Bug Fixes
|
||||||
|
- bug where note grid would not clip correctly
|
||||||
2
fastlane/metadata/ios/en-US/changelogs/24.txt
Normal file
2
fastlane/metadata/ios/en-US/changelogs/24.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Bug Fixes
|
||||||
|
- make markdown links clickable
|
||||||
4
fastlane/metadata/ios/en-US/changelogs/25.txt
Normal file
4
fastlane/metadata/ios/en-US/changelogs/25.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
Features
|
||||||
|
- add setting to require checkbox tap to complete checklist items
|
||||||
|
Bug Fixes
|
||||||
|
- preserve subpath for Nextcloud instances hosted on sub-paths
|
||||||
5
fastlane/metadata/ios/en-US/changelogs/26.txt
Normal file
5
fastlane/metadata/ios/en-US/changelogs/26.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Features
|
||||||
|
- add setting to show spacing between categories in checklist items
|
||||||
|
- create new lists from the list selector
|
||||||
|
- share photos, links, and text to Pantry from other apps
|
||||||
|
- take photos directly from the photo board
|
||||||
6
fastlane/metadata/ios/en-US/changelogs/27.txt
Normal file
6
fastlane/metadata/ios/en-US/changelogs/27.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
Features
|
||||||
|
- add trash view
|
||||||
|
- add undo action for checking items
|
||||||
|
- improve ui for larger devices
|
||||||
|
- open full file picker when running on macOS
|
||||||
|
- switch between photos in photo view
|
||||||
1
fastlane/metadata/macos/copyright.txt
Normal file
1
fastlane/metadata/macos/copyright.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
2026 Chen Asraf
|
||||||
5
fastlane/metadata/macos/en-US/changelogs/26.txt
Normal file
5
fastlane/metadata/macos/en-US/changelogs/26.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Features
|
||||||
|
- add setting to show spacing between categories in checklist items
|
||||||
|
- create new lists from the list selector
|
||||||
|
- share photos, links, and text to Pantry from other apps
|
||||||
|
- take photos directly from the photo board
|
||||||
6
fastlane/metadata/macos/en-US/changelogs/27.txt
Normal file
6
fastlane/metadata/macos/en-US/changelogs/27.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
Features
|
||||||
|
- add trash view
|
||||||
|
- add undo action for checking items
|
||||||
|
- improve ui for larger devices
|
||||||
|
- go back by using Esc key
|
||||||
|
- switch between photos in photo view
|
||||||
25
fastlane/metadata/macos/en-US/description.txt
Normal file
25
fastlane/metadata/macos/en-US/description.txt
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
Pantry is a companion app for the Nextcloud Pantry server app. It lets you and your household members collaborate on shared checklists, a photo board, and a notes wall — all stored on your own Nextcloud server.
|
||||||
|
|
||||||
|
* Checklists
|
||||||
|
Create shopping lists and to-do lists with categories, quantities, recurring items, and images. Drag to reorder, sort by name or date, and check items off as you go.
|
||||||
|
|
||||||
|
* Photo Board
|
||||||
|
Upload and organize photos into folders. Add captions, drag to reorder, and browse everything in a clean grid view.
|
||||||
|
|
||||||
|
* Notes Wall
|
||||||
|
Keep shared notes with your household. Color-code them, write in markdown, and pin the important stuff where everyone can see it.
|
||||||
|
|
||||||
|
* Your data, your server
|
||||||
|
Pantry connects directly to your Nextcloud instance. No accounts to create, no cloud services in between. Your data never leaves your server.
|
||||||
|
|
||||||
|
* Features
|
||||||
|
- Shared checklists with categories, quantities, and recurrence
|
||||||
|
- Photo board with folders, captions, and multi-upload
|
||||||
|
- Color-coded notes wall
|
||||||
|
- Drag-and-drop reordering everywhere
|
||||||
|
- Multi-select for bulk actions
|
||||||
|
- Offline caching for fast loading
|
||||||
|
- Material Design 3 with dark mode support
|
||||||
|
- Secure login flow authentication
|
||||||
|
|
||||||
|
* Requires a Nextcloud server with the Pantry app installed. Visit the project page for setup instructions.
|
||||||
1
fastlane/metadata/macos/en-US/keywords.txt
Normal file
1
fastlane/metadata/macos/en-US/keywords.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
nextcloud, checklist, todo, shopping list, notes, self-hosted, household
|
||||||
1
fastlane/metadata/macos/en-US/marketing_url.txt
Normal file
1
fastlane/metadata/macos/en-US/marketing_url.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
https://github.com/chenasraf/pantry-flutter
|
||||||
1
fastlane/metadata/macos/en-US/name.txt
Normal file
1
fastlane/metadata/macos/en-US/name.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Pantry for Nextcloud
|
||||||
1
fastlane/metadata/macos/en-US/privacy_url.txt
Normal file
1
fastlane/metadata/macos/en-US/privacy_url.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
https://casraf.dev/pantry-privacy-policy
|
||||||
1
fastlane/metadata/macos/en-US/promotional_text.txt
Normal file
1
fastlane/metadata/macos/en-US/promotional_text.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Manage your household on your Nextcloud — shared lists, photos & notes.
|
||||||
6
fastlane/metadata/macos/en-US/release_notes.txt
Normal file
6
fastlane/metadata/macos/en-US/release_notes.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
Features
|
||||||
|
- add trash view
|
||||||
|
- add undo action for checking items
|
||||||
|
- improve ui for larger devices
|
||||||
|
- go back by using Esc key
|
||||||
|
- switch between photos in photo view
|
||||||
BIN
fastlane/metadata/macos/en-US/screenshots/0_APP_DESKTOP_0.png
Normal file
BIN
fastlane/metadata/macos/en-US/screenshots/0_APP_DESKTOP_0.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 49 KiB |
BIN
fastlane/metadata/macos/en-US/screenshots/1_APP_DESKTOP_1.png
Normal file
BIN
fastlane/metadata/macos/en-US/screenshots/1_APP_DESKTOP_1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 200 KiB |
BIN
fastlane/metadata/macos/en-US/screenshots/2_APP_DESKTOP_2.png
Normal file
BIN
fastlane/metadata/macos/en-US/screenshots/2_APP_DESKTOP_2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 63 KiB |
1
fastlane/metadata/macos/en-US/subtitle.txt
Normal file
1
fastlane/metadata/macos/en-US/subtitle.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Home lists, photos & notes
|
||||||
1
fastlane/metadata/macos/en-US/support_url.txt
Normal file
1
fastlane/metadata/macos/en-US/support_url.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
https://github.com/chenasraf/pantry-flutter
|
||||||
1
fastlane/metadata/macos/primary_category.txt
Normal file
1
fastlane/metadata/macos/primary_category.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
PRODUCTIVITY
|
||||||
1
fastlane/metadata/macos/primary_first_sub_category.txt
Normal file
1
fastlane/metadata/macos/primary_first_sub_category.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
fastlane/metadata/macos/primary_second_sub_category.txt
Normal file
1
fastlane/metadata/macos/primary_second_sub_category.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
EQq38!t9uA!@RdAkn6umJHo@nDh3ZZwM
|
||||||
1
fastlane/metadata/macos/review_information/demo_user.txt
Normal file
1
fastlane/metadata/macos/review_information/demo_user.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
store-test
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
casraf@pm.me
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Chen
|
||||||
1
fastlane/metadata/macos/review_information/last_name.txt
Normal file
1
fastlane/metadata/macos/review_information/last_name.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Asraf
|
||||||
3
fastlane/metadata/macos/review_information/notes.txt
Normal file
3
fastlane/metadata/macos/review_information/notes.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
1. In the login screen, for the server, use: spider.casraf.dev and click "Connect"
|
||||||
|
2. Use the given username/password to sign in to the Nextcloud website loaded in the default browser
|
||||||
|
3. Click "Grant Access" to grant access to the app inside the in-app browser
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
+972549107970
|
||||||
1
fastlane/metadata/macos/secondary_category.txt
Normal file
1
fastlane/metadata/macos/secondary_category.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
fastlane/metadata/macos/secondary_first_sub_category.txt
Normal file
1
fastlane/metadata/macos/secondary_first_sub_category.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
10
ios/Gemfile
Normal file
10
ios/Gemfile
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
|
gem 'cocoapods'
|
||||||
|
|
||||||
|
# Pin xcodeproj to a commit on master that supports objectVersion 70
|
||||||
|
# (generated by Xcode 16+). Drop this override once a release > 1.27.0
|
||||||
|
# is published on rubygems.
|
||||||
|
gem 'xcodeproj',
|
||||||
|
git: 'https://github.com/CocoaPods/Xcodeproj.git',
|
||||||
|
ref: 'c12d2ae619ae42f947a6b07d865f69948c752df5'
|
||||||
194
ios/Gemfile.lock
Normal file
194
ios/Gemfile.lock
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
GIT
|
||||||
|
remote: https://github.com/CocoaPods/Xcodeproj.git
|
||||||
|
revision: c12d2ae619ae42f947a6b07d865f69948c752df5
|
||||||
|
ref: c12d2ae619ae42f947a6b07d865f69948c752df5
|
||||||
|
specs:
|
||||||
|
xcodeproj (1.27.0)
|
||||||
|
CFPropertyList (>= 2.3.3, < 4.0)
|
||||||
|
atomos (~> 0.1.3)
|
||||||
|
claide (>= 1.0.2, < 2.0)
|
||||||
|
colored2 (~> 3.1)
|
||||||
|
nanaimo (~> 0.4.0)
|
||||||
|
rexml (>= 3.3.6, < 4.0)
|
||||||
|
|
||||||
|
GEM
|
||||||
|
remote: https://rubygems.org/
|
||||||
|
specs:
|
||||||
|
CFPropertyList (3.0.8)
|
||||||
|
activesupport (7.2.3.1)
|
||||||
|
base64
|
||||||
|
benchmark (>= 0.3)
|
||||||
|
bigdecimal
|
||||||
|
concurrent-ruby (~> 1.0, >= 1.3.1)
|
||||||
|
connection_pool (>= 2.2.5)
|
||||||
|
drb
|
||||||
|
i18n (>= 1.6, < 2)
|
||||||
|
logger (>= 1.4.2)
|
||||||
|
minitest (>= 5.1, < 6)
|
||||||
|
securerandom (>= 0.3)
|
||||||
|
tzinfo (~> 2.0, >= 2.0.5)
|
||||||
|
addressable (2.9.0)
|
||||||
|
public_suffix (>= 2.0.2, < 8.0)
|
||||||
|
algoliasearch (1.27.5)
|
||||||
|
httpclient (~> 2.8, >= 2.8.3)
|
||||||
|
json (>= 1.5.1)
|
||||||
|
atomos (0.1.3)
|
||||||
|
base64 (0.3.0)
|
||||||
|
benchmark (0.5.0)
|
||||||
|
bigdecimal (4.1.2)
|
||||||
|
claide (1.1.0)
|
||||||
|
cocoapods (1.16.2)
|
||||||
|
addressable (~> 2.8)
|
||||||
|
claide (>= 1.0.2, < 2.0)
|
||||||
|
cocoapods-core (= 1.16.2)
|
||||||
|
cocoapods-deintegrate (>= 1.0.3, < 2.0)
|
||||||
|
cocoapods-downloader (>= 2.1, < 3.0)
|
||||||
|
cocoapods-plugins (>= 1.0.0, < 2.0)
|
||||||
|
cocoapods-search (>= 1.0.0, < 2.0)
|
||||||
|
cocoapods-trunk (>= 1.6.0, < 2.0)
|
||||||
|
cocoapods-try (>= 1.1.0, < 2.0)
|
||||||
|
colored2 (~> 3.1)
|
||||||
|
escape (~> 0.0.4)
|
||||||
|
fourflusher (>= 2.3.0, < 3.0)
|
||||||
|
gh_inspector (~> 1.0)
|
||||||
|
molinillo (~> 0.8.0)
|
||||||
|
nap (~> 1.0)
|
||||||
|
ruby-macho (>= 2.3.0, < 3.0)
|
||||||
|
xcodeproj (>= 1.27.0, < 2.0)
|
||||||
|
cocoapods-core (1.16.2)
|
||||||
|
activesupport (>= 5.0, < 8)
|
||||||
|
addressable (~> 2.8)
|
||||||
|
algoliasearch (~> 1.0)
|
||||||
|
concurrent-ruby (~> 1.1)
|
||||||
|
fuzzy_match (~> 2.0.4)
|
||||||
|
nap (~> 1.0)
|
||||||
|
netrc (~> 0.11)
|
||||||
|
public_suffix (~> 4.0)
|
||||||
|
typhoeus (~> 1.0)
|
||||||
|
cocoapods-deintegrate (1.0.5)
|
||||||
|
cocoapods-downloader (2.1)
|
||||||
|
cocoapods-plugins (1.0.0)
|
||||||
|
nap
|
||||||
|
cocoapods-search (1.0.1)
|
||||||
|
cocoapods-trunk (1.6.0)
|
||||||
|
nap (>= 0.8, < 2.0)
|
||||||
|
netrc (~> 0.11)
|
||||||
|
cocoapods-try (1.2.0)
|
||||||
|
colored2 (3.1.2)
|
||||||
|
concurrent-ruby (1.3.6)
|
||||||
|
connection_pool (3.0.2)
|
||||||
|
drb (2.2.3)
|
||||||
|
escape (0.0.4)
|
||||||
|
ethon (0.18.0)
|
||||||
|
ffi (>= 1.15.0)
|
||||||
|
logger
|
||||||
|
ffi (1.17.4)
|
||||||
|
ffi (1.17.4-aarch64-linux-gnu)
|
||||||
|
ffi (1.17.4-aarch64-linux-musl)
|
||||||
|
ffi (1.17.4-arm-linux-gnu)
|
||||||
|
ffi (1.17.4-arm-linux-musl)
|
||||||
|
ffi (1.17.4-arm64-darwin)
|
||||||
|
ffi (1.17.4-x86-linux-gnu)
|
||||||
|
ffi (1.17.4-x86-linux-musl)
|
||||||
|
ffi (1.17.4-x86_64-darwin)
|
||||||
|
ffi (1.17.4-x86_64-linux-gnu)
|
||||||
|
ffi (1.17.4-x86_64-linux-musl)
|
||||||
|
fourflusher (2.3.1)
|
||||||
|
fuzzy_match (2.0.4)
|
||||||
|
gh_inspector (1.1.3)
|
||||||
|
httpclient (2.9.0)
|
||||||
|
mutex_m
|
||||||
|
i18n (1.14.8)
|
||||||
|
concurrent-ruby (~> 1.0)
|
||||||
|
json (2.19.5)
|
||||||
|
logger (1.7.0)
|
||||||
|
minitest (5.27.0)
|
||||||
|
molinillo (0.8.0)
|
||||||
|
mutex_m (0.3.0)
|
||||||
|
nanaimo (0.4.0)
|
||||||
|
nap (1.1.0)
|
||||||
|
netrc (0.11.0)
|
||||||
|
public_suffix (4.0.7)
|
||||||
|
rexml (3.4.4)
|
||||||
|
ruby-macho (2.5.1)
|
||||||
|
securerandom (0.4.1)
|
||||||
|
typhoeus (1.6.0)
|
||||||
|
ethon (>= 0.18.0)
|
||||||
|
tzinfo (2.0.6)
|
||||||
|
concurrent-ruby (~> 1.0)
|
||||||
|
|
||||||
|
PLATFORMS
|
||||||
|
aarch64-linux-gnu
|
||||||
|
aarch64-linux-musl
|
||||||
|
arm-linux-gnu
|
||||||
|
arm-linux-musl
|
||||||
|
arm64-darwin
|
||||||
|
ruby
|
||||||
|
x86-linux-gnu
|
||||||
|
x86-linux-musl
|
||||||
|
x86_64-darwin
|
||||||
|
x86_64-linux-gnu
|
||||||
|
x86_64-linux-musl
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
cocoapods
|
||||||
|
xcodeproj!
|
||||||
|
|
||||||
|
CHECKSUMS
|
||||||
|
CFPropertyList (3.0.8) sha256=2c99d0d980536d3d7ab252f7bd59ac8be50fbdd1ff487c98c949bb66bb114261
|
||||||
|
activesupport (7.2.3.1) sha256=11ebed516a43a0bb47346227a35ebae4d9427465a7c9eb197a03d5c8d283cb34
|
||||||
|
addressable (2.9.0) sha256=7fdf6ac3660f7f4e867a0838be3f6cf722ace541dd97767fa42bc6cfa980c7af
|
||||||
|
algoliasearch (1.27.5) sha256=26c1cddf3c2ec4bd60c148389e42702c98fdac862881dc6b07a4c0b89ffec853
|
||||||
|
atomos (0.1.3) sha256=7d43b22f2454a36bace5532d30785b06de3711399cb1c6bf932573eda536789f
|
||||||
|
base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
|
||||||
|
benchmark (0.5.0) sha256=465df122341aedcb81a2a24b4d3bd19b6c67c1530713fd533f3ff034e419236c
|
||||||
|
bigdecimal (4.1.2) sha256=53d217666027eab4280346fba98e7d5b66baaae1b9c3c1c0ffe89d48188a3fbd
|
||||||
|
claide (1.1.0) sha256=6d3c5c089dde904d96aa30e73306d0d4bd444b1accb9b3125ce14a3c0183f82e
|
||||||
|
cocoapods (1.16.2) sha256=0ff1c860f32df3db8b16df09b58da1a6bb2a12fe55f6d5e8be994a74fadd1e5e
|
||||||
|
cocoapods-core (1.16.2) sha256=4bb1b5c420691e60cf36fa227dec6bc48c096c34c97bb7aa512ea7f3246fc12b
|
||||||
|
cocoapods-deintegrate (1.0.5) sha256=517c2a448ef563afe99b6e7668704c27f5de9e02715a88ee9de6974dc1b3f6a2
|
||||||
|
cocoapods-downloader (2.1) sha256=bb6ebe1b3966dc4055de54f7a28b773485ac724fdf575d9bee2212d235e7b6d1
|
||||||
|
cocoapods-plugins (1.0.0) sha256=725d17ce90b52f862e73476623fd91441b4430b742d8a071000831efb440ca9a
|
||||||
|
cocoapods-search (1.0.1) sha256=1b133b0e6719ed439bd840e84a1828cca46425ab73a11eff5e096c3b2df05589
|
||||||
|
cocoapods-trunk (1.6.0) sha256=5f5bda8c172afead48fa2d43a718cf534b1313c367ba1194cebdeb9bfee9ed31
|
||||||
|
cocoapods-try (1.2.0) sha256=145b946c6e7747ed0301d975165157951153d27469e6b2763c83e25c84b9defe
|
||||||
|
colored2 (3.1.2) sha256=b13c2bd7eeae2cf7356a62501d398e72fde78780bd26aec6a979578293c28b4a
|
||||||
|
concurrent-ruby (1.3.6) sha256=6b56837e1e7e5292f9864f34b69c5a2cbc75c0cf5338f1ce9903d10fa762d5ab
|
||||||
|
connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a
|
||||||
|
drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373
|
||||||
|
escape (0.0.4) sha256=e49f44ae2b4f47c6a3abd544ae77fe4157802794e32f19b8e773cbc4dcec4169
|
||||||
|
ethon (0.18.0) sha256=b598afc9f30448cb068b850714b7d6948e941476095d04f90a4ac65b8d6efcb2
|
||||||
|
ffi (1.17.4) sha256=bcd1642e06f0d16fc9e09ac6d49c3a7298b9789bcb58127302f934e437d60acf
|
||||||
|
ffi (1.17.4-aarch64-linux-gnu) sha256=b208f06f91ffd8f5e1193da3cae3d2ccfc27fc36fba577baf698d26d91c080df
|
||||||
|
ffi (1.17.4-aarch64-linux-musl) sha256=9286b7a615f2676245283aef0a0a3b475ae3aae2bb5448baace630bb77b91f39
|
||||||
|
ffi (1.17.4-arm-linux-gnu) sha256=d6dbddf7cb77bf955411af5f187a65b8cd378cb003c15c05697f5feee1cb1564
|
||||||
|
ffi (1.17.4-arm-linux-musl) sha256=9d4838ded0465bef6e2426935f6bcc93134b6616785a84ffd2a3d82bc3cf6f95
|
||||||
|
ffi (1.17.4-arm64-darwin) sha256=19071aaf1419251b0a46852abf960e77330a3b334d13a4ab51d58b31a937001b
|
||||||
|
ffi (1.17.4-x86-linux-gnu) sha256=38e150df5f4ca555e25beca4090823ae09657bceded154e3c52f8631c1ed72cf
|
||||||
|
ffi (1.17.4-x86-linux-musl) sha256=fbeec0fc7c795bcf86f623bb18d31ea1820f7bd580e1703a3d3740d527437809
|
||||||
|
ffi (1.17.4-x86_64-darwin) sha256=aa70390523cf3235096cf64962b709b4cfbd5c082a2cb2ae714eb0fe2ccda496
|
||||||
|
ffi (1.17.4-x86_64-linux-gnu) sha256=9d3db14c2eae074b382fa9c083fe95aec6e0a1451da249eab096c34002bc752d
|
||||||
|
ffi (1.17.4-x86_64-linux-musl) sha256=3fdf9888483de005f8ef8d1cf2d3b20d86626af206cbf780f6a6a12439a9c49e
|
||||||
|
fourflusher (2.3.1) sha256=1b3de61c7c791b6a4e64f31e3719eb25203d151746bb519a0292bff1065ccaa9
|
||||||
|
fuzzy_match (2.0.4) sha256=b5de4f95816589c5b5c3ad13770c0af539b75131c158135b3f3bbba75d0cfca5
|
||||||
|
gh_inspector (1.1.3) sha256=04cca7171b87164e053aa43147971d3b7f500fcb58177698886b48a9fc4a1939
|
||||||
|
httpclient (2.9.0) sha256=4b645958e494b2f86c2f8a2f304c959baa273a310e77a2931ddb986d83e498c8
|
||||||
|
i18n (1.14.8) sha256=285778639134865c5e0f6269e0b818256017e8cde89993fdfcbfb64d088824a5
|
||||||
|
json (2.19.5) sha256=218a18553e4801d579ca7e0f5bc72bafd776d7397238a1fb4e74db5b0a812c59
|
||||||
|
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
|
||||||
|
minitest (5.27.0) sha256=2d3b17f8a36fe7801c1adcffdbc38233b938eb0b4966e97a6739055a45fa77d5
|
||||||
|
molinillo (0.8.0) sha256=efbff2716324e2a30bccd3eba1ff3a735f4d5d53ffddbc6a2f32c0ca9433045d
|
||||||
|
mutex_m (0.3.0) sha256=cfcb04ac16b69c4813777022fdceda24e9f798e48092a2b817eb4c0a782b0751
|
||||||
|
nanaimo (0.4.0) sha256=faf069551bab17f15169c1f74a1c73c220657e71b6e900919897a10d991d0723
|
||||||
|
nap (1.1.0) sha256=949691660f9d041d75be611bb2a8d2fd559c467537deac241f4097d9b5eea576
|
||||||
|
netrc (0.11.0) sha256=de1ce33da8c99ab1d97871726cba75151113f117146becbe45aa85cb3dabee3f
|
||||||
|
public_suffix (4.0.7) sha256=8be161e2421f8d45b0098c042c06486789731ea93dc3a896d30554ee38b573b8
|
||||||
|
rexml (3.4.4) sha256=19e0a2c3425dfbf2d4fc1189747bdb2f849b6c5e74180401b15734bc97b5d142
|
||||||
|
ruby-macho (2.5.1) sha256=9075e52e0f9270b552a90b24fcc6219ad149b0d15eae1bc364ecd0ac8984f5c9
|
||||||
|
securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1
|
||||||
|
typhoeus (1.6.0) sha256=bacc41c23e379547e29801dc235cd1699b70b955a1ba3d32b2b877aa844c331d
|
||||||
|
tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b
|
||||||
|
xcodeproj (1.27.0)
|
||||||
|
|
||||||
|
BUNDLED WITH
|
||||||
|
4.0.7
|
||||||
14
ios/Podfile
14
ios/Podfile
@@ -1,5 +1,4 @@
|
|||||||
# Uncomment this line to define a global platform for your project
|
platform :ios, '14.0'
|
||||||
# platform :ios, '13.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'
|
||||||
@@ -36,6 +35,17 @@ target 'Runner' do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Share Extension target has no pod dependencies — the
|
||||||
|
# `RSIShareViewController` base class is vendored directly into the
|
||||||
|
# extension's sources (ios/Share/RSIShareViewController.swift). This
|
||||||
|
# avoids dragging in Flutter.framework and `addApplicationDelegate`
|
||||||
|
# from the receive_sharing_intent plugin, which are banned in app
|
||||||
|
# extensions. `use_frameworks!` is declared so CocoaPods doesn't flag
|
||||||
|
# the host/embedded mismatch with Runner.
|
||||||
|
target 'Share' do
|
||||||
|
use_frameworks!
|
||||||
|
end
|
||||||
|
|
||||||
post_install do |installer|
|
post_install do |installer|
|
||||||
installer.pods_project.targets.each do |target|
|
installer.pods_project.targets.each do |target|
|
||||||
flutter_additional_ios_build_settings(target)
|
flutter_additional_ios_build_settings(target)
|
||||||
|
|||||||
@@ -1,4 +1,40 @@
|
|||||||
PODS:
|
PODS:
|
||||||
|
- device_info_plus (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- DKImagePickerController/Core (4.3.9):
|
||||||
|
- DKImagePickerController/ImageDataManager
|
||||||
|
- DKImagePickerController/Resource
|
||||||
|
- DKImagePickerController/ImageDataManager (4.3.9)
|
||||||
|
- DKImagePickerController/PhotoGallery (4.3.9):
|
||||||
|
- DKImagePickerController/Core
|
||||||
|
- DKPhotoGallery
|
||||||
|
- DKImagePickerController/Resource (4.3.9)
|
||||||
|
- DKPhotoGallery (0.0.19):
|
||||||
|
- DKPhotoGallery/Core (= 0.0.19)
|
||||||
|
- DKPhotoGallery/Model (= 0.0.19)
|
||||||
|
- DKPhotoGallery/Preview (= 0.0.19)
|
||||||
|
- DKPhotoGallery/Resource (= 0.0.19)
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
|
- DKPhotoGallery/Core (0.0.19):
|
||||||
|
- DKPhotoGallery/Model
|
||||||
|
- DKPhotoGallery/Preview
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
|
- DKPhotoGallery/Model (0.0.19):
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
|
- DKPhotoGallery/Preview (0.0.19):
|
||||||
|
- DKPhotoGallery/Model
|
||||||
|
- DKPhotoGallery/Resource
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
|
- DKPhotoGallery/Resource (0.0.19):
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
|
- file_picker (0.0.1):
|
||||||
|
- DKImagePickerController/PhotoGallery
|
||||||
|
- Flutter
|
||||||
- Flutter (1.0.0)
|
- Flutter (1.0.0)
|
||||||
- flutter_local_notifications (0.0.1):
|
- flutter_local_notifications (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
@@ -11,9 +47,15 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- package_info_plus (0.4.5):
|
- package_info_plus (0.4.5):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- receive_sharing_intent (1.8.1):
|
||||||
|
- Flutter
|
||||||
|
- SDWebImage (5.21.7):
|
||||||
|
- SDWebImage/Core (= 5.21.7)
|
||||||
|
- SDWebImage/Core (5.21.7)
|
||||||
- sqflite_darwin (0.0.4):
|
- sqflite_darwin (0.0.4):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
|
- SwiftyGif (5.4.5)
|
||||||
- url_launcher_ios (0.0.1):
|
- url_launcher_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- wakelock_plus (0.0.1):
|
- wakelock_plus (0.0.1):
|
||||||
@@ -22,18 +64,32 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
|
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||||
|
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||||
- Flutter (from `Flutter`)
|
- Flutter (from `Flutter`)
|
||||||
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
||||||
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
|
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
|
||||||
- flutter_secure_storage_darwin (from `.symlinks/plugins/flutter_secure_storage_darwin/darwin`)
|
- flutter_secure_storage_darwin (from `.symlinks/plugins/flutter_secure_storage_darwin/darwin`)
|
||||||
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
||||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||||
|
- receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`)
|
||||||
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
|
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
|
||||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||||
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
||||||
- workmanager_apple (from `.symlinks/plugins/workmanager_apple/ios`)
|
- workmanager_apple (from `.symlinks/plugins/workmanager_apple/ios`)
|
||||||
|
|
||||||
|
SPEC REPOS:
|
||||||
|
trunk:
|
||||||
|
- DKImagePickerController
|
||||||
|
- DKPhotoGallery
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
|
device_info_plus:
|
||||||
|
:path: ".symlinks/plugins/device_info_plus/ios"
|
||||||
|
file_picker:
|
||||||
|
:path: ".symlinks/plugins/file_picker/ios"
|
||||||
Flutter:
|
Flutter:
|
||||||
:path: Flutter
|
:path: Flutter
|
||||||
flutter_local_notifications:
|
flutter_local_notifications:
|
||||||
@@ -46,6 +102,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/image_picker_ios/ios"
|
:path: ".symlinks/plugins/image_picker_ios/ios"
|
||||||
package_info_plus:
|
package_info_plus:
|
||||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||||
|
receive_sharing_intent:
|
||||||
|
:path: ".symlinks/plugins/receive_sharing_intent/ios"
|
||||||
sqflite_darwin:
|
sqflite_darwin:
|
||||||
:path: ".symlinks/plugins/sqflite_darwin/darwin"
|
:path: ".symlinks/plugins/sqflite_darwin/darwin"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
@@ -56,17 +114,24 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/workmanager_apple/ios"
|
:path: ".symlinks/plugins/workmanager_apple/ios"
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
|
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
|
||||||
|
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
|
||||||
|
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
|
||||||
|
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
|
||||||
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
|
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
|
||||||
flutter_local_notifications: 395056b3175ba4f08480a7c5de30cd36d69827e4
|
flutter_local_notifications: 395056b3175ba4f08480a7c5de30cd36d69827e4
|
||||||
flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
|
flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
|
||||||
flutter_secure_storage_darwin: acdb3f316ed05a3e68f856e0353b133eec373a23
|
flutter_secure_storage_darwin: acdb3f316ed05a3e68f856e0353b133eec373a23
|
||||||
image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326
|
image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326
|
||||||
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
||||||
|
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
|
||||||
|
SDWebImage: e9fc87c1aab89a8ab1bbd74eba378c6f53be8abf
|
||||||
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
||||||
|
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||||
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
|
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
|
||||||
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
|
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
|
||||||
workmanager_apple: 904529ae31e97fc5be632cf628507652294a0778
|
workmanager_apple: 904529ae31e97fc5be632cf628507652294a0778
|
||||||
|
|
||||||
PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e
|
PODFILE CHECKSUM: e8d97e41f073e724afe14e2390c9692116d292ff
|
||||||
|
|
||||||
COCOAPODS: 1.16.2
|
COCOAPODS: 1.16.2
|
||||||
|
|||||||
2
ios/Profile.xcconfig
Normal file
2
ios/Profile.xcconfig
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"
|
||||||
|
#include "Generated.xcconfig"
|
||||||
@@ -11,8 +11,11 @@
|
|||||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||||
4B2FECE151D6658169DC6E88 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E836629E52B02A5B6D0F862 /* Pods_RunnerTests.framework */; };
|
4B2FECE151D6658169DC6E88 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E836629E52B02A5B6D0F862 /* Pods_RunnerTests.framework */; };
|
||||||
|
745F12F32FB5CF07007C0ADF /* Share.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 745F12E92FB5CF07007C0ADF /* Share.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
|
745F13182FB5D473007C0ADF /* Profile.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 745F13172FB5D473007C0ADF /* Profile.xcconfig */; };
|
||||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||||
7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; };
|
7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; };
|
||||||
|
971DDFFA6B83AAC1FD474A95 /* Pods_Share.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1B495CAE63B8B48AA6114881 /* Pods_Share.framework */; };
|
||||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||||
@@ -27,9 +30,27 @@
|
|||||||
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
|
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
|
||||||
remoteInfo = Runner;
|
remoteInfo = Runner;
|
||||||
};
|
};
|
||||||
|
745F12F12FB5CF07007C0ADF /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 745F12E82FB5CF07007C0ADF;
|
||||||
|
remoteInfo = Share;
|
||||||
|
};
|
||||||
/* End PBXContainerItemProxy section */
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
745F12F42FB5CF07007C0ADF /* Embed Foundation Extensions */ = {
|
||||||
|
isa = PBXCopyFilesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
dstPath = "";
|
||||||
|
dstSubfolderSpec = 13;
|
||||||
|
files = (
|
||||||
|
745F12F32FB5CF07007C0ADF /* Share.appex in Embed Foundation Extensions */,
|
||||||
|
);
|
||||||
|
name = "Embed Foundation Extensions";
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
||||||
isa = PBXCopyFilesBuildPhase;
|
isa = PBXCopyFilesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -46,12 +67,17 @@
|
|||||||
0D02B01150F8705A7BE3C6D1 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
0D02B01150F8705A7BE3C6D1 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||||
|
1B495CAE63B8B48AA6114881 /* Pods_Share.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Share.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
1E836629E52B02A5B6D0F862 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
1E836629E52B02A5B6D0F862 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
31D13B974C1302A5F0CE86D2 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
31D13B974C1302A5F0CE86D2 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
33DF0655613AFDEC743B1898 /* Pods-Share.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Share.profile.xcconfig"; path = "Target Support Files/Pods-Share/Pods-Share.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||||
|
3D05507B181A60A566EB9904 /* Pods-Share.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Share.debug.xcconfig"; path = "Target Support Files/Pods-Share/Pods-Share.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
736C2329657A6FBB9CE1D305 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
736C2329657A6FBB9CE1D305 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
745F12E92FB5CF07007C0ADF /* Share.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = Share.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
745F13172FB5D473007C0ADF /* Profile.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Profile.xcconfig; sourceTree = "<group>"; };
|
||||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||||
@@ -65,10 +91,36 @@
|
|||||||
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>"; };
|
||||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
9885F82953FBB27851D4D171 /* Pods-Share.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Share.release.xcconfig"; path = "Target Support Files/Pods-Share/Pods-Share.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
C28EA37C4C36CE14FE19E720 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
C28EA37C4C36CE14FE19E720 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
ECEC55E4DC05821BB0BEA50F /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
ECEC55E4DC05821BB0BEA50F /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||||
|
745F13312FB5D55F007C0ADF /* Exceptions for "Share" folder in "Share" target */ = {
|
||||||
|
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||||
|
membershipExceptions = (
|
||||||
|
Info.plist,
|
||||||
|
);
|
||||||
|
target = 745F12E82FB5CF07007C0ADF /* Share */;
|
||||||
|
};
|
||||||
|
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||||
|
|
||||||
|
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||||
|
745F12EA2FB5CF07007C0ADF /* Share */ = {
|
||||||
|
isa = PBXFileSystemSynchronizedRootGroup;
|
||||||
|
exceptions = (
|
||||||
|
745F13312FB5D55F007C0ADF /* Exceptions for "Share" folder in "Share" target */,
|
||||||
|
);
|
||||||
|
explicitFileTypes = {
|
||||||
|
};
|
||||||
|
explicitFolders = (
|
||||||
|
);
|
||||||
|
path = Share;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXFileSystemSynchronizedRootGroup section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
55917F8B3405971C4327A3FF /* Frameworks */ = {
|
55917F8B3405971C4327A3FF /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
@@ -78,6 +130,14 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
745F12E62FB5CF07007C0ADF /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
971DDFFA6B83AAC1FD474A95 /* Pods_Share.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -102,6 +162,7 @@
|
|||||||
children = (
|
children = (
|
||||||
31D13B974C1302A5F0CE86D2 /* Pods_Runner.framework */,
|
31D13B974C1302A5F0CE86D2 /* Pods_Runner.framework */,
|
||||||
1E836629E52B02A5B6D0F862 /* Pods_RunnerTests.framework */,
|
1E836629E52B02A5B6D0F862 /* Pods_RunnerTests.framework */,
|
||||||
|
1B495CAE63B8B48AA6114881 /* Pods_Share.framework */,
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -122,10 +183,12 @@
|
|||||||
children = (
|
children = (
|
||||||
9740EEB11CF90186004384FC /* Flutter */,
|
9740EEB11CF90186004384FC /* Flutter */,
|
||||||
97C146F01CF9000F007C117D /* Runner */,
|
97C146F01CF9000F007C117D /* Runner */,
|
||||||
|
745F12EA2FB5CF07007C0ADF /* Share */,
|
||||||
97C146EF1CF9000F007C117D /* Products */,
|
97C146EF1CF9000F007C117D /* Products */,
|
||||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||||
ECEC5B714C9B60C200CF4964 /* Pods */,
|
ECEC5B714C9B60C200CF4964 /* Pods */,
|
||||||
43389EC5ADFFCB84CB05BC4D /* Frameworks */,
|
43389EC5ADFFCB84CB05BC4D /* Frameworks */,
|
||||||
|
745F13172FB5D473007C0ADF /* Profile.xcconfig */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@@ -134,6 +197,7 @@
|
|||||||
children = (
|
children = (
|
||||||
97C146EE1CF9000F007C117D /* Runner.app */,
|
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
|
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
|
||||||
|
745F12E92FB5CF07007C0ADF /* Share.appex */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -163,8 +227,10 @@
|
|||||||
0D02B01150F8705A7BE3C6D1 /* Pods-RunnerTests.debug.xcconfig */,
|
0D02B01150F8705A7BE3C6D1 /* Pods-RunnerTests.debug.xcconfig */,
|
||||||
91DAEB15490ECD076B82EE80 /* Pods-RunnerTests.release.xcconfig */,
|
91DAEB15490ECD076B82EE80 /* Pods-RunnerTests.release.xcconfig */,
|
||||||
736C2329657A6FBB9CE1D305 /* Pods-RunnerTests.profile.xcconfig */,
|
736C2329657A6FBB9CE1D305 /* Pods-RunnerTests.profile.xcconfig */,
|
||||||
|
3D05507B181A60A566EB9904 /* Pods-Share.debug.xcconfig */,
|
||||||
|
9885F82953FBB27851D4D171 /* Pods-Share.release.xcconfig */,
|
||||||
|
33DF0655613AFDEC743B1898 /* Pods-Share.profile.xcconfig */,
|
||||||
);
|
);
|
||||||
name = Pods;
|
|
||||||
path = Pods;
|
path = Pods;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@@ -190,6 +256,27 @@
|
|||||||
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
|
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
|
||||||
productType = "com.apple.product-type.bundle.unit-test";
|
productType = "com.apple.product-type.bundle.unit-test";
|
||||||
};
|
};
|
||||||
|
745F12E82FB5CF07007C0ADF /* Share */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 745F12F92FB5CF07007C0ADF /* Build configuration list for PBXNativeTarget "Share" */;
|
||||||
|
buildPhases = (
|
||||||
|
1DFA5925966D69304295FDAF /* [CP] Check Pods Manifest.lock */,
|
||||||
|
745F12E52FB5CF07007C0ADF /* Sources */,
|
||||||
|
745F12E62FB5CF07007C0ADF /* Frameworks */,
|
||||||
|
745F12E72FB5CF07007C0ADF /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
fileSystemSynchronizedGroups = (
|
||||||
|
745F12EA2FB5CF07007C0ADF /* Share */,
|
||||||
|
);
|
||||||
|
name = Share;
|
||||||
|
productName = Share;
|
||||||
|
productReference = 745F12E92FB5CF07007C0ADF /* Share.appex */;
|
||||||
|
productType = "com.apple.product-type.app-extension";
|
||||||
|
};
|
||||||
97C146ED1CF9000F007C117D /* Runner */ = {
|
97C146ED1CF9000F007C117D /* Runner */ = {
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||||
@@ -200,12 +287,14 @@
|
|||||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||||
97C146EC1CF9000F007C117D /* Resources */,
|
97C146EC1CF9000F007C117D /* Resources */,
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
|
745F12F42FB5CF07007C0ADF /* Embed Foundation Extensions */,
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
60CC7BE4F08CFECA259D64E9 /* [CP] Embed Pods Frameworks */,
|
60CC7BE4F08CFECA259D64E9 /* [CP] Embed Pods Frameworks */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
|
745F12F22FB5CF07007C0ADF /* PBXTargetDependency */,
|
||||||
);
|
);
|
||||||
name = Runner;
|
name = Runner;
|
||||||
productName = Runner;
|
productName = Runner;
|
||||||
@@ -219,6 +308,7 @@
|
|||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
BuildIndependentTargetsInParallel = YES;
|
BuildIndependentTargetsInParallel = YES;
|
||||||
|
LastSwiftUpdateCheck = 2630;
|
||||||
LastUpgradeCheck = 1510;
|
LastUpgradeCheck = 1510;
|
||||||
ORGANIZATIONNAME = "";
|
ORGANIZATIONNAME = "";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
@@ -226,6 +316,9 @@
|
|||||||
CreatedOnToolsVersion = 14.0;
|
CreatedOnToolsVersion = 14.0;
|
||||||
TestTargetID = 97C146ED1CF9000F007C117D;
|
TestTargetID = 97C146ED1CF9000F007C117D;
|
||||||
};
|
};
|
||||||
|
745F12E82FB5CF07007C0ADF = {
|
||||||
|
CreatedOnToolsVersion = 26.3;
|
||||||
|
};
|
||||||
97C146ED1CF9000F007C117D = {
|
97C146ED1CF9000F007C117D = {
|
||||||
CreatedOnToolsVersion = 7.3.1;
|
CreatedOnToolsVersion = 7.3.1;
|
||||||
LastSwiftMigration = 1100;
|
LastSwiftMigration = 1100;
|
||||||
@@ -247,6 +340,7 @@
|
|||||||
targets = (
|
targets = (
|
||||||
97C146ED1CF9000F007C117D /* Runner */,
|
97C146ED1CF9000F007C117D /* Runner */,
|
||||||
331C8080294A63A400263BE5 /* RunnerTests */,
|
331C8080294A63A400263BE5 /* RunnerTests */,
|
||||||
|
745F12E82FB5CF07007C0ADF /* Share */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
@@ -259,6 +353,14 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
745F12E72FB5CF07007C0ADF /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
745F13182FB5D473007C0ADF /* Profile.xcconfig in Resources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
97C146EC1CF9000F007C117D /* Resources */ = {
|
97C146EC1CF9000F007C117D /* Resources */ = {
|
||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -273,6 +375,28 @@
|
|||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXShellScriptBuildPhase section */
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
|
1DFA5925966D69304295FDAF /* [CP] Check Pods Manifest.lock */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||||
|
"${PODS_ROOT}/Manifest.lock",
|
||||||
|
);
|
||||||
|
name = "[CP] Check Pods Manifest.lock";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
"$(DERIVED_FILE_DIR)/Pods-Share-checkManifestLockResult.txt",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
alwaysOutOfDate = 1;
|
alwaysOutOfDate = 1;
|
||||||
@@ -376,6 +500,13 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
745F12E52FB5CF07007C0ADF /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
97C146EA1CF9000F007C117D /* Sources */ = {
|
97C146EA1CF9000F007C117D /* Sources */ = {
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -394,6 +525,11 @@
|
|||||||
target = 97C146ED1CF9000F007C117D /* Runner */;
|
target = 97C146ED1CF9000F007C117D /* Runner */;
|
||||||
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
|
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
|
||||||
};
|
};
|
||||||
|
745F12F22FB5CF07007C0ADF /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 745F12E82FB5CF07007C0ADF /* Share */;
|
||||||
|
targetProxy = 745F12F12FB5CF07007C0ADF /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
/* End PBXTargetDependency section */
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
/* Begin PBXVariantGroup section */
|
/* Begin PBXVariantGroup section */
|
||||||
@@ -470,10 +606,11 @@
|
|||||||
};
|
};
|
||||||
249021D4217E4FDB00AE95B9 /* Profile */ = {
|
249021D4217E4FDB00AE95B9 /* Profile */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
baseConfigurationReference = 745F13172FB5D473007C0ADF /* Profile.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
DEVELOPMENT_TEAM = Y893L6NQP2;
|
DEVELOPMENT_TEAM = Y893L6NQP2;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
@@ -543,6 +680,134 @@
|
|||||||
};
|
};
|
||||||
name = Profile;
|
name = Profile;
|
||||||
};
|
};
|
||||||
|
745F12F52FB5CF07007C0ADF /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 3D05507B181A60A566EB9904 /* Pods-Share.debug.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Share/ShareRelease.entitlements;
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = Y893L6NQP2;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = Share/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = Share;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@executable_path/../../Frameworks",
|
||||||
|
);
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = dev.casraf.pantry.Share;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
745F12F62FB5CF07007C0ADF /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 9885F82953FBB27851D4D171 /* Pods-Share.release.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Share/ShareRelease.entitlements;
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Distribution";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = Y893L6NQP2;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = Share/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = Share;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@executable_path/../../Frameworks",
|
||||||
|
);
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = dev.casraf.pantry.Share;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "Pantry Share Distribution";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
745F12F72FB5CF07007C0ADF /* Profile */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 33DF0655613AFDEC743B1898 /* Pods-Share.profile.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Share/ShareRelease.entitlements;
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = Y893L6NQP2;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = Share/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = Share;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@executable_path/../../Frameworks",
|
||||||
|
);
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = dev.casraf.pantry.Share;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Profile;
|
||||||
|
};
|
||||||
97C147031CF9000F007C117D /* Debug */ = {
|
97C147031CF9000F007C117D /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
@@ -660,6 +925,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
DEVELOPMENT_TEAM = Y893L6NQP2;
|
DEVELOPMENT_TEAM = Y893L6NQP2;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
@@ -686,6 +952,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Distribution";
|
CODE_SIGN_IDENTITY = "Apple Distribution";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
@@ -721,6 +988,16 @@
|
|||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
|
745F12F92FB5CF07007C0ADF /* Build configuration list for PBXNativeTarget "Share" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
745F12F52FB5CF07007C0ADF /* Debug */,
|
||||||
|
745F12F62FB5CF07007C0ADF /* Release */,
|
||||||
|
745F12F72FB5CF07007C0ADF /* Profile */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
|
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
|
|||||||
@@ -84,5 +84,24 @@
|
|||||||
</array>
|
</array>
|
||||||
<key>ITSAppUsesNonExemptEncryption</key>
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
<false/>
|
<false/>
|
||||||
|
<key>NSCameraUsageDescription</key>
|
||||||
|
<string>Pantry needs access to the camera so you can take photos and upload them to your photo board.</string>
|
||||||
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
|
<string>Pantry needs access to your photo library so you can pick existing photos and upload them to your photo board.</string>
|
||||||
|
<key>AppGroupId</key>
|
||||||
|
<string>group.dev.casraf.pantry</string>
|
||||||
|
<key>CFBundleURLTypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Editor</string>
|
||||||
|
<key>CFBundleURLName</key>
|
||||||
|
<string>dev.casraf.pantry.share</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>ShareMedia-dev.casraf.pantry</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
10
ios/Runner/Runner.entitlements
Normal file
10
ios/Runner/Runner.entitlements
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.security.application-groups</key>
|
||||||
|
<array>
|
||||||
|
<string>group.dev.casraf.pantry</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
24
ios/Share/Base.lproj/MainInterface.storyboard
Normal file
24
ios/Share/Base.lproj/MainInterface.storyboard
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="j1y-V4-xli">
|
||||||
|
<dependencies>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
|
||||||
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--Share View Controller-->
|
||||||
|
<scene sceneID="ceB-am-kn3">
|
||||||
|
<objects>
|
||||||
|
<viewController id="j1y-V4-xli" customClass="ShareViewController" customModuleProvider="target" sceneMemberID="viewController">
|
||||||
|
<view key="view" opaque="NO" contentMode="scaleToFill" id="wbc-yd-nQP">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<viewLayoutGuide key="safeArea" id="1Xd-am-t49"/>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="CEy-Cv-SGf" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
</document>
|
||||||
29
ios/Share/Info.plist
Normal file
29
ios/Share/Info.plist
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>NSExtension</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSExtensionAttributes</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSExtensionActivationRule</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
|
||||||
|
<integer>20</integer>
|
||||||
|
<key>NSExtensionActivationSupportsMovieWithMaxCount</key>
|
||||||
|
<integer>5</integer>
|
||||||
|
<key>NSExtensionActivationSupportsText</key>
|
||||||
|
<true/>
|
||||||
|
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
|
||||||
|
<integer>5</integer>
|
||||||
|
<key>NSExtensionActivationSupportsFileWithMaxCount</key>
|
||||||
|
<integer>10</integer>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>NSExtensionMainStoryboard</key>
|
||||||
|
<string>MainInterface</string>
|
||||||
|
<key>NSExtensionPointIdentifier</key>
|
||||||
|
<string>com.apple.share-services</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
346
ios/Share/RSIShareViewController.swift
Normal file
346
ios/Share/RSIShareViewController.swift
Normal file
@@ -0,0 +1,346 @@
|
|||||||
|
// Vendored from receive_sharing_intent 1.8.1 so the Share Extension does
|
||||||
|
// not need to import the pod (which transitively pulls in Flutter +
|
||||||
|
// UIApplication APIs that are banned in app extensions).
|
||||||
|
//
|
||||||
|
// Keep the constants and `SharedMediaFile` / `SharedMediaType` shapes in
|
||||||
|
// sync with `SwiftReceiveSharingIntentPlugin.swift` in the upstream pod,
|
||||||
|
// otherwise the host app side will not decode payloads correctly.
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import Social
|
||||||
|
import MobileCoreServices
|
||||||
|
import Photos
|
||||||
|
import UniformTypeIdentifiers
|
||||||
|
|
||||||
|
let kSchemePrefix = "ShareMedia"
|
||||||
|
let kUserDefaultsKey = "ShareKey"
|
||||||
|
let kUserDefaultsMessageKey = "ShareMessageKey"
|
||||||
|
let kAppGroupIdKey = "AppGroupId"
|
||||||
|
|
||||||
|
class SharedMediaFile: Codable {
|
||||||
|
var path: String
|
||||||
|
var mimeType: String?
|
||||||
|
var thumbnail: String?
|
||||||
|
var duration: Double?
|
||||||
|
var message: String?
|
||||||
|
var type: SharedMediaType
|
||||||
|
|
||||||
|
init(
|
||||||
|
path: String,
|
||||||
|
mimeType: String? = nil,
|
||||||
|
thumbnail: String? = nil,
|
||||||
|
duration: Double? = nil,
|
||||||
|
message: String? = nil,
|
||||||
|
type: SharedMediaType
|
||||||
|
) {
|
||||||
|
self.path = path
|
||||||
|
self.mimeType = mimeType
|
||||||
|
self.thumbnail = thumbnail
|
||||||
|
self.duration = duration
|
||||||
|
self.message = message
|
||||||
|
self.type = type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SharedMediaType: String, Codable, CaseIterable {
|
||||||
|
case image
|
||||||
|
case video
|
||||||
|
case text
|
||||||
|
case file
|
||||||
|
case url
|
||||||
|
|
||||||
|
var toUTTypeIdentifier: String {
|
||||||
|
if #available(iOS 14.0, *) {
|
||||||
|
switch self {
|
||||||
|
case .image: return UTType.image.identifier
|
||||||
|
case .video: return UTType.movie.identifier
|
||||||
|
case .text: return UTType.text.identifier
|
||||||
|
case .file: return UTType.fileURL.identifier
|
||||||
|
case .url: return UTType.url.identifier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch self {
|
||||||
|
case .image: return "public.image"
|
||||||
|
case .video: return "public.movie"
|
||||||
|
case .text: return "public.text"
|
||||||
|
case .file: return "public.file-url"
|
||||||
|
case .url: return "public.url"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(swift, introduced: 5.0)
|
||||||
|
open class RSIShareViewController: SLComposeServiceViewController {
|
||||||
|
var hostAppBundleIdentifier = ""
|
||||||
|
var appGroupId = ""
|
||||||
|
var sharedMedia: [SharedMediaFile] = []
|
||||||
|
|
||||||
|
open func shouldAutoRedirect() -> Bool { true }
|
||||||
|
|
||||||
|
open override func isContentValid() -> Bool { true }
|
||||||
|
|
||||||
|
open override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
loadIds()
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func didSelectPost() {
|
||||||
|
saveAndRedirect(message: contentText)
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func viewDidAppear(_ animated: Bool) {
|
||||||
|
super.viewDidAppear(animated)
|
||||||
|
|
||||||
|
if let content = extensionContext!.inputItems[0] as? NSExtensionItem,
|
||||||
|
let contents = content.attachments {
|
||||||
|
for (index, attachment) in contents.enumerated() {
|
||||||
|
for type in SharedMediaType.allCases {
|
||||||
|
if attachment.hasItemConformingToTypeIdentifier(type.toUTTypeIdentifier) {
|
||||||
|
attachment.loadItem(forTypeIdentifier: type.toUTTypeIdentifier) { [weak self] data, error in
|
||||||
|
guard let this = self, error == nil else {
|
||||||
|
self?.dismissWithError()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch type {
|
||||||
|
case .text:
|
||||||
|
if let text = data as? String {
|
||||||
|
this.handleMedia(forLiteral: text, type: type, index: index, content: content)
|
||||||
|
}
|
||||||
|
case .url:
|
||||||
|
if let url = data as? URL {
|
||||||
|
this.handleMedia(forLiteral: url.absoluteString, type: type, index: index, content: content)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if let url = data as? URL {
|
||||||
|
this.handleMedia(forFile: url, type: type, index: index, content: content)
|
||||||
|
} else if let image = data as? UIImage {
|
||||||
|
this.handleMedia(forUIImage: image, type: type, index: index, content: content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func configurationItems() -> [Any]! { [] }
|
||||||
|
|
||||||
|
private func loadIds() {
|
||||||
|
let shareExtensionAppBundleIdentifier = Bundle.main.bundleIdentifier!
|
||||||
|
let lastIndexOfPoint = shareExtensionAppBundleIdentifier.lastIndex(of: ".")
|
||||||
|
hostAppBundleIdentifier = String(shareExtensionAppBundleIdentifier[..<lastIndexOfPoint!])
|
||||||
|
let defaultAppGroupId = "group.\(hostAppBundleIdentifier)"
|
||||||
|
let customAppGroupId = Bundle.main.object(forInfoDictionaryKey: kAppGroupIdKey) as? String
|
||||||
|
appGroupId = customAppGroupId ?? defaultAppGroupId
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleMedia(forLiteral item: String, type: SharedMediaType, index: Int, content: NSExtensionItem) {
|
||||||
|
sharedMedia.append(SharedMediaFile(
|
||||||
|
path: item,
|
||||||
|
mimeType: type == .text ? "text/plain" : nil,
|
||||||
|
type: type
|
||||||
|
))
|
||||||
|
if index == (content.attachments?.count ?? 0) - 1, shouldAutoRedirect() {
|
||||||
|
saveAndRedirect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleMedia(forUIImage image: UIImage, type: SharedMediaType, index: Int, content: NSExtensionItem) {
|
||||||
|
guard let containerURL = FileManager.default
|
||||||
|
.containerURL(forSecurityApplicationGroupIdentifier: appGroupId) else {
|
||||||
|
if index == (content.attachments?.count ?? 0) - 1, shouldAutoRedirect() {
|
||||||
|
saveAndRedirect()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let tempPath = containerURL.appendingPathComponent("TempImage.png")
|
||||||
|
if writeTempFile(image, to: tempPath) {
|
||||||
|
let newPathDecoded = tempPath.absoluteString.removingPercentEncoding!
|
||||||
|
sharedMedia.append(SharedMediaFile(
|
||||||
|
path: newPathDecoded,
|
||||||
|
mimeType: type == .image ? "image/png" : nil,
|
||||||
|
type: type
|
||||||
|
))
|
||||||
|
}
|
||||||
|
if index == (content.attachments?.count ?? 0) - 1, shouldAutoRedirect() {
|
||||||
|
saveAndRedirect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleMedia(forFile url: URL, type: SharedMediaType, index: Int, content: NSExtensionItem) {
|
||||||
|
let fileName = getFileName(from: url, type: type)
|
||||||
|
guard let containerURL = FileManager.default
|
||||||
|
.containerURL(forSecurityApplicationGroupIdentifier: appGroupId) else {
|
||||||
|
if index == (content.attachments?.count ?? 0) - 1, shouldAutoRedirect() {
|
||||||
|
saveAndRedirect()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let newPath = containerURL.appendingPathComponent(fileName)
|
||||||
|
|
||||||
|
if copyFile(at: url, to: newPath) {
|
||||||
|
let newPathDecoded = newPath.absoluteString.removingPercentEncoding!
|
||||||
|
if type == .video, let videoInfo = getVideoInfo(from: url) {
|
||||||
|
let thumbnailPathDecoded = videoInfo.thumbnail?.removingPercentEncoding
|
||||||
|
sharedMedia.append(SharedMediaFile(
|
||||||
|
path: newPathDecoded,
|
||||||
|
mimeType: url.mimeType(),
|
||||||
|
thumbnail: thumbnailPathDecoded,
|
||||||
|
duration: videoInfo.duration,
|
||||||
|
type: type
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
sharedMedia.append(SharedMediaFile(
|
||||||
|
path: newPathDecoded,
|
||||||
|
mimeType: url.mimeType(),
|
||||||
|
type: type
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if index == (content.attachments?.count ?? 0) - 1, shouldAutoRedirect() {
|
||||||
|
saveAndRedirect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func saveAndRedirect(message: String? = nil) {
|
||||||
|
let userDefaults = UserDefaults(suiteName: appGroupId)
|
||||||
|
userDefaults?.set(toData(data: sharedMedia), forKey: kUserDefaultsKey)
|
||||||
|
userDefaults?.set(message, forKey: kUserDefaultsMessageKey)
|
||||||
|
userDefaults?.synchronize()
|
||||||
|
redirectToHostApp()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func redirectToHostApp() {
|
||||||
|
loadIds()
|
||||||
|
let url = URL(string: "\(kSchemePrefix)-\(hostAppBundleIdentifier):share")!
|
||||||
|
var responder = self as UIResponder?
|
||||||
|
// iOS 18 removed the legacy `openURL:` selector, so we have to
|
||||||
|
// walk the responder chain and call `UIApplication.open(_:)`
|
||||||
|
// through the dynamic cast — this path is what the upstream
|
||||||
|
// receive_sharing_intent package uses.
|
||||||
|
if #available(iOS 18.0, *) {
|
||||||
|
while responder != nil {
|
||||||
|
if let application = responder as? UIApplication {
|
||||||
|
application.open(url, options: [:], completionHandler: nil)
|
||||||
|
}
|
||||||
|
responder = responder?.next
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let selectorOpenURL = sel_registerName("openURL:")
|
||||||
|
while responder != nil {
|
||||||
|
if responder?.responds(to: selectorOpenURL) == true {
|
||||||
|
_ = responder?.perform(selectorOpenURL, with: url)
|
||||||
|
}
|
||||||
|
responder = responder?.next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func dismissWithError() {
|
||||||
|
let alert = UIAlertController(title: "Error", message: "Error loading data", preferredStyle: .alert)
|
||||||
|
alert.addAction(UIAlertAction(title: "OK", style: .cancel) { _ in
|
||||||
|
self.dismiss(animated: true, completion: nil)
|
||||||
|
})
|
||||||
|
present(alert, animated: true, completion: nil)
|
||||||
|
extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getFileName(from url: URL, type: SharedMediaType) -> String {
|
||||||
|
var name = url.lastPathComponent
|
||||||
|
if name.isEmpty {
|
||||||
|
switch type {
|
||||||
|
case .image: name = UUID().uuidString + ".png"
|
||||||
|
case .video: name = UUID().uuidString + ".mp4"
|
||||||
|
case .text: name = UUID().uuidString + ".txt"
|
||||||
|
default: name = UUID().uuidString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
private func writeTempFile(_ image: UIImage, to dstURL: URL) -> Bool {
|
||||||
|
do {
|
||||||
|
if FileManager.default.fileExists(atPath: dstURL.path) {
|
||||||
|
try FileManager.default.removeItem(at: dstURL)
|
||||||
|
}
|
||||||
|
try image.pngData()?.write(to: dstURL)
|
||||||
|
return true
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func copyFile(at srcURL: URL, to dstURL: URL) -> Bool {
|
||||||
|
do {
|
||||||
|
if FileManager.default.fileExists(atPath: dstURL.path) {
|
||||||
|
try FileManager.default.removeItem(at: dstURL)
|
||||||
|
}
|
||||||
|
try FileManager.default.copyItem(at: srcURL, to: dstURL)
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getVideoInfo(from url: URL) -> (thumbnail: String?, duration: Double)? {
|
||||||
|
let asset = AVAsset(url: url)
|
||||||
|
let duration = (CMTimeGetSeconds(asset.duration) * 1000).rounded()
|
||||||
|
let thumbnailPath = getThumbnailPath(for: url)
|
||||||
|
|
||||||
|
if FileManager.default.fileExists(atPath: thumbnailPath.path) {
|
||||||
|
return (thumbnail: thumbnailPath.absoluteString, duration: duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
var saved = false
|
||||||
|
let assetImgGenerate = AVAssetImageGenerator(asset: asset)
|
||||||
|
assetImgGenerate.appliesPreferredTrackTransform = true
|
||||||
|
assetImgGenerate.maximumSize = CGSize(width: 360, height: 360)
|
||||||
|
do {
|
||||||
|
let img = try assetImgGenerate.copyCGImage(
|
||||||
|
at: CMTimeMakeWithSeconds(600, preferredTimescale: 1),
|
||||||
|
actualTime: nil
|
||||||
|
)
|
||||||
|
try UIImage(cgImage: img).pngData()?.write(to: thumbnailPath)
|
||||||
|
saved = true
|
||||||
|
} catch {
|
||||||
|
saved = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return saved ? (thumbnail: thumbnailPath.absoluteString, duration: duration) : nil
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getThumbnailPath(for url: URL) -> URL {
|
||||||
|
let fileName = Data(url.lastPathComponent.utf8)
|
||||||
|
.base64EncodedString()
|
||||||
|
.replacingOccurrences(of: "==", with: "")
|
||||||
|
return FileManager.default
|
||||||
|
.containerURL(forSecurityApplicationGroupIdentifier: appGroupId)!
|
||||||
|
.appendingPathComponent("\(fileName).jpg")
|
||||||
|
}
|
||||||
|
|
||||||
|
private func toData(data: [SharedMediaFile]) -> Data {
|
||||||
|
try! JSONEncoder().encode(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension URL {
|
||||||
|
func mimeType() -> String {
|
||||||
|
if #available(iOS 14.0, *) {
|
||||||
|
if let mimeType = UTType(filenameExtension: pathExtension)?.preferredMIMEType {
|
||||||
|
return mimeType
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let uti = UTTypeCreatePreferredIdentifierForTag(
|
||||||
|
kUTTagClassFilenameExtension, pathExtension as NSString, nil
|
||||||
|
)?.takeRetainedValue(),
|
||||||
|
let mimetype = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue() {
|
||||||
|
return mimetype as String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "application/octet-stream"
|
||||||
|
}
|
||||||
|
}
|
||||||
10
ios/Share/ShareRelease.entitlements
Normal file
10
ios/Share/ShareRelease.entitlements
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.security.application-groups</key>
|
||||||
|
<array>
|
||||||
|
<string>group.dev.casraf.pantry</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
10
ios/Share/ShareViewController.swift
Normal file
10
ios/Share/ShareViewController.swift
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import UIKit
|
||||||
|
|
||||||
|
class ShareViewController: RSIShareViewController {
|
||||||
|
// Inherits default behavior from `RSIShareViewController` (vendored in
|
||||||
|
// RSIShareViewController.swift): collect the shared payload (images,
|
||||||
|
// text, URLs), persist it to the App Group's UserDefaults, then open
|
||||||
|
// the host app via the registered URL scheme. Override
|
||||||
|
// `shouldAutoRedirect()` to return `false` if a custom share sheet UI
|
||||||
|
// is needed before posting.
|
||||||
|
}
|
||||||
180
lib/main.dart
180
lib/main.dart
@@ -1,8 +1,11 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:io' show Platform;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'package:wakelock_plus/wakelock_plus.dart';
|
import 'package:wakelock_plus/wakelock_plus.dart';
|
||||||
|
|
||||||
import 'i18n.dart';
|
import 'i18n.dart';
|
||||||
@@ -16,6 +19,7 @@ import 'services/local_notifications_service.dart';
|
|||||||
import 'services/note_service.dart';
|
import 'services/note_service.dart';
|
||||||
import 'services/photo_service.dart';
|
import 'services/photo_service.dart';
|
||||||
import 'services/prefs_service.dart';
|
import 'services/prefs_service.dart';
|
||||||
|
import 'services/share_intent_service.dart';
|
||||||
import 'services/theming_service.dart';
|
import 'services/theming_service.dart';
|
||||||
import 'views/home/home_view.dart';
|
import 'views/home/home_view.dart';
|
||||||
import 'views/login/login_view.dart';
|
import 'views/login/login_view.dart';
|
||||||
@@ -46,6 +50,7 @@ void main() async {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
LocaleService.instance.apply();
|
LocaleService.instance.apply();
|
||||||
|
unawaited(ShareIntentService.instance.init());
|
||||||
runApp(const PantryApp());
|
runApp(const PantryApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,6 +61,39 @@ class PantryApp extends StatefulWidget {
|
|||||||
State<PantryApp> createState() => PantryAppState();
|
State<PantryApp> createState() => PantryAppState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _EscapePopWrapper extends StatelessWidget {
|
||||||
|
final Widget child;
|
||||||
|
const _EscapePopWrapper({required this.child});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Shortcuts(
|
||||||
|
shortcuts: const <ShortcutActivator, Intent>{
|
||||||
|
SingleActivator(LogicalKeyboardKey.escape): _PopRouteIntent(),
|
||||||
|
},
|
||||||
|
child: Actions(
|
||||||
|
actions: <Type, Action<Intent>>{_PopRouteIntent: _PopRouteAction()},
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PopRouteIntent extends Intent {
|
||||||
|
const _PopRouteIntent();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PopRouteAction extends Action<_PopRouteIntent> {
|
||||||
|
@override
|
||||||
|
Object? invoke(covariant _PopRouteIntent intent) {
|
||||||
|
final nav = rootNavigatorKey.currentState;
|
||||||
|
if (nav?.canPop() == true) {
|
||||||
|
nav!.maybePop();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class PantryAppState extends State<PantryApp> {
|
class PantryAppState extends State<PantryApp> {
|
||||||
bool _isLoggedIn = AuthService.instance.isLoggedIn;
|
bool _isLoggedIn = AuthService.instance.isLoggedIn;
|
||||||
|
|
||||||
@@ -113,74 +151,90 @@ class PantryAppState extends State<PantryApp> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final color = ThemingService.instance.effectiveColor;
|
final color = ThemingService.instance.effectiveColor;
|
||||||
final locale = LocaleService.instance.effectiveLocale;
|
final locale = LocaleService.instance.effectiveLocale;
|
||||||
return Directionality(
|
final isMacOS = !kIsWeb && Platform.isMacOS;
|
||||||
textDirection: LocaleService.instance.textDirection,
|
final isDesktopHost =
|
||||||
child: MaterialApp(
|
kIsWeb ||
|
||||||
key: ValueKey(locale),
|
(!kIsWeb &&
|
||||||
// debugShowCheckedModeBanner: false,
|
(Platform.isMacOS || Platform.isWindows || Platform.isLinux));
|
||||||
navigatorKey: rootNavigatorKey,
|
final appBarTheme = isMacOS ? const AppBarTheme(toolbarHeight: 66) : null;
|
||||||
locale: locale,
|
return ChangeNotifierProvider<PrefsService>.value(
|
||||||
supportedLocales: supportedLocales,
|
value: PrefsService.instance,
|
||||||
localizationsDelegates: const [
|
child: Directionality(
|
||||||
GlobalMaterialLocalizations.delegate,
|
textDirection: LocaleService.instance.textDirection,
|
||||||
GlobalWidgetsLocalizations.delegate,
|
child: MaterialApp(
|
||||||
GlobalCupertinoLocalizations.delegate,
|
key: ValueKey(locale),
|
||||||
],
|
debugShowCheckedModeBanner: false,
|
||||||
title: m.common.appTitle,
|
navigatorKey: rootNavigatorKey,
|
||||||
theme: ThemeData(
|
locale: locale,
|
||||||
colorScheme: ColorScheme.fromSeed(
|
supportedLocales: supportedLocales,
|
||||||
seedColor: color,
|
localizationsDelegates: const [
|
||||||
).copyWith(primary: color),
|
GlobalMaterialLocalizations.delegate,
|
||||||
useMaterial3: true,
|
GlobalWidgetsLocalizations.delegate,
|
||||||
popupMenuTheme: PopupMenuThemeData(
|
GlobalCupertinoLocalizations.delegate,
|
||||||
shape: RoundedRectangleBorder(
|
],
|
||||||
borderRadius: BorderRadius.circular(20),
|
title: m.common.appTitle,
|
||||||
|
theme: ThemeData(
|
||||||
|
colorScheme: ColorScheme.fromSeed(
|
||||||
|
seedColor: color,
|
||||||
|
).copyWith(primary: color),
|
||||||
|
useMaterial3: true,
|
||||||
|
appBarTheme: appBarTheme,
|
||||||
|
popupMenuTheme: PopupMenuThemeData(
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
),
|
||||||
|
elevation: 8,
|
||||||
|
position: PopupMenuPosition.under,
|
||||||
),
|
),
|
||||||
elevation: 8,
|
|
||||||
position: PopupMenuPosition.under,
|
|
||||||
),
|
),
|
||||||
),
|
darkTheme: ThemeData(
|
||||||
darkTheme: ThemeData(
|
colorScheme: ColorScheme.fromSeed(
|
||||||
colorScheme: ColorScheme.fromSeed(
|
seedColor: color,
|
||||||
seedColor: color,
|
brightness: Brightness.dark,
|
||||||
brightness: Brightness.dark,
|
).copyWith(primary: color),
|
||||||
).copyWith(primary: color),
|
useMaterial3: true,
|
||||||
useMaterial3: true,
|
appBarTheme: appBarTheme,
|
||||||
popupMenuTheme: PopupMenuThemeData(
|
popupMenuTheme: PopupMenuThemeData(
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
),
|
||||||
|
elevation: 8,
|
||||||
|
position: PopupMenuPosition.under,
|
||||||
),
|
),
|
||||||
elevation: 8,
|
|
||||||
position: PopupMenuPosition.under,
|
|
||||||
),
|
),
|
||||||
|
themeMode: ThemingService.instance.themeMode,
|
||||||
|
builder: (context, child) {
|
||||||
|
if (child == null) return const SizedBox.shrink();
|
||||||
|
if (!isDesktopHost) return child;
|
||||||
|
return _EscapePopWrapper(child: child);
|
||||||
|
},
|
||||||
|
onGenerateInitialRoutes: (initialRoute) => [
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (_) => _isLoggedIn
|
||||||
|
? (PrefsService.instance.notificationsIntroSeen
|
||||||
|
? HomeView(onLogout: _onLogout)
|
||||||
|
: NotificationsIntroView(onDone: _onIntroDone))
|
||||||
|
: LoginView(onLoginSuccess: _onLoginSuccess),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
onGenerateRoute: (settings) {
|
||||||
|
switch (settings.name) {
|
||||||
|
case '/home':
|
||||||
|
return MaterialPageRoute(
|
||||||
|
builder: (_) => HomeView(onLogout: _onLogout),
|
||||||
|
);
|
||||||
|
case '/notifications-intro':
|
||||||
|
return MaterialPageRoute(
|
||||||
|
builder: (_) => NotificationsIntroView(onDone: _onIntroDone),
|
||||||
|
);
|
||||||
|
case '/login':
|
||||||
|
default:
|
||||||
|
return MaterialPageRoute(
|
||||||
|
builder: (_) => LoginView(onLoginSuccess: _onLoginSuccess),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
),
|
),
|
||||||
themeMode: ThemingService.instance.themeMode,
|
|
||||||
onGenerateInitialRoutes: (initialRoute) => [
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (_) => _isLoggedIn
|
|
||||||
? (PrefsService.instance.notificationsIntroSeen
|
|
||||||
? HomeView(onLogout: _onLogout)
|
|
||||||
: NotificationsIntroView(onDone: _onIntroDone))
|
|
||||||
: LoginView(onLoginSuccess: _onLoginSuccess),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
onGenerateRoute: (settings) {
|
|
||||||
switch (settings.name) {
|
|
||||||
case '/home':
|
|
||||||
return MaterialPageRoute(
|
|
||||||
builder: (_) => HomeView(onLogout: _onLogout),
|
|
||||||
);
|
|
||||||
case '/notifications-intro':
|
|
||||||
return MaterialPageRoute(
|
|
||||||
builder: (_) => NotificationsIntroView(onDone: _onIntroDone),
|
|
||||||
);
|
|
||||||
case '/login':
|
|
||||||
default:
|
|
||||||
return MaterialPageRoute(
|
|
||||||
builder: (_) => LoginView(onLoginSuccess: _onLoginSuccess),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ class Messages {
|
|||||||
ChecklistsMessages get checklists => ChecklistsMessages(this);
|
ChecklistsMessages get checklists => ChecklistsMessages(this);
|
||||||
NotesWallMessages get notesWall => NotesWallMessages(this);
|
NotesWallMessages get notesWall => NotesWallMessages(this);
|
||||||
PhotoBoardMessages get photoBoard => PhotoBoardMessages(this);
|
PhotoBoardMessages get photoBoard => PhotoBoardMessages(this);
|
||||||
|
ShareMessages get share => ShareMessages(this);
|
||||||
RecurrenceMessages get recurrence => RecurrenceMessages(this);
|
RecurrenceMessages get recurrence => RecurrenceMessages(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,6 +362,35 @@ class SettingsMessages {
|
|||||||
/// ```
|
/// ```
|
||||||
String get generalSection => """General""";
|
String get generalSection => """General""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Interface"
|
||||||
|
/// ```
|
||||||
|
String get interfaceSection => """Interface""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Tap row to complete items"
|
||||||
|
/// ```
|
||||||
|
String get tapRowToComplete => """Tap row to complete items""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "When off, items are only marked complete by tapping the checkbox."
|
||||||
|
/// ```
|
||||||
|
String get tapRowToCompleteBody =>
|
||||||
|
"""When off, items are only marked complete by tapping the checkbox.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Show spacing between categories in list items"
|
||||||
|
/// ```
|
||||||
|
String get categorySpacing =>
|
||||||
|
"""Show spacing between categories in list items""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Only visible when sorting by category"
|
||||||
|
/// ```
|
||||||
|
String get categorySpacingBody => """Only visible when sorting by category""";
|
||||||
|
CategorySpacingNamesSettingsMessages get categorySpacingNames =>
|
||||||
|
CategorySpacingNamesSettingsMessages(this);
|
||||||
|
|
||||||
/// ```dart
|
/// ```dart
|
||||||
/// "Language"
|
/// "Language"
|
||||||
/// ```
|
/// ```
|
||||||
@@ -427,6 +457,26 @@ class SettingsMessages {
|
|||||||
"""Notification permission was denied. Enable it in system settings.""";
|
"""Notification permission was denied. Enable it in system settings.""";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CategorySpacingNamesSettingsMessages {
|
||||||
|
final SettingsMessages _parent;
|
||||||
|
const CategorySpacingNamesSettingsMessages(this._parent);
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Disabled"
|
||||||
|
/// ```
|
||||||
|
String get disabled => """Disabled""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Space"
|
||||||
|
/// ```
|
||||||
|
String get space => """Space""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Divider"
|
||||||
|
/// ```
|
||||||
|
String get divider => """Divider""";
|
||||||
|
}
|
||||||
|
|
||||||
class LanguageNamesSettingsMessages {
|
class LanguageNamesSettingsMessages {
|
||||||
final SettingsMessages _parent;
|
final SettingsMessages _parent;
|
||||||
const LanguageNamesSettingsMessages(this._parent);
|
const LanguageNamesSettingsMessages(this._parent);
|
||||||
@@ -657,6 +707,92 @@ class ChecklistsMessages {
|
|||||||
/// ```
|
/// ```
|
||||||
String get moveFailed => """Failed to move item.""";
|
String get moveFailed => """Failed to move item.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Item marked as done"
|
||||||
|
/// ```
|
||||||
|
String get itemMarkedDone => """Item marked as done""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Undo"
|
||||||
|
/// ```
|
||||||
|
String get undo => """Undo""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "View trash"
|
||||||
|
/// ```
|
||||||
|
String get viewTrash => """View trash""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Exit trash"
|
||||||
|
/// ```
|
||||||
|
String get exitTrash => """Exit trash""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Trash"
|
||||||
|
/// ```
|
||||||
|
String get trashTitle => """Trash""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Trash is empty."
|
||||||
|
/// ```
|
||||||
|
String get noTrashedItems => """Trash is empty.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Empty trash"
|
||||||
|
/// ```
|
||||||
|
String get emptyTrash => """Empty trash""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Empty the trash?"
|
||||||
|
/// ```
|
||||||
|
String get emptyTrashConfirm => """Empty the trash?""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "All items in the trash will be permanently deleted. This cannot be undone."
|
||||||
|
/// ```
|
||||||
|
String get emptyTrashConfirmBody =>
|
||||||
|
"""All items in the trash will be permanently deleted. This cannot be undone.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Failed to empty trash."
|
||||||
|
/// ```
|
||||||
|
String get emptyTrashFailed => """Failed to empty trash.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Restore"
|
||||||
|
/// ```
|
||||||
|
String get restoreItem => """Restore""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Delete permanently"
|
||||||
|
/// ```
|
||||||
|
String get permanentlyDeleteItem => """Delete permanently""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Permanently delete this item?"
|
||||||
|
/// ```
|
||||||
|
String get permanentlyDeleteConfirm => """Permanently delete this item?""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "This cannot be undone."
|
||||||
|
/// ```
|
||||||
|
String get permanentlyDeleteConfirmBody => """This cannot be undone.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Failed to restore item."
|
||||||
|
/// ```
|
||||||
|
String get restoreFailed => """Failed to restore item.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Failed to delete item."
|
||||||
|
/// ```
|
||||||
|
String get permanentlyDeleteFailed => """Failed to delete item.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Item restored"
|
||||||
|
/// ```
|
||||||
|
String get itemRestored => """Item restored""";
|
||||||
|
|
||||||
/// ```dart
|
/// ```dart
|
||||||
/// "New list"
|
/// "New list"
|
||||||
/// ```
|
/// ```
|
||||||
@@ -1053,9 +1189,30 @@ class PhotoBoardMessages {
|
|||||||
/// "$count"
|
/// "$count"
|
||||||
/// ```
|
/// ```
|
||||||
String photoCount(int count) => """$count""";
|
String photoCount(int count) => """$count""";
|
||||||
|
AddMenuPhotoBoardMessages get addMenu => AddMenuPhotoBoardMessages(this);
|
||||||
SortPhotoBoardMessages get sort => SortPhotoBoardMessages(this);
|
SortPhotoBoardMessages get sort => SortPhotoBoardMessages(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AddMenuPhotoBoardMessages {
|
||||||
|
final PhotoBoardMessages _parent;
|
||||||
|
const AddMenuPhotoBoardMessages(this._parent);
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Upload photos"
|
||||||
|
/// ```
|
||||||
|
String get upload => """Upload photos""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Take photo"
|
||||||
|
/// ```
|
||||||
|
String get camera => """Take photo""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "New folder"
|
||||||
|
/// ```
|
||||||
|
String get newFolder => """New folder""";
|
||||||
|
}
|
||||||
|
|
||||||
class SortPhotoBoardMessages {
|
class SortPhotoBoardMessages {
|
||||||
final PhotoBoardMessages _parent;
|
final PhotoBoardMessages _parent;
|
||||||
const SortPhotoBoardMessages(this._parent);
|
const SortPhotoBoardMessages(this._parent);
|
||||||
@@ -1091,6 +1248,56 @@ class SortPhotoBoardMessages {
|
|||||||
String get custom => """Custom""";
|
String get custom => """Custom""";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ShareMessages {
|
||||||
|
final Messages _parent;
|
||||||
|
const ShareMessages(this._parent);
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Share to Pantry"
|
||||||
|
/// ```
|
||||||
|
String get title => """Share to Pantry""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Choose house"
|
||||||
|
/// ```
|
||||||
|
String get chooseHouse => """Choose house""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Upload to"
|
||||||
|
/// ```
|
||||||
|
String get choosePhotoDestination => """Upload to""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Photo Board"
|
||||||
|
/// ```
|
||||||
|
String get photoBoardRoot => """Photo Board""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "New folder"
|
||||||
|
/// ```
|
||||||
|
String get newFolder => """New folder""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Folder name"
|
||||||
|
/// ```
|
||||||
|
String get newFolderName => """Folder name""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Failed to create folder."
|
||||||
|
/// ```
|
||||||
|
String get failedToCreateFolder => """Failed to create folder.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Could not open the shared content."
|
||||||
|
/// ```
|
||||||
|
String get failedToOpenShare => """Could not open the shared content.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "No houses available. Create a house first."
|
||||||
|
/// ```
|
||||||
|
String get noHouses => """No houses available. Create a house first.""";
|
||||||
|
}
|
||||||
|
|
||||||
class RecurrenceMessages {
|
class RecurrenceMessages {
|
||||||
final Messages _parent;
|
final Messages _parent;
|
||||||
const RecurrenceMessages(this._parent);
|
const RecurrenceMessages(this._parent);
|
||||||
@@ -1390,6 +1597,17 @@ Please complete login in your browser.""",
|
|||||||
"""about.feedback""": """Feedback & issues""",
|
"""about.feedback""": """Feedback & issues""",
|
||||||
"""settings.title""": """App Settings""",
|
"""settings.title""": """App Settings""",
|
||||||
"""settings.generalSection""": """General""",
|
"""settings.generalSection""": """General""",
|
||||||
|
"""settings.interfaceSection""": """Interface""",
|
||||||
|
"""settings.tapRowToComplete""": """Tap row to complete items""",
|
||||||
|
"""settings.tapRowToCompleteBody""":
|
||||||
|
"""When off, items are only marked complete by tapping the checkbox.""",
|
||||||
|
"""settings.categorySpacing""":
|
||||||
|
"""Show spacing between categories in list items""",
|
||||||
|
"""settings.categorySpacingBody""":
|
||||||
|
"""Only visible when sorting by category""",
|
||||||
|
"""settings.categorySpacingNames.disabled""": """Disabled""",
|
||||||
|
"""settings.categorySpacingNames.space""": """Space""",
|
||||||
|
"""settings.categorySpacingNames.divider""": """Divider""",
|
||||||
"""settings.language""": """Language""",
|
"""settings.language""": """Language""",
|
||||||
"""settings.languageNames.system""": """System default""",
|
"""settings.languageNames.system""": """System default""",
|
||||||
"""settings.languageNames.english""": """English""",
|
"""settings.languageNames.english""": """English""",
|
||||||
@@ -1442,6 +1660,25 @@ Please complete login in your browser.""",
|
|||||||
"""checklists.removeItem""": """Remove item""",
|
"""checklists.removeItem""": """Remove item""",
|
||||||
"""checklists.moveItem""": """Move to list""",
|
"""checklists.moveItem""": """Move to list""",
|
||||||
"""checklists.moveFailed""": """Failed to move item.""",
|
"""checklists.moveFailed""": """Failed to move item.""",
|
||||||
|
"""checklists.itemMarkedDone""": """Item marked as done""",
|
||||||
|
"""checklists.undo""": """Undo""",
|
||||||
|
"""checklists.viewTrash""": """View trash""",
|
||||||
|
"""checklists.exitTrash""": """Exit trash""",
|
||||||
|
"""checklists.trashTitle""": """Trash""",
|
||||||
|
"""checklists.noTrashedItems""": """Trash is empty.""",
|
||||||
|
"""checklists.emptyTrash""": """Empty trash""",
|
||||||
|
"""checklists.emptyTrashConfirm""": """Empty the trash?""",
|
||||||
|
"""checklists.emptyTrashConfirmBody""":
|
||||||
|
"""All items in the trash will be permanently deleted. This cannot be undone.""",
|
||||||
|
"""checklists.emptyTrashFailed""": """Failed to empty trash.""",
|
||||||
|
"""checklists.restoreItem""": """Restore""",
|
||||||
|
"""checklists.permanentlyDeleteItem""": """Delete permanently""",
|
||||||
|
"""checklists.permanentlyDeleteConfirm""":
|
||||||
|
"""Permanently delete this item?""",
|
||||||
|
"""checklists.permanentlyDeleteConfirmBody""": """This cannot be undone.""",
|
||||||
|
"""checklists.restoreFailed""": """Failed to restore item.""",
|
||||||
|
"""checklists.permanentlyDeleteFailed""": """Failed to delete item.""",
|
||||||
|
"""checklists.itemRestored""": """Item restored""",
|
||||||
"""checklists.createList""": """New list""",
|
"""checklists.createList""": """New list""",
|
||||||
"""checklists.listName""": """List name""",
|
"""checklists.listName""": """List name""",
|
||||||
"""checklists.listDescription""": """Description (optional)""",
|
"""checklists.listDescription""": """Description (optional)""",
|
||||||
@@ -1514,12 +1751,24 @@ Please complete login in your browser.""",
|
|||||||
"""photoBoard.folderName""": """Folder name""",
|
"""photoBoard.folderName""": """Folder name""",
|
||||||
"""photoBoard.renameFolder""": """Rename folder""",
|
"""photoBoard.renameFolder""": """Rename folder""",
|
||||||
"""photoBoard.caption""": """Caption""",
|
"""photoBoard.caption""": """Caption""",
|
||||||
|
"""photoBoard.addMenu.upload""": """Upload photos""",
|
||||||
|
"""photoBoard.addMenu.camera""": """Take photo""",
|
||||||
|
"""photoBoard.addMenu.newFolder""": """New folder""",
|
||||||
"""photoBoard.sort.foldersFirst""": """Folders first""",
|
"""photoBoard.sort.foldersFirst""": """Folders first""",
|
||||||
"""photoBoard.sort.newestFirst""": """Newest first""",
|
"""photoBoard.sort.newestFirst""": """Newest first""",
|
||||||
"""photoBoard.sort.oldestFirst""": """Oldest first""",
|
"""photoBoard.sort.oldestFirst""": """Oldest first""",
|
||||||
"""photoBoard.sort.captionAZ""": """Caption A–Z""",
|
"""photoBoard.sort.captionAZ""": """Caption A–Z""",
|
||||||
"""photoBoard.sort.captionZA""": """Caption Z–A""",
|
"""photoBoard.sort.captionZA""": """Caption Z–A""",
|
||||||
"""photoBoard.sort.custom""": """Custom""",
|
"""photoBoard.sort.custom""": """Custom""",
|
||||||
|
"""share.title""": """Share to Pantry""",
|
||||||
|
"""share.chooseHouse""": """Choose house""",
|
||||||
|
"""share.choosePhotoDestination""": """Upload to""",
|
||||||
|
"""share.photoBoardRoot""": """Photo Board""",
|
||||||
|
"""share.newFolder""": """New folder""",
|
||||||
|
"""share.newFolderName""": """Folder name""",
|
||||||
|
"""share.failedToCreateFolder""": """Failed to create folder.""",
|
||||||
|
"""share.failedToOpenShare""": """Could not open the shared content.""",
|
||||||
|
"""share.noHouses""": """No houses available. Create a house first.""",
|
||||||
"""recurrence.title""": """Recurrence""",
|
"""recurrence.title""": """Recurrence""",
|
||||||
"""recurrence.presets""": """Presets""",
|
"""recurrence.presets""": """Presets""",
|
||||||
"""recurrence.daily""": """Daily""",
|
"""recurrence.daily""": """Daily""",
|
||||||
|
|||||||
@@ -59,6 +59,15 @@ about:
|
|||||||
settings:
|
settings:
|
||||||
title: App Settings
|
title: App Settings
|
||||||
generalSection: General
|
generalSection: General
|
||||||
|
interfaceSection: Interface
|
||||||
|
tapRowToComplete: Tap row to complete items
|
||||||
|
tapRowToCompleteBody: "When off, items are only marked complete by tapping the checkbox."
|
||||||
|
categorySpacing: Show spacing between categories in list items
|
||||||
|
categorySpacingBody: Only visible when sorting by category
|
||||||
|
categorySpacingNames:
|
||||||
|
disabled: Disabled
|
||||||
|
space: Space
|
||||||
|
divider: Divider
|
||||||
language: Language
|
language: Language
|
||||||
languageNames:
|
languageNames:
|
||||||
system: "System default"
|
system: "System default"
|
||||||
@@ -120,6 +129,23 @@ checklists:
|
|||||||
removeItem: Remove item
|
removeItem: Remove item
|
||||||
moveItem: Move to list
|
moveItem: Move to list
|
||||||
moveFailed: Failed to move item.
|
moveFailed: Failed to move item.
|
||||||
|
itemMarkedDone: Item marked as done
|
||||||
|
undo: Undo
|
||||||
|
viewTrash: View trash
|
||||||
|
exitTrash: Exit trash
|
||||||
|
trashTitle: Trash
|
||||||
|
noTrashedItems: Trash is empty.
|
||||||
|
emptyTrash: Empty trash
|
||||||
|
emptyTrashConfirm: Empty the trash?
|
||||||
|
emptyTrashConfirmBody: All items in the trash will be permanently deleted. This cannot be undone.
|
||||||
|
emptyTrashFailed: Failed to empty trash.
|
||||||
|
restoreItem: Restore
|
||||||
|
permanentlyDeleteItem: Delete permanently
|
||||||
|
permanentlyDeleteConfirm: Permanently delete this item?
|
||||||
|
permanentlyDeleteConfirmBody: This cannot be undone.
|
||||||
|
restoreFailed: Failed to restore item.
|
||||||
|
permanentlyDeleteFailed: Failed to delete item.
|
||||||
|
itemRestored: Item restored
|
||||||
createList: New list
|
createList: New list
|
||||||
listName: List name
|
listName: List name
|
||||||
listDescription: Description (optional)
|
listDescription: Description (optional)
|
||||||
@@ -200,6 +226,10 @@ photoBoard:
|
|||||||
renameFolder: Rename folder
|
renameFolder: Rename folder
|
||||||
caption: Caption
|
caption: Caption
|
||||||
photoCount(int count): "$count"
|
photoCount(int count): "$count"
|
||||||
|
addMenu:
|
||||||
|
upload: Upload photos
|
||||||
|
camera: Take photo
|
||||||
|
newFolder: New folder
|
||||||
sort:
|
sort:
|
||||||
foldersFirst: Folders first
|
foldersFirst: Folders first
|
||||||
newestFirst: Newest first
|
newestFirst: Newest first
|
||||||
@@ -208,6 +238,17 @@ photoBoard:
|
|||||||
captionZA: "Caption Z–A"
|
captionZA: "Caption Z–A"
|
||||||
custom: Custom
|
custom: Custom
|
||||||
|
|
||||||
|
share:
|
||||||
|
title: Share to Pantry
|
||||||
|
chooseHouse: Choose house
|
||||||
|
choosePhotoDestination: Upload to
|
||||||
|
photoBoardRoot: Photo Board
|
||||||
|
newFolder: New folder
|
||||||
|
newFolderName: Folder name
|
||||||
|
failedToCreateFolder: Failed to create folder.
|
||||||
|
failedToOpenShare: Could not open the shared content.
|
||||||
|
noHouses: No houses available. Create a house first.
|
||||||
|
|
||||||
recurrence:
|
recurrence:
|
||||||
title: Recurrence
|
title: Recurrence
|
||||||
presets: Presets
|
presets: Presets
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ class MessagesDe extends Messages {
|
|||||||
ChecklistsMessagesDe get checklists => ChecklistsMessagesDe(this);
|
ChecklistsMessagesDe get checklists => ChecklistsMessagesDe(this);
|
||||||
NotesWallMessagesDe get notesWall => NotesWallMessagesDe(this);
|
NotesWallMessagesDe get notesWall => NotesWallMessagesDe(this);
|
||||||
PhotoBoardMessagesDe get photoBoard => PhotoBoardMessagesDe(this);
|
PhotoBoardMessagesDe get photoBoard => PhotoBoardMessagesDe(this);
|
||||||
|
ShareMessagesDe get share => ShareMessagesDe(this);
|
||||||
RecurrenceMessagesDe get recurrence => RecurrenceMessagesDe(this);
|
RecurrenceMessagesDe get recurrence => RecurrenceMessagesDe(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,6 +364,36 @@ class SettingsMessagesDe extends SettingsMessages {
|
|||||||
/// ```
|
/// ```
|
||||||
String get generalSection => """Allgemein""";
|
String get generalSection => """Allgemein""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Oberfläche"
|
||||||
|
/// ```
|
||||||
|
String get interfaceSection => """Oberfläche""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Eintrag durch Tippen der Zeile abhaken"
|
||||||
|
/// ```
|
||||||
|
String get tapRowToComplete => """Eintrag durch Tippen der Zeile abhaken""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Wenn aus, werden Einträge nur durch Tippen auf das Kontrollkästchen abgehakt."
|
||||||
|
/// ```
|
||||||
|
String get tapRowToCompleteBody =>
|
||||||
|
"""Wenn aus, werden Einträge nur durch Tippen auf das Kontrollkästchen abgehakt.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Abstand zwischen Kategorien in Listeneinträgen anzeigen"
|
||||||
|
/// ```
|
||||||
|
String get categorySpacing =>
|
||||||
|
"""Abstand zwischen Kategorien in Listeneinträgen anzeigen""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Nur sichtbar bei Sortierung nach Kategorie"
|
||||||
|
/// ```
|
||||||
|
String get categorySpacingBody =>
|
||||||
|
"""Nur sichtbar bei Sortierung nach Kategorie""";
|
||||||
|
CategorySpacingNamesSettingsMessagesDe get categorySpacingNames =>
|
||||||
|
CategorySpacingNamesSettingsMessagesDe(this);
|
||||||
|
|
||||||
/// ```dart
|
/// ```dart
|
||||||
/// "Sprache"
|
/// "Sprache"
|
||||||
/// ```
|
/// ```
|
||||||
@@ -430,6 +461,27 @@ class SettingsMessagesDe extends SettingsMessages {
|
|||||||
"""Benachrichtigungsberechtigung wurde verweigert. Aktiviere sie in den Systemeinstellungen.""";
|
"""Benachrichtigungsberechtigung wurde verweigert. Aktiviere sie in den Systemeinstellungen.""";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CategorySpacingNamesSettingsMessagesDe
|
||||||
|
extends CategorySpacingNamesSettingsMessages {
|
||||||
|
final SettingsMessagesDe _parent;
|
||||||
|
const CategorySpacingNamesSettingsMessagesDe(this._parent) : super(_parent);
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Deaktiviert"
|
||||||
|
/// ```
|
||||||
|
String get disabled => """Deaktiviert""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Abstand"
|
||||||
|
/// ```
|
||||||
|
String get space => """Abstand""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Trennlinie"
|
||||||
|
/// ```
|
||||||
|
String get divider => """Trennlinie""";
|
||||||
|
}
|
||||||
|
|
||||||
class LanguageNamesSettingsMessagesDe extends LanguageNamesSettingsMessages {
|
class LanguageNamesSettingsMessagesDe extends LanguageNamesSettingsMessages {
|
||||||
final SettingsMessagesDe _parent;
|
final SettingsMessagesDe _parent;
|
||||||
const LanguageNamesSettingsMessagesDe(this._parent) : super(_parent);
|
const LanguageNamesSettingsMessagesDe(this._parent) : super(_parent);
|
||||||
@@ -661,6 +713,96 @@ class ChecklistsMessagesDe extends ChecklistsMessages {
|
|||||||
/// ```
|
/// ```
|
||||||
String get moveFailed => """Eintrag konnte nicht verschoben werden.""";
|
String get moveFailed => """Eintrag konnte nicht verschoben werden.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Eintrag als erledigt markiert"
|
||||||
|
/// ```
|
||||||
|
String get itemMarkedDone => """Eintrag als erledigt markiert""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Rückgängig"
|
||||||
|
/// ```
|
||||||
|
String get undo => """Rückgängig""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Papierkorb anzeigen"
|
||||||
|
/// ```
|
||||||
|
String get viewTrash => """Papierkorb anzeigen""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Papierkorb verlassen"
|
||||||
|
/// ```
|
||||||
|
String get exitTrash => """Papierkorb verlassen""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Papierkorb"
|
||||||
|
/// ```
|
||||||
|
String get trashTitle => """Papierkorb""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Der Papierkorb ist leer."
|
||||||
|
/// ```
|
||||||
|
String get noTrashedItems => """Der Papierkorb ist leer.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Papierkorb leeren"
|
||||||
|
/// ```
|
||||||
|
String get emptyTrash => """Papierkorb leeren""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Papierkorb leeren?"
|
||||||
|
/// ```
|
||||||
|
String get emptyTrashConfirm => """Papierkorb leeren?""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Alle Einträge im Papierkorb werden endgültig gelöscht. Dies kann nicht rückgängig gemacht werden."
|
||||||
|
/// ```
|
||||||
|
String get emptyTrashConfirmBody =>
|
||||||
|
"""Alle Einträge im Papierkorb werden endgültig gelöscht. Dies kann nicht rückgängig gemacht werden.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Papierkorb konnte nicht geleert werden."
|
||||||
|
/// ```
|
||||||
|
String get emptyTrashFailed => """Papierkorb konnte nicht geleert werden.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Wiederherstellen"
|
||||||
|
/// ```
|
||||||
|
String get restoreItem => """Wiederherstellen""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Endgültig löschen"
|
||||||
|
/// ```
|
||||||
|
String get permanentlyDeleteItem => """Endgültig löschen""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Diesen Eintrag endgültig löschen?"
|
||||||
|
/// ```
|
||||||
|
String get permanentlyDeleteConfirm =>
|
||||||
|
"""Diesen Eintrag endgültig löschen?""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Dies kann nicht rückgängig gemacht werden."
|
||||||
|
/// ```
|
||||||
|
String get permanentlyDeleteConfirmBody =>
|
||||||
|
"""Dies kann nicht rückgängig gemacht werden.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Eintrag konnte nicht wiederhergestellt werden."
|
||||||
|
/// ```
|
||||||
|
String get restoreFailed =>
|
||||||
|
"""Eintrag konnte nicht wiederhergestellt werden.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Eintrag konnte nicht gelöscht werden."
|
||||||
|
/// ```
|
||||||
|
String get permanentlyDeleteFailed =>
|
||||||
|
"""Eintrag konnte nicht gelöscht werden.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Eintrag wiederhergestellt"
|
||||||
|
/// ```
|
||||||
|
String get itemRestored => """Eintrag wiederhergestellt""";
|
||||||
|
|
||||||
/// ```dart
|
/// ```dart
|
||||||
/// "Neue Liste"
|
/// "Neue Liste"
|
||||||
/// ```
|
/// ```
|
||||||
@@ -1062,9 +1204,30 @@ class PhotoBoardMessagesDe extends PhotoBoardMessages {
|
|||||||
/// "$count"
|
/// "$count"
|
||||||
/// ```
|
/// ```
|
||||||
String photoCount(int count) => """$count""";
|
String photoCount(int count) => """$count""";
|
||||||
|
AddMenuPhotoBoardMessagesDe get addMenu => AddMenuPhotoBoardMessagesDe(this);
|
||||||
SortPhotoBoardMessagesDe get sort => SortPhotoBoardMessagesDe(this);
|
SortPhotoBoardMessagesDe get sort => SortPhotoBoardMessagesDe(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AddMenuPhotoBoardMessagesDe extends AddMenuPhotoBoardMessages {
|
||||||
|
final PhotoBoardMessagesDe _parent;
|
||||||
|
const AddMenuPhotoBoardMessagesDe(this._parent) : super(_parent);
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Fotos hochladen"
|
||||||
|
/// ```
|
||||||
|
String get upload => """Fotos hochladen""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Foto aufnehmen"
|
||||||
|
/// ```
|
||||||
|
String get camera => """Foto aufnehmen""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Neuer Ordner"
|
||||||
|
/// ```
|
||||||
|
String get newFolder => """Neuer Ordner""";
|
||||||
|
}
|
||||||
|
|
||||||
class SortPhotoBoardMessagesDe extends SortPhotoBoardMessages {
|
class SortPhotoBoardMessagesDe extends SortPhotoBoardMessages {
|
||||||
final PhotoBoardMessagesDe _parent;
|
final PhotoBoardMessagesDe _parent;
|
||||||
const SortPhotoBoardMessagesDe(this._parent) : super(_parent);
|
const SortPhotoBoardMessagesDe(this._parent) : super(_parent);
|
||||||
@@ -1100,6 +1263,58 @@ class SortPhotoBoardMessagesDe extends SortPhotoBoardMessages {
|
|||||||
String get custom => """Benutzerdefiniert""";
|
String get custom => """Benutzerdefiniert""";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ShareMessagesDe extends ShareMessages {
|
||||||
|
final MessagesDe _parent;
|
||||||
|
const ShareMessagesDe(this._parent) : super(_parent);
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "An Pantry senden"
|
||||||
|
/// ```
|
||||||
|
String get title => """An Pantry senden""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Haus auswählen"
|
||||||
|
/// ```
|
||||||
|
String get chooseHouse => """Haus auswählen""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Hochladen nach"
|
||||||
|
/// ```
|
||||||
|
String get choosePhotoDestination => """Hochladen nach""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Fotowand"
|
||||||
|
/// ```
|
||||||
|
String get photoBoardRoot => """Fotowand""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Neuer Ordner"
|
||||||
|
/// ```
|
||||||
|
String get newFolder => """Neuer Ordner""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Ordnername"
|
||||||
|
/// ```
|
||||||
|
String get newFolderName => """Ordnername""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Ordner konnte nicht erstellt werden."
|
||||||
|
/// ```
|
||||||
|
String get failedToCreateFolder => """Ordner konnte nicht erstellt werden.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Der geteilte Inhalt konnte nicht geöffnet werden."
|
||||||
|
/// ```
|
||||||
|
String get failedToOpenShare =>
|
||||||
|
"""Der geteilte Inhalt konnte nicht geöffnet werden.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Keine Häuser verfügbar. Erstelle zuerst ein Haus."
|
||||||
|
/// ```
|
||||||
|
String get noHouses =>
|
||||||
|
"""Keine Häuser verfügbar. Erstelle zuerst ein Haus.""";
|
||||||
|
}
|
||||||
|
|
||||||
class RecurrenceMessagesDe extends RecurrenceMessages {
|
class RecurrenceMessagesDe extends RecurrenceMessages {
|
||||||
final MessagesDe _parent;
|
final MessagesDe _parent;
|
||||||
const RecurrenceMessagesDe(this._parent) : super(_parent);
|
const RecurrenceMessagesDe(this._parent) : super(_parent);
|
||||||
@@ -1403,6 +1618,17 @@ Bitte melde dich in deinem Browser an.""",
|
|||||||
"""about.feedback""": """Feedback & Probleme""",
|
"""about.feedback""": """Feedback & Probleme""",
|
||||||
"""settings.title""": """App-Einstellungen""",
|
"""settings.title""": """App-Einstellungen""",
|
||||||
"""settings.generalSection""": """Allgemein""",
|
"""settings.generalSection""": """Allgemein""",
|
||||||
|
"""settings.interfaceSection""": """Oberfläche""",
|
||||||
|
"""settings.tapRowToComplete""": """Eintrag durch Tippen der Zeile abhaken""",
|
||||||
|
"""settings.tapRowToCompleteBody""":
|
||||||
|
"""Wenn aus, werden Einträge nur durch Tippen auf das Kontrollkästchen abgehakt.""",
|
||||||
|
"""settings.categorySpacing""":
|
||||||
|
"""Abstand zwischen Kategorien in Listeneinträgen anzeigen""",
|
||||||
|
"""settings.categorySpacingBody""":
|
||||||
|
"""Nur sichtbar bei Sortierung nach Kategorie""",
|
||||||
|
"""settings.categorySpacingNames.disabled""": """Deaktiviert""",
|
||||||
|
"""settings.categorySpacingNames.space""": """Abstand""",
|
||||||
|
"""settings.categorySpacingNames.divider""": """Trennlinie""",
|
||||||
"""settings.language""": """Sprache""",
|
"""settings.language""": """Sprache""",
|
||||||
"""settings.languageNames.system""": """Systemstandard""",
|
"""settings.languageNames.system""": """Systemstandard""",
|
||||||
"""settings.languageNames.english""": """English""",
|
"""settings.languageNames.english""": """English""",
|
||||||
@@ -1459,6 +1685,29 @@ Bitte melde dich in deinem Browser an.""",
|
|||||||
"""checklists.removeItem""": """Eintrag entfernen""",
|
"""checklists.removeItem""": """Eintrag entfernen""",
|
||||||
"""checklists.moveItem""": """In Liste verschieben""",
|
"""checklists.moveItem""": """In Liste verschieben""",
|
||||||
"""checklists.moveFailed""": """Eintrag konnte nicht verschoben werden.""",
|
"""checklists.moveFailed""": """Eintrag konnte nicht verschoben werden.""",
|
||||||
|
"""checklists.itemMarkedDone""": """Eintrag als erledigt markiert""",
|
||||||
|
"""checklists.undo""": """Rückgängig""",
|
||||||
|
"""checklists.viewTrash""": """Papierkorb anzeigen""",
|
||||||
|
"""checklists.exitTrash""": """Papierkorb verlassen""",
|
||||||
|
"""checklists.trashTitle""": """Papierkorb""",
|
||||||
|
"""checklists.noTrashedItems""": """Der Papierkorb ist leer.""",
|
||||||
|
"""checklists.emptyTrash""": """Papierkorb leeren""",
|
||||||
|
"""checklists.emptyTrashConfirm""": """Papierkorb leeren?""",
|
||||||
|
"""checklists.emptyTrashConfirmBody""":
|
||||||
|
"""Alle Einträge im Papierkorb werden endgültig gelöscht. Dies kann nicht rückgängig gemacht werden.""",
|
||||||
|
"""checklists.emptyTrashFailed""":
|
||||||
|
"""Papierkorb konnte nicht geleert werden.""",
|
||||||
|
"""checklists.restoreItem""": """Wiederherstellen""",
|
||||||
|
"""checklists.permanentlyDeleteItem""": """Endgültig löschen""",
|
||||||
|
"""checklists.permanentlyDeleteConfirm""":
|
||||||
|
"""Diesen Eintrag endgültig löschen?""",
|
||||||
|
"""checklists.permanentlyDeleteConfirmBody""":
|
||||||
|
"""Dies kann nicht rückgängig gemacht werden.""",
|
||||||
|
"""checklists.restoreFailed""":
|
||||||
|
"""Eintrag konnte nicht wiederhergestellt werden.""",
|
||||||
|
"""checklists.permanentlyDeleteFailed""":
|
||||||
|
"""Eintrag konnte nicht gelöscht werden.""",
|
||||||
|
"""checklists.itemRestored""": """Eintrag wiederhergestellt""",
|
||||||
"""checklists.createList""": """Neue Liste""",
|
"""checklists.createList""": """Neue Liste""",
|
||||||
"""checklists.listName""": """Listenname""",
|
"""checklists.listName""": """Listenname""",
|
||||||
"""checklists.listDescription""": """Beschreibung (optional)""",
|
"""checklists.listDescription""": """Beschreibung (optional)""",
|
||||||
@@ -1534,12 +1783,25 @@ Bitte melde dich in deinem Browser an.""",
|
|||||||
"""photoBoard.folderName""": """Ordnername""",
|
"""photoBoard.folderName""": """Ordnername""",
|
||||||
"""photoBoard.renameFolder""": """Ordner umbenennen""",
|
"""photoBoard.renameFolder""": """Ordner umbenennen""",
|
||||||
"""photoBoard.caption""": """Beschriftung""",
|
"""photoBoard.caption""": """Beschriftung""",
|
||||||
|
"""photoBoard.addMenu.upload""": """Fotos hochladen""",
|
||||||
|
"""photoBoard.addMenu.camera""": """Foto aufnehmen""",
|
||||||
|
"""photoBoard.addMenu.newFolder""": """Neuer Ordner""",
|
||||||
"""photoBoard.sort.foldersFirst""": """Ordner zuerst""",
|
"""photoBoard.sort.foldersFirst""": """Ordner zuerst""",
|
||||||
"""photoBoard.sort.newestFirst""": """Neueste zuerst""",
|
"""photoBoard.sort.newestFirst""": """Neueste zuerst""",
|
||||||
"""photoBoard.sort.oldestFirst""": """Älteste zuerst""",
|
"""photoBoard.sort.oldestFirst""": """Älteste zuerst""",
|
||||||
"""photoBoard.sort.captionAZ""": """Beschriftung A–Z""",
|
"""photoBoard.sort.captionAZ""": """Beschriftung A–Z""",
|
||||||
"""photoBoard.sort.captionZA""": """Beschriftung Z–A""",
|
"""photoBoard.sort.captionZA""": """Beschriftung Z–A""",
|
||||||
"""photoBoard.sort.custom""": """Benutzerdefiniert""",
|
"""photoBoard.sort.custom""": """Benutzerdefiniert""",
|
||||||
|
"""share.title""": """An Pantry senden""",
|
||||||
|
"""share.chooseHouse""": """Haus auswählen""",
|
||||||
|
"""share.choosePhotoDestination""": """Hochladen nach""",
|
||||||
|
"""share.photoBoardRoot""": """Fotowand""",
|
||||||
|
"""share.newFolder""": """Neuer Ordner""",
|
||||||
|
"""share.newFolderName""": """Ordnername""",
|
||||||
|
"""share.failedToCreateFolder""": """Ordner konnte nicht erstellt werden.""",
|
||||||
|
"""share.failedToOpenShare""":
|
||||||
|
"""Der geteilte Inhalt konnte nicht geöffnet werden.""",
|
||||||
|
"""share.noHouses""": """Keine Häuser verfügbar. Erstelle zuerst ein Haus.""",
|
||||||
"""recurrence.title""": """Wiederholung""",
|
"""recurrence.title""": """Wiederholung""",
|
||||||
"""recurrence.presets""": """Voreinstellungen""",
|
"""recurrence.presets""": """Voreinstellungen""",
|
||||||
"""recurrence.daily""": """Täglich""",
|
"""recurrence.daily""": """Täglich""",
|
||||||
|
|||||||
@@ -59,6 +59,15 @@ about:
|
|||||||
settings:
|
settings:
|
||||||
title: App-Einstellungen
|
title: App-Einstellungen
|
||||||
generalSection: Allgemein
|
generalSection: Allgemein
|
||||||
|
interfaceSection: Oberfläche
|
||||||
|
tapRowToComplete: Eintrag durch Tippen der Zeile abhaken
|
||||||
|
tapRowToCompleteBody: "Wenn aus, werden Einträge nur durch Tippen auf das Kontrollkästchen abgehakt."
|
||||||
|
categorySpacing: Abstand zwischen Kategorien in Listeneinträgen anzeigen
|
||||||
|
categorySpacingBody: Nur sichtbar bei Sortierung nach Kategorie
|
||||||
|
categorySpacingNames:
|
||||||
|
disabled: Deaktiviert
|
||||||
|
space: Abstand
|
||||||
|
divider: Trennlinie
|
||||||
language: Sprache
|
language: Sprache
|
||||||
languageNames:
|
languageNames:
|
||||||
system: Systemstandard
|
system: Systemstandard
|
||||||
@@ -120,6 +129,23 @@ checklists:
|
|||||||
removeItem: Eintrag entfernen
|
removeItem: Eintrag entfernen
|
||||||
moveItem: In Liste verschieben
|
moveItem: In Liste verschieben
|
||||||
moveFailed: Eintrag konnte nicht verschoben werden.
|
moveFailed: Eintrag konnte nicht verschoben werden.
|
||||||
|
itemMarkedDone: Eintrag als erledigt markiert
|
||||||
|
undo: "Rückgängig"
|
||||||
|
viewTrash: Papierkorb anzeigen
|
||||||
|
exitTrash: Papierkorb verlassen
|
||||||
|
trashTitle: Papierkorb
|
||||||
|
noTrashedItems: Der Papierkorb ist leer.
|
||||||
|
emptyTrash: Papierkorb leeren
|
||||||
|
emptyTrashConfirm: Papierkorb leeren?
|
||||||
|
emptyTrashConfirmBody: "Alle Einträge im Papierkorb werden endgültig gelöscht. Dies kann nicht rückgängig gemacht werden."
|
||||||
|
emptyTrashFailed: Papierkorb konnte nicht geleert werden.
|
||||||
|
restoreItem: Wiederherstellen
|
||||||
|
permanentlyDeleteItem: Endgültig löschen
|
||||||
|
permanentlyDeleteConfirm: Diesen Eintrag endgültig löschen?
|
||||||
|
permanentlyDeleteConfirmBody: "Dies kann nicht rückgängig gemacht werden."
|
||||||
|
restoreFailed: Eintrag konnte nicht wiederhergestellt werden.
|
||||||
|
permanentlyDeleteFailed: Eintrag konnte nicht gelöscht werden.
|
||||||
|
itemRestored: Eintrag wiederhergestellt
|
||||||
createList: Neue Liste
|
createList: Neue Liste
|
||||||
listName: Listenname
|
listName: Listenname
|
||||||
listDescription: Beschreibung (optional)
|
listDescription: Beschreibung (optional)
|
||||||
@@ -200,6 +226,10 @@ photoBoard:
|
|||||||
renameFolder: Ordner umbenennen
|
renameFolder: Ordner umbenennen
|
||||||
caption: Beschriftung
|
caption: Beschriftung
|
||||||
photoCount(int count): "$count"
|
photoCount(int count): "$count"
|
||||||
|
addMenu:
|
||||||
|
upload: Fotos hochladen
|
||||||
|
camera: Foto aufnehmen
|
||||||
|
newFolder: Neuer Ordner
|
||||||
sort:
|
sort:
|
||||||
foldersFirst: Ordner zuerst
|
foldersFirst: Ordner zuerst
|
||||||
newestFirst: Neueste zuerst
|
newestFirst: Neueste zuerst
|
||||||
@@ -208,6 +238,17 @@ photoBoard:
|
|||||||
captionZA: "Beschriftung Z–A"
|
captionZA: "Beschriftung Z–A"
|
||||||
custom: Benutzerdefiniert
|
custom: Benutzerdefiniert
|
||||||
|
|
||||||
|
share:
|
||||||
|
title: An Pantry senden
|
||||||
|
chooseHouse: Haus auswählen
|
||||||
|
choosePhotoDestination: Hochladen nach
|
||||||
|
photoBoardRoot: Fotowand
|
||||||
|
newFolder: Neuer Ordner
|
||||||
|
newFolderName: Ordnername
|
||||||
|
failedToCreateFolder: Ordner konnte nicht erstellt werden.
|
||||||
|
failedToOpenShare: Der geteilte Inhalt konnte nicht geöffnet werden.
|
||||||
|
noHouses: Keine Häuser verfügbar. Erstelle zuerst ein Haus.
|
||||||
|
|
||||||
recurrence:
|
recurrence:
|
||||||
title: Wiederholung
|
title: Wiederholung
|
||||||
presets: Voreinstellungen
|
presets: Voreinstellungen
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ class MessagesEs extends Messages {
|
|||||||
ChecklistsMessagesEs get checklists => ChecklistsMessagesEs(this);
|
ChecklistsMessagesEs get checklists => ChecklistsMessagesEs(this);
|
||||||
NotesWallMessagesEs get notesWall => NotesWallMessagesEs(this);
|
NotesWallMessagesEs get notesWall => NotesWallMessagesEs(this);
|
||||||
PhotoBoardMessagesEs get photoBoard => PhotoBoardMessagesEs(this);
|
PhotoBoardMessagesEs get photoBoard => PhotoBoardMessagesEs(this);
|
||||||
|
ShareMessagesEs get share => ShareMessagesEs(this);
|
||||||
RecurrenceMessagesEs get recurrence => RecurrenceMessagesEs(this);
|
RecurrenceMessagesEs get recurrence => RecurrenceMessagesEs(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,6 +364,35 @@ class SettingsMessagesEs extends SettingsMessages {
|
|||||||
/// ```
|
/// ```
|
||||||
String get generalSection => """General""";
|
String get generalSection => """General""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Interfaz"
|
||||||
|
/// ```
|
||||||
|
String get interfaceSection => """Interfaz""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Tocar la fila para completar elementos"
|
||||||
|
/// ```
|
||||||
|
String get tapRowToComplete => """Tocar la fila para completar elementos""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Cuando está desactivado, los elementos solo se marcan como completados al tocar la casilla."
|
||||||
|
/// ```
|
||||||
|
String get tapRowToCompleteBody =>
|
||||||
|
"""Cuando está desactivado, los elementos solo se marcan como completados al tocar la casilla.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Mostrar espacio entre categorías en los elementos de la lista"
|
||||||
|
/// ```
|
||||||
|
String get categorySpacing =>
|
||||||
|
"""Mostrar espacio entre categorías en los elementos de la lista""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Solo visible al ordenar por categoría"
|
||||||
|
/// ```
|
||||||
|
String get categorySpacingBody => """Solo visible al ordenar por categoría""";
|
||||||
|
CategorySpacingNamesSettingsMessagesEs get categorySpacingNames =>
|
||||||
|
CategorySpacingNamesSettingsMessagesEs(this);
|
||||||
|
|
||||||
/// ```dart
|
/// ```dart
|
||||||
/// "Idioma"
|
/// "Idioma"
|
||||||
/// ```
|
/// ```
|
||||||
@@ -430,6 +460,27 @@ class SettingsMessagesEs extends SettingsMessages {
|
|||||||
"""El permiso de notificaciones fue denegado. Actívalo en los ajustes del sistema.""";
|
"""El permiso de notificaciones fue denegado. Actívalo en los ajustes del sistema.""";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CategorySpacingNamesSettingsMessagesEs
|
||||||
|
extends CategorySpacingNamesSettingsMessages {
|
||||||
|
final SettingsMessagesEs _parent;
|
||||||
|
const CategorySpacingNamesSettingsMessagesEs(this._parent) : super(_parent);
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Desactivado"
|
||||||
|
/// ```
|
||||||
|
String get disabled => """Desactivado""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Espacio"
|
||||||
|
/// ```
|
||||||
|
String get space => """Espacio""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Separador"
|
||||||
|
/// ```
|
||||||
|
String get divider => """Separador""";
|
||||||
|
}
|
||||||
|
|
||||||
class LanguageNamesSettingsMessagesEs extends LanguageNamesSettingsMessages {
|
class LanguageNamesSettingsMessagesEs extends LanguageNamesSettingsMessages {
|
||||||
final SettingsMessagesEs _parent;
|
final SettingsMessagesEs _parent;
|
||||||
const LanguageNamesSettingsMessagesEs(this._parent) : super(_parent);
|
const LanguageNamesSettingsMessagesEs(this._parent) : super(_parent);
|
||||||
@@ -660,6 +711,94 @@ class ChecklistsMessagesEs extends ChecklistsMessages {
|
|||||||
/// ```
|
/// ```
|
||||||
String get moveFailed => """No se pudo mover el artículo.""";
|
String get moveFailed => """No se pudo mover el artículo.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Artículo marcado como hecho"
|
||||||
|
/// ```
|
||||||
|
String get itemMarkedDone => """Artículo marcado como hecho""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Deshacer"
|
||||||
|
/// ```
|
||||||
|
String get undo => """Deshacer""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Ver papelera"
|
||||||
|
/// ```
|
||||||
|
String get viewTrash => """Ver papelera""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Salir de la papelera"
|
||||||
|
/// ```
|
||||||
|
String get exitTrash => """Salir de la papelera""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Papelera"
|
||||||
|
/// ```
|
||||||
|
String get trashTitle => """Papelera""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "La papelera está vacía."
|
||||||
|
/// ```
|
||||||
|
String get noTrashedItems => """La papelera está vacía.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Vaciar papelera"
|
||||||
|
/// ```
|
||||||
|
String get emptyTrash => """Vaciar papelera""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "¿Vaciar la papelera?"
|
||||||
|
/// ```
|
||||||
|
String get emptyTrashConfirm => """¿Vaciar la papelera?""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Todos los artículos de la papelera se eliminarán permanentemente. Esta acción no se puede deshacer."
|
||||||
|
/// ```
|
||||||
|
String get emptyTrashConfirmBody =>
|
||||||
|
"""Todos los artículos de la papelera se eliminarán permanentemente. Esta acción no se puede deshacer.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "No se pudo vaciar la papelera."
|
||||||
|
/// ```
|
||||||
|
String get emptyTrashFailed => """No se pudo vaciar la papelera.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Restaurar"
|
||||||
|
/// ```
|
||||||
|
String get restoreItem => """Restaurar""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Eliminar permanentemente"
|
||||||
|
/// ```
|
||||||
|
String get permanentlyDeleteItem => """Eliminar permanentemente""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "¿Eliminar este artículo permanentemente?"
|
||||||
|
/// ```
|
||||||
|
String get permanentlyDeleteConfirm =>
|
||||||
|
"""¿Eliminar este artículo permanentemente?""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Esta acción no se puede deshacer."
|
||||||
|
/// ```
|
||||||
|
String get permanentlyDeleteConfirmBody =>
|
||||||
|
"""Esta acción no se puede deshacer.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "No se pudo restaurar el artículo."
|
||||||
|
/// ```
|
||||||
|
String get restoreFailed => """No se pudo restaurar el artículo.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "No se pudo eliminar el artículo."
|
||||||
|
/// ```
|
||||||
|
String get permanentlyDeleteFailed => """No se pudo eliminar el artículo.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Artículo restaurado"
|
||||||
|
/// ```
|
||||||
|
String get itemRestored => """Artículo restaurado""";
|
||||||
|
|
||||||
/// ```dart
|
/// ```dart
|
||||||
/// "Nueva lista"
|
/// "Nueva lista"
|
||||||
/// ```
|
/// ```
|
||||||
@@ -1059,9 +1198,30 @@ class PhotoBoardMessagesEs extends PhotoBoardMessages {
|
|||||||
/// "$count"
|
/// "$count"
|
||||||
/// ```
|
/// ```
|
||||||
String photoCount(int count) => """$count""";
|
String photoCount(int count) => """$count""";
|
||||||
|
AddMenuPhotoBoardMessagesEs get addMenu => AddMenuPhotoBoardMessagesEs(this);
|
||||||
SortPhotoBoardMessagesEs get sort => SortPhotoBoardMessagesEs(this);
|
SortPhotoBoardMessagesEs get sort => SortPhotoBoardMessagesEs(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AddMenuPhotoBoardMessagesEs extends AddMenuPhotoBoardMessages {
|
||||||
|
final PhotoBoardMessagesEs _parent;
|
||||||
|
const AddMenuPhotoBoardMessagesEs(this._parent) : super(_parent);
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Subir fotos"
|
||||||
|
/// ```
|
||||||
|
String get upload => """Subir fotos""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Tomar foto"
|
||||||
|
/// ```
|
||||||
|
String get camera => """Tomar foto""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Nueva carpeta"
|
||||||
|
/// ```
|
||||||
|
String get newFolder => """Nueva carpeta""";
|
||||||
|
}
|
||||||
|
|
||||||
class SortPhotoBoardMessagesEs extends SortPhotoBoardMessages {
|
class SortPhotoBoardMessagesEs extends SortPhotoBoardMessages {
|
||||||
final PhotoBoardMessagesEs _parent;
|
final PhotoBoardMessagesEs _parent;
|
||||||
const SortPhotoBoardMessagesEs(this._parent) : super(_parent);
|
const SortPhotoBoardMessagesEs(this._parent) : super(_parent);
|
||||||
@@ -1097,6 +1257,57 @@ class SortPhotoBoardMessagesEs extends SortPhotoBoardMessages {
|
|||||||
String get custom => """Personalizado""";
|
String get custom => """Personalizado""";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ShareMessagesEs extends ShareMessages {
|
||||||
|
final MessagesEs _parent;
|
||||||
|
const ShareMessagesEs(this._parent) : super(_parent);
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Compartir con Pantry"
|
||||||
|
/// ```
|
||||||
|
String get title => """Compartir con Pantry""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Elegir casa"
|
||||||
|
/// ```
|
||||||
|
String get chooseHouse => """Elegir casa""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Subir a"
|
||||||
|
/// ```
|
||||||
|
String get choosePhotoDestination => """Subir a""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Tablón de fotos"
|
||||||
|
/// ```
|
||||||
|
String get photoBoardRoot => """Tablón de fotos""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Nueva carpeta"
|
||||||
|
/// ```
|
||||||
|
String get newFolder => """Nueva carpeta""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Nombre de la carpeta"
|
||||||
|
/// ```
|
||||||
|
String get newFolderName => """Nombre de la carpeta""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "No se pudo crear la carpeta."
|
||||||
|
/// ```
|
||||||
|
String get failedToCreateFolder => """No se pudo crear la carpeta.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "No se pudo abrir el contenido compartido."
|
||||||
|
/// ```
|
||||||
|
String get failedToOpenShare =>
|
||||||
|
"""No se pudo abrir el contenido compartido.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "No hay casas disponibles. Crea una casa primero."
|
||||||
|
/// ```
|
||||||
|
String get noHouses => """No hay casas disponibles. Crea una casa primero.""";
|
||||||
|
}
|
||||||
|
|
||||||
class RecurrenceMessagesEs extends RecurrenceMessages {
|
class RecurrenceMessagesEs extends RecurrenceMessages {
|
||||||
final MessagesEs _parent;
|
final MessagesEs _parent;
|
||||||
const RecurrenceMessagesEs(this._parent) : super(_parent);
|
const RecurrenceMessagesEs(this._parent) : super(_parent);
|
||||||
@@ -1398,6 +1609,17 @@ Por favor, completa el inicio de sesión en tu navegador.""",
|
|||||||
"""about.feedback""": """Comentarios y problemas""",
|
"""about.feedback""": """Comentarios y problemas""",
|
||||||
"""settings.title""": """Ajustes de la app""",
|
"""settings.title""": """Ajustes de la app""",
|
||||||
"""settings.generalSection""": """General""",
|
"""settings.generalSection""": """General""",
|
||||||
|
"""settings.interfaceSection""": """Interfaz""",
|
||||||
|
"""settings.tapRowToComplete""": """Tocar la fila para completar elementos""",
|
||||||
|
"""settings.tapRowToCompleteBody""":
|
||||||
|
"""Cuando está desactivado, los elementos solo se marcan como completados al tocar la casilla.""",
|
||||||
|
"""settings.categorySpacing""":
|
||||||
|
"""Mostrar espacio entre categorías en los elementos de la lista""",
|
||||||
|
"""settings.categorySpacingBody""":
|
||||||
|
"""Solo visible al ordenar por categoría""",
|
||||||
|
"""settings.categorySpacingNames.disabled""": """Desactivado""",
|
||||||
|
"""settings.categorySpacingNames.space""": """Espacio""",
|
||||||
|
"""settings.categorySpacingNames.divider""": """Separador""",
|
||||||
"""settings.language""": """Idioma""",
|
"""settings.language""": """Idioma""",
|
||||||
"""settings.languageNames.system""": """Predeterminado del sistema""",
|
"""settings.languageNames.system""": """Predeterminado del sistema""",
|
||||||
"""settings.languageNames.english""": """English""",
|
"""settings.languageNames.english""": """English""",
|
||||||
@@ -1453,6 +1675,27 @@ Por favor, completa el inicio de sesión en tu navegador.""",
|
|||||||
"""checklists.removeItem""": """Eliminar artículo""",
|
"""checklists.removeItem""": """Eliminar artículo""",
|
||||||
"""checklists.moveItem""": """Mover a lista""",
|
"""checklists.moveItem""": """Mover a lista""",
|
||||||
"""checklists.moveFailed""": """No se pudo mover el artículo.""",
|
"""checklists.moveFailed""": """No se pudo mover el artículo.""",
|
||||||
|
"""checklists.itemMarkedDone""": """Artículo marcado como hecho""",
|
||||||
|
"""checklists.undo""": """Deshacer""",
|
||||||
|
"""checklists.viewTrash""": """Ver papelera""",
|
||||||
|
"""checklists.exitTrash""": """Salir de la papelera""",
|
||||||
|
"""checklists.trashTitle""": """Papelera""",
|
||||||
|
"""checklists.noTrashedItems""": """La papelera está vacía.""",
|
||||||
|
"""checklists.emptyTrash""": """Vaciar papelera""",
|
||||||
|
"""checklists.emptyTrashConfirm""": """¿Vaciar la papelera?""",
|
||||||
|
"""checklists.emptyTrashConfirmBody""":
|
||||||
|
"""Todos los artículos de la papelera se eliminarán permanentemente. Esta acción no se puede deshacer.""",
|
||||||
|
"""checklists.emptyTrashFailed""": """No se pudo vaciar la papelera.""",
|
||||||
|
"""checklists.restoreItem""": """Restaurar""",
|
||||||
|
"""checklists.permanentlyDeleteItem""": """Eliminar permanentemente""",
|
||||||
|
"""checklists.permanentlyDeleteConfirm""":
|
||||||
|
"""¿Eliminar este artículo permanentemente?""",
|
||||||
|
"""checklists.permanentlyDeleteConfirmBody""":
|
||||||
|
"""Esta acción no se puede deshacer.""",
|
||||||
|
"""checklists.restoreFailed""": """No se pudo restaurar el artículo.""",
|
||||||
|
"""checklists.permanentlyDeleteFailed""":
|
||||||
|
"""No se pudo eliminar el artículo.""",
|
||||||
|
"""checklists.itemRestored""": """Artículo restaurado""",
|
||||||
"""checklists.createList""": """Nueva lista""",
|
"""checklists.createList""": """Nueva lista""",
|
||||||
"""checklists.listName""": """Nombre de la lista""",
|
"""checklists.listName""": """Nombre de la lista""",
|
||||||
"""checklists.listDescription""": """Descripción (opcional)""",
|
"""checklists.listDescription""": """Descripción (opcional)""",
|
||||||
@@ -1526,12 +1769,25 @@ Por favor, completa el inicio de sesión en tu navegador.""",
|
|||||||
"""photoBoard.folderName""": """Nombre de la carpeta""",
|
"""photoBoard.folderName""": """Nombre de la carpeta""",
|
||||||
"""photoBoard.renameFolder""": """Renombrar carpeta""",
|
"""photoBoard.renameFolder""": """Renombrar carpeta""",
|
||||||
"""photoBoard.caption""": """Descripción""",
|
"""photoBoard.caption""": """Descripción""",
|
||||||
|
"""photoBoard.addMenu.upload""": """Subir fotos""",
|
||||||
|
"""photoBoard.addMenu.camera""": """Tomar foto""",
|
||||||
|
"""photoBoard.addMenu.newFolder""": """Nueva carpeta""",
|
||||||
"""photoBoard.sort.foldersFirst""": """Carpetas primero""",
|
"""photoBoard.sort.foldersFirst""": """Carpetas primero""",
|
||||||
"""photoBoard.sort.newestFirst""": """Más recientes""",
|
"""photoBoard.sort.newestFirst""": """Más recientes""",
|
||||||
"""photoBoard.sort.oldestFirst""": """Más antiguos""",
|
"""photoBoard.sort.oldestFirst""": """Más antiguos""",
|
||||||
"""photoBoard.sort.captionAZ""": """Descripción A–Z""",
|
"""photoBoard.sort.captionAZ""": """Descripción A–Z""",
|
||||||
"""photoBoard.sort.captionZA""": """Descripción Z–A""",
|
"""photoBoard.sort.captionZA""": """Descripción Z–A""",
|
||||||
"""photoBoard.sort.custom""": """Personalizado""",
|
"""photoBoard.sort.custom""": """Personalizado""",
|
||||||
|
"""share.title""": """Compartir con Pantry""",
|
||||||
|
"""share.chooseHouse""": """Elegir casa""",
|
||||||
|
"""share.choosePhotoDestination""": """Subir a""",
|
||||||
|
"""share.photoBoardRoot""": """Tablón de fotos""",
|
||||||
|
"""share.newFolder""": """Nueva carpeta""",
|
||||||
|
"""share.newFolderName""": """Nombre de la carpeta""",
|
||||||
|
"""share.failedToCreateFolder""": """No se pudo crear la carpeta.""",
|
||||||
|
"""share.failedToOpenShare""":
|
||||||
|
"""No se pudo abrir el contenido compartido.""",
|
||||||
|
"""share.noHouses""": """No hay casas disponibles. Crea una casa primero.""",
|
||||||
"""recurrence.title""": """Recurrencia""",
|
"""recurrence.title""": """Recurrencia""",
|
||||||
"""recurrence.presets""": """Preajustes""",
|
"""recurrence.presets""": """Preajustes""",
|
||||||
"""recurrence.daily""": """Diario""",
|
"""recurrence.daily""": """Diario""",
|
||||||
|
|||||||
@@ -59,6 +59,15 @@ about:
|
|||||||
settings:
|
settings:
|
||||||
title: Ajustes de la app
|
title: Ajustes de la app
|
||||||
generalSection: General
|
generalSection: General
|
||||||
|
interfaceSection: Interfaz
|
||||||
|
tapRowToComplete: Tocar la fila para completar elementos
|
||||||
|
tapRowToCompleteBody: "Cuando está desactivado, los elementos solo se marcan como completados al tocar la casilla."
|
||||||
|
categorySpacing: Mostrar espacio entre categorías en los elementos de la lista
|
||||||
|
categorySpacingBody: Solo visible al ordenar por categoría
|
||||||
|
categorySpacingNames:
|
||||||
|
disabled: Desactivado
|
||||||
|
space: Espacio
|
||||||
|
divider: Separador
|
||||||
language: Idioma
|
language: Idioma
|
||||||
languageNames:
|
languageNames:
|
||||||
system: Predeterminado del sistema
|
system: Predeterminado del sistema
|
||||||
@@ -120,6 +129,23 @@ checklists:
|
|||||||
removeItem: "Eliminar artículo"
|
removeItem: "Eliminar artículo"
|
||||||
moveItem: Mover a lista
|
moveItem: Mover a lista
|
||||||
moveFailed: "No se pudo mover el artículo."
|
moveFailed: "No se pudo mover el artículo."
|
||||||
|
itemMarkedDone: "Artículo marcado como hecho"
|
||||||
|
undo: Deshacer
|
||||||
|
viewTrash: Ver papelera
|
||||||
|
exitTrash: Salir de la papelera
|
||||||
|
trashTitle: Papelera
|
||||||
|
noTrashedItems: La papelera está vacía.
|
||||||
|
emptyTrash: Vaciar papelera
|
||||||
|
emptyTrashConfirm: ¿Vaciar la papelera?
|
||||||
|
emptyTrashConfirmBody: "Todos los artículos de la papelera se eliminarán permanentemente. Esta acción no se puede deshacer."
|
||||||
|
emptyTrashFailed: No se pudo vaciar la papelera.
|
||||||
|
restoreItem: Restaurar
|
||||||
|
permanentlyDeleteItem: Eliminar permanentemente
|
||||||
|
permanentlyDeleteConfirm: "¿Eliminar este artículo permanentemente?"
|
||||||
|
permanentlyDeleteConfirmBody: Esta acción no se puede deshacer.
|
||||||
|
restoreFailed: No se pudo restaurar el artículo.
|
||||||
|
permanentlyDeleteFailed: No se pudo eliminar el artículo.
|
||||||
|
itemRestored: Artículo restaurado
|
||||||
createList: Nueva lista
|
createList: Nueva lista
|
||||||
listName: Nombre de la lista
|
listName: Nombre de la lista
|
||||||
listDescription: "Descripción (opcional)"
|
listDescription: "Descripción (opcional)"
|
||||||
@@ -200,6 +226,10 @@ photoBoard:
|
|||||||
renameFolder: Renombrar carpeta
|
renameFolder: Renombrar carpeta
|
||||||
caption: "Descripción"
|
caption: "Descripción"
|
||||||
photoCount(int count): "$count"
|
photoCount(int count): "$count"
|
||||||
|
addMenu:
|
||||||
|
upload: Subir fotos
|
||||||
|
camera: Tomar foto
|
||||||
|
newFolder: Nueva carpeta
|
||||||
sort:
|
sort:
|
||||||
foldersFirst: Carpetas primero
|
foldersFirst: Carpetas primero
|
||||||
newestFirst: "Más recientes"
|
newestFirst: "Más recientes"
|
||||||
@@ -208,6 +238,17 @@ photoBoard:
|
|||||||
captionZA: "Descripción Z–A"
|
captionZA: "Descripción Z–A"
|
||||||
custom: Personalizado
|
custom: Personalizado
|
||||||
|
|
||||||
|
share:
|
||||||
|
title: Compartir con Pantry
|
||||||
|
chooseHouse: Elegir casa
|
||||||
|
choosePhotoDestination: Subir a
|
||||||
|
photoBoardRoot: Tablón de fotos
|
||||||
|
newFolder: Nueva carpeta
|
||||||
|
newFolderName: Nombre de la carpeta
|
||||||
|
failedToCreateFolder: No se pudo crear la carpeta.
|
||||||
|
failedToOpenShare: No se pudo abrir el contenido compartido.
|
||||||
|
noHouses: No hay casas disponibles. Crea una casa primero.
|
||||||
|
|
||||||
recurrence:
|
recurrence:
|
||||||
title: Recurrencia
|
title: Recurrencia
|
||||||
presets: Preajustes
|
presets: Preajustes
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ class MessagesFr extends Messages {
|
|||||||
ChecklistsMessagesFr get checklists => ChecklistsMessagesFr(this);
|
ChecklistsMessagesFr get checklists => ChecklistsMessagesFr(this);
|
||||||
NotesWallMessagesFr get notesWall => NotesWallMessagesFr(this);
|
NotesWallMessagesFr get notesWall => NotesWallMessagesFr(this);
|
||||||
PhotoBoardMessagesFr get photoBoard => PhotoBoardMessagesFr(this);
|
PhotoBoardMessagesFr get photoBoard => PhotoBoardMessagesFr(this);
|
||||||
|
ShareMessagesFr get share => ShareMessagesFr(this);
|
||||||
RecurrenceMessagesFr get recurrence => RecurrenceMessagesFr(this);
|
RecurrenceMessagesFr get recurrence => RecurrenceMessagesFr(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,6 +364,37 @@ class SettingsMessagesFr extends SettingsMessages {
|
|||||||
/// ```
|
/// ```
|
||||||
String get generalSection => """Général""";
|
String get generalSection => """Général""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Interface"
|
||||||
|
/// ```
|
||||||
|
String get interfaceSection => """Interface""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Toucher la ligne pour cocher les éléments"
|
||||||
|
/// ```
|
||||||
|
String get tapRowToComplete =>
|
||||||
|
"""Toucher la ligne pour cocher les éléments""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Quand désactivé, les éléments ne sont cochés qu'en touchant la case."
|
||||||
|
/// ```
|
||||||
|
String get tapRowToCompleteBody =>
|
||||||
|
"""Quand désactivé, les éléments ne sont cochés qu'en touchant la case.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Afficher un espacement entre les catégories dans les éléments de la liste"
|
||||||
|
/// ```
|
||||||
|
String get categorySpacing =>
|
||||||
|
"""Afficher un espacement entre les catégories dans les éléments de la liste""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Visible uniquement lors du tri par catégorie"
|
||||||
|
/// ```
|
||||||
|
String get categorySpacingBody =>
|
||||||
|
"""Visible uniquement lors du tri par catégorie""";
|
||||||
|
CategorySpacingNamesSettingsMessagesFr get categorySpacingNames =>
|
||||||
|
CategorySpacingNamesSettingsMessagesFr(this);
|
||||||
|
|
||||||
/// ```dart
|
/// ```dart
|
||||||
/// "Langue"
|
/// "Langue"
|
||||||
/// ```
|
/// ```
|
||||||
@@ -430,6 +462,27 @@ class SettingsMessagesFr extends SettingsMessages {
|
|||||||
"""La permission de notification a été refusée. Activez-la dans les réglages système.""";
|
"""La permission de notification a été refusée. Activez-la dans les réglages système.""";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CategorySpacingNamesSettingsMessagesFr
|
||||||
|
extends CategorySpacingNamesSettingsMessages {
|
||||||
|
final SettingsMessagesFr _parent;
|
||||||
|
const CategorySpacingNamesSettingsMessagesFr(this._parent) : super(_parent);
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Désactivé"
|
||||||
|
/// ```
|
||||||
|
String get disabled => """Désactivé""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Espace"
|
||||||
|
/// ```
|
||||||
|
String get space => """Espace""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Séparateur"
|
||||||
|
/// ```
|
||||||
|
String get divider => """Séparateur""";
|
||||||
|
}
|
||||||
|
|
||||||
class LanguageNamesSettingsMessagesFr extends LanguageNamesSettingsMessages {
|
class LanguageNamesSettingsMessagesFr extends LanguageNamesSettingsMessages {
|
||||||
final SettingsMessagesFr _parent;
|
final SettingsMessagesFr _parent;
|
||||||
const LanguageNamesSettingsMessagesFr(this._parent) : super(_parent);
|
const LanguageNamesSettingsMessagesFr(this._parent) : super(_parent);
|
||||||
@@ -661,6 +714,95 @@ class ChecklistsMessagesFr extends ChecklistsMessages {
|
|||||||
/// ```
|
/// ```
|
||||||
String get moveFailed => """Impossible de déplacer l'article.""";
|
String get moveFailed => """Impossible de déplacer l'article.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Article marqué comme fait"
|
||||||
|
/// ```
|
||||||
|
String get itemMarkedDone => """Article marqué comme fait""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Annuler"
|
||||||
|
/// ```
|
||||||
|
String get undo => """Annuler""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Afficher la corbeille"
|
||||||
|
/// ```
|
||||||
|
String get viewTrash => """Afficher la corbeille""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Quitter la corbeille"
|
||||||
|
/// ```
|
||||||
|
String get exitTrash => """Quitter la corbeille""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Corbeille"
|
||||||
|
/// ```
|
||||||
|
String get trashTitle => """Corbeille""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "La corbeille est vide."
|
||||||
|
/// ```
|
||||||
|
String get noTrashedItems => """La corbeille est vide.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Vider la corbeille"
|
||||||
|
/// ```
|
||||||
|
String get emptyTrash => """Vider la corbeille""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Vider la corbeille ?"
|
||||||
|
/// ```
|
||||||
|
String get emptyTrashConfirm => """Vider la corbeille ?""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Tous les articles de la corbeille seront supprimés définitivement. Cette action est irréversible."
|
||||||
|
/// ```
|
||||||
|
String get emptyTrashConfirmBody =>
|
||||||
|
"""Tous les articles de la corbeille seront supprimés définitivement. Cette action est irréversible.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Impossible de vider la corbeille."
|
||||||
|
/// ```
|
||||||
|
String get emptyTrashFailed => """Impossible de vider la corbeille.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Restaurer"
|
||||||
|
/// ```
|
||||||
|
String get restoreItem => """Restaurer""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Supprimer définitivement"
|
||||||
|
/// ```
|
||||||
|
String get permanentlyDeleteItem => """Supprimer définitivement""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Supprimer définitivement cet article ?"
|
||||||
|
/// ```
|
||||||
|
String get permanentlyDeleteConfirm =>
|
||||||
|
"""Supprimer définitivement cet article ?""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Cette action est irréversible."
|
||||||
|
/// ```
|
||||||
|
String get permanentlyDeleteConfirmBody =>
|
||||||
|
"""Cette action est irréversible.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Impossible de restaurer l'article."
|
||||||
|
/// ```
|
||||||
|
String get restoreFailed => """Impossible de restaurer l'article.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Impossible de supprimer l'article."
|
||||||
|
/// ```
|
||||||
|
String get permanentlyDeleteFailed =>
|
||||||
|
"""Impossible de supprimer l'article.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Article restauré"
|
||||||
|
/// ```
|
||||||
|
String get itemRestored => """Article restauré""";
|
||||||
|
|
||||||
/// ```dart
|
/// ```dart
|
||||||
/// "Nouvelle liste"
|
/// "Nouvelle liste"
|
||||||
/// ```
|
/// ```
|
||||||
@@ -1060,9 +1202,30 @@ class PhotoBoardMessagesFr extends PhotoBoardMessages {
|
|||||||
/// "$count"
|
/// "$count"
|
||||||
/// ```
|
/// ```
|
||||||
String photoCount(int count) => """$count""";
|
String photoCount(int count) => """$count""";
|
||||||
|
AddMenuPhotoBoardMessagesFr get addMenu => AddMenuPhotoBoardMessagesFr(this);
|
||||||
SortPhotoBoardMessagesFr get sort => SortPhotoBoardMessagesFr(this);
|
SortPhotoBoardMessagesFr get sort => SortPhotoBoardMessagesFr(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AddMenuPhotoBoardMessagesFr extends AddMenuPhotoBoardMessages {
|
||||||
|
final PhotoBoardMessagesFr _parent;
|
||||||
|
const AddMenuPhotoBoardMessagesFr(this._parent) : super(_parent);
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Téléverser des photos"
|
||||||
|
/// ```
|
||||||
|
String get upload => """Téléverser des photos""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Prendre une photo"
|
||||||
|
/// ```
|
||||||
|
String get camera => """Prendre une photo""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Nouveau dossier"
|
||||||
|
/// ```
|
||||||
|
String get newFolder => """Nouveau dossier""";
|
||||||
|
}
|
||||||
|
|
||||||
class SortPhotoBoardMessagesFr extends SortPhotoBoardMessages {
|
class SortPhotoBoardMessagesFr extends SortPhotoBoardMessages {
|
||||||
final PhotoBoardMessagesFr _parent;
|
final PhotoBoardMessagesFr _parent;
|
||||||
const SortPhotoBoardMessagesFr(this._parent) : super(_parent);
|
const SortPhotoBoardMessagesFr(this._parent) : super(_parent);
|
||||||
@@ -1098,6 +1261,57 @@ class SortPhotoBoardMessagesFr extends SortPhotoBoardMessages {
|
|||||||
String get custom => """Personnalisé""";
|
String get custom => """Personnalisé""";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ShareMessagesFr extends ShareMessages {
|
||||||
|
final MessagesFr _parent;
|
||||||
|
const ShareMessagesFr(this._parent) : super(_parent);
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Partager vers Pantry"
|
||||||
|
/// ```
|
||||||
|
String get title => """Partager vers Pantry""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Choisir une maison"
|
||||||
|
/// ```
|
||||||
|
String get chooseHouse => """Choisir une maison""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Téléverser vers"
|
||||||
|
/// ```
|
||||||
|
String get choosePhotoDestination => """Téléverser vers""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Tableau photos"
|
||||||
|
/// ```
|
||||||
|
String get photoBoardRoot => """Tableau photos""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Nouveau dossier"
|
||||||
|
/// ```
|
||||||
|
String get newFolder => """Nouveau dossier""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Nom du dossier"
|
||||||
|
/// ```
|
||||||
|
String get newFolderName => """Nom du dossier""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Impossible de créer le dossier."
|
||||||
|
/// ```
|
||||||
|
String get failedToCreateFolder => """Impossible de créer le dossier.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Impossible d'ouvrir le contenu partagé."
|
||||||
|
/// ```
|
||||||
|
String get failedToOpenShare => """Impossible d'ouvrir le contenu partagé.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "Aucune maison disponible. Créez d'abord une maison."
|
||||||
|
/// ```
|
||||||
|
String get noHouses =>
|
||||||
|
"""Aucune maison disponible. Créez d'abord une maison.""";
|
||||||
|
}
|
||||||
|
|
||||||
class RecurrenceMessagesFr extends RecurrenceMessages {
|
class RecurrenceMessagesFr extends RecurrenceMessages {
|
||||||
final MessagesFr _parent;
|
final MessagesFr _parent;
|
||||||
const RecurrenceMessagesFr(this._parent) : super(_parent);
|
const RecurrenceMessagesFr(this._parent) : super(_parent);
|
||||||
@@ -1401,6 +1615,18 @@ Veuillez terminer la connexion dans votre navigateur.""",
|
|||||||
"""about.feedback""": """Commentaires & problèmes""",
|
"""about.feedback""": """Commentaires & problèmes""",
|
||||||
"""settings.title""": """Réglages de l'app""",
|
"""settings.title""": """Réglages de l'app""",
|
||||||
"""settings.generalSection""": """Général""",
|
"""settings.generalSection""": """Général""",
|
||||||
|
"""settings.interfaceSection""": """Interface""",
|
||||||
|
"""settings.tapRowToComplete""":
|
||||||
|
"""Toucher la ligne pour cocher les éléments""",
|
||||||
|
"""settings.tapRowToCompleteBody""":
|
||||||
|
"""Quand désactivé, les éléments ne sont cochés qu'en touchant la case.""",
|
||||||
|
"""settings.categorySpacing""":
|
||||||
|
"""Afficher un espacement entre les catégories dans les éléments de la liste""",
|
||||||
|
"""settings.categorySpacingBody""":
|
||||||
|
"""Visible uniquement lors du tri par catégorie""",
|
||||||
|
"""settings.categorySpacingNames.disabled""": """Désactivé""",
|
||||||
|
"""settings.categorySpacingNames.space""": """Espace""",
|
||||||
|
"""settings.categorySpacingNames.divider""": """Séparateur""",
|
||||||
"""settings.language""": """Langue""",
|
"""settings.language""": """Langue""",
|
||||||
"""settings.languageNames.system""": """Par défaut du système""",
|
"""settings.languageNames.system""": """Par défaut du système""",
|
||||||
"""settings.languageNames.english""": """English""",
|
"""settings.languageNames.english""": """English""",
|
||||||
@@ -1455,6 +1681,27 @@ Veuillez terminer la connexion dans votre navigateur.""",
|
|||||||
"""checklists.removeItem""": """Supprimer l'article""",
|
"""checklists.removeItem""": """Supprimer l'article""",
|
||||||
"""checklists.moveItem""": """Déplacer vers une liste""",
|
"""checklists.moveItem""": """Déplacer vers une liste""",
|
||||||
"""checklists.moveFailed""": """Impossible de déplacer l'article.""",
|
"""checklists.moveFailed""": """Impossible de déplacer l'article.""",
|
||||||
|
"""checklists.itemMarkedDone""": """Article marqué comme fait""",
|
||||||
|
"""checklists.undo""": """Annuler""",
|
||||||
|
"""checklists.viewTrash""": """Afficher la corbeille""",
|
||||||
|
"""checklists.exitTrash""": """Quitter la corbeille""",
|
||||||
|
"""checklists.trashTitle""": """Corbeille""",
|
||||||
|
"""checklists.noTrashedItems""": """La corbeille est vide.""",
|
||||||
|
"""checklists.emptyTrash""": """Vider la corbeille""",
|
||||||
|
"""checklists.emptyTrashConfirm""": """Vider la corbeille ?""",
|
||||||
|
"""checklists.emptyTrashConfirmBody""":
|
||||||
|
"""Tous les articles de la corbeille seront supprimés définitivement. Cette action est irréversible.""",
|
||||||
|
"""checklists.emptyTrashFailed""": """Impossible de vider la corbeille.""",
|
||||||
|
"""checklists.restoreItem""": """Restaurer""",
|
||||||
|
"""checklists.permanentlyDeleteItem""": """Supprimer définitivement""",
|
||||||
|
"""checklists.permanentlyDeleteConfirm""":
|
||||||
|
"""Supprimer définitivement cet article ?""",
|
||||||
|
"""checklists.permanentlyDeleteConfirmBody""":
|
||||||
|
"""Cette action est irréversible.""",
|
||||||
|
"""checklists.restoreFailed""": """Impossible de restaurer l'article.""",
|
||||||
|
"""checklists.permanentlyDeleteFailed""":
|
||||||
|
"""Impossible de supprimer l'article.""",
|
||||||
|
"""checklists.itemRestored""": """Article restauré""",
|
||||||
"""checklists.createList""": """Nouvelle liste""",
|
"""checklists.createList""": """Nouvelle liste""",
|
||||||
"""checklists.listName""": """Nom de la liste""",
|
"""checklists.listName""": """Nom de la liste""",
|
||||||
"""checklists.listDescription""": """Description (facultatif)""",
|
"""checklists.listDescription""": """Description (facultatif)""",
|
||||||
@@ -1531,12 +1778,25 @@ Veuillez terminer la connexion dans votre navigateur.""",
|
|||||||
"""photoBoard.folderName""": """Nom du dossier""",
|
"""photoBoard.folderName""": """Nom du dossier""",
|
||||||
"""photoBoard.renameFolder""": """Renommer le dossier""",
|
"""photoBoard.renameFolder""": """Renommer le dossier""",
|
||||||
"""photoBoard.caption""": """Légende""",
|
"""photoBoard.caption""": """Légende""",
|
||||||
|
"""photoBoard.addMenu.upload""": """Téléverser des photos""",
|
||||||
|
"""photoBoard.addMenu.camera""": """Prendre une photo""",
|
||||||
|
"""photoBoard.addMenu.newFolder""": """Nouveau dossier""",
|
||||||
"""photoBoard.sort.foldersFirst""": """Dossiers en premier""",
|
"""photoBoard.sort.foldersFirst""": """Dossiers en premier""",
|
||||||
"""photoBoard.sort.newestFirst""": """Plus récents""",
|
"""photoBoard.sort.newestFirst""": """Plus récents""",
|
||||||
"""photoBoard.sort.oldestFirst""": """Plus anciens""",
|
"""photoBoard.sort.oldestFirst""": """Plus anciens""",
|
||||||
"""photoBoard.sort.captionAZ""": """Légende A–Z""",
|
"""photoBoard.sort.captionAZ""": """Légende A–Z""",
|
||||||
"""photoBoard.sort.captionZA""": """Légende Z–A""",
|
"""photoBoard.sort.captionZA""": """Légende Z–A""",
|
||||||
"""photoBoard.sort.custom""": """Personnalisé""",
|
"""photoBoard.sort.custom""": """Personnalisé""",
|
||||||
|
"""share.title""": """Partager vers Pantry""",
|
||||||
|
"""share.chooseHouse""": """Choisir une maison""",
|
||||||
|
"""share.choosePhotoDestination""": """Téléverser vers""",
|
||||||
|
"""share.photoBoardRoot""": """Tableau photos""",
|
||||||
|
"""share.newFolder""": """Nouveau dossier""",
|
||||||
|
"""share.newFolderName""": """Nom du dossier""",
|
||||||
|
"""share.failedToCreateFolder""": """Impossible de créer le dossier.""",
|
||||||
|
"""share.failedToOpenShare""": """Impossible d'ouvrir le contenu partagé.""",
|
||||||
|
"""share.noHouses""":
|
||||||
|
"""Aucune maison disponible. Créez d'abord une maison.""",
|
||||||
"""recurrence.title""": """Récurrence""",
|
"""recurrence.title""": """Récurrence""",
|
||||||
"""recurrence.presets""": """Préréglages""",
|
"""recurrence.presets""": """Préréglages""",
|
||||||
"""recurrence.daily""": """Quotidien""",
|
"""recurrence.daily""": """Quotidien""",
|
||||||
|
|||||||
@@ -59,6 +59,15 @@ about:
|
|||||||
settings:
|
settings:
|
||||||
title: "Réglages de l'app"
|
title: "Réglages de l'app"
|
||||||
generalSection: "Général"
|
generalSection: "Général"
|
||||||
|
interfaceSection: Interface
|
||||||
|
tapRowToComplete: Toucher la ligne pour cocher les éléments
|
||||||
|
tapRowToCompleteBody: "Quand désactivé, les éléments ne sont cochés qu'en touchant la case."
|
||||||
|
categorySpacing: Afficher un espacement entre les catégories dans les éléments de la liste
|
||||||
|
categorySpacingBody: Visible uniquement lors du tri par catégorie
|
||||||
|
categorySpacingNames:
|
||||||
|
disabled: "Désactivé"
|
||||||
|
space: Espace
|
||||||
|
divider: "Séparateur"
|
||||||
language: Langue
|
language: Langue
|
||||||
languageNames:
|
languageNames:
|
||||||
system: "Par défaut du système"
|
system: "Par défaut du système"
|
||||||
@@ -120,6 +129,23 @@ checklists:
|
|||||||
removeItem: Supprimer l'article
|
removeItem: Supprimer l'article
|
||||||
moveItem: "Déplacer vers une liste"
|
moveItem: "Déplacer vers une liste"
|
||||||
moveFailed: "Impossible de déplacer l'article."
|
moveFailed: "Impossible de déplacer l'article."
|
||||||
|
itemMarkedDone: "Article marqué comme fait"
|
||||||
|
undo: Annuler
|
||||||
|
viewTrash: "Afficher la corbeille"
|
||||||
|
exitTrash: "Quitter la corbeille"
|
||||||
|
trashTitle: Corbeille
|
||||||
|
noTrashedItems: "La corbeille est vide."
|
||||||
|
emptyTrash: "Vider la corbeille"
|
||||||
|
emptyTrashConfirm: "Vider la corbeille ?"
|
||||||
|
emptyTrashConfirmBody: "Tous les articles de la corbeille seront supprimés définitivement. Cette action est irréversible."
|
||||||
|
emptyTrashFailed: "Impossible de vider la corbeille."
|
||||||
|
restoreItem: Restaurer
|
||||||
|
permanentlyDeleteItem: "Supprimer définitivement"
|
||||||
|
permanentlyDeleteConfirm: "Supprimer définitivement cet article ?"
|
||||||
|
permanentlyDeleteConfirmBody: "Cette action est irréversible."
|
||||||
|
restoreFailed: "Impossible de restaurer l'article."
|
||||||
|
permanentlyDeleteFailed: "Impossible de supprimer l'article."
|
||||||
|
itemRestored: "Article restauré"
|
||||||
createList: Nouvelle liste
|
createList: Nouvelle liste
|
||||||
listName: Nom de la liste
|
listName: Nom de la liste
|
||||||
listDescription: Description (facultatif)
|
listDescription: Description (facultatif)
|
||||||
@@ -200,6 +226,10 @@ photoBoard:
|
|||||||
renameFolder: Renommer le dossier
|
renameFolder: Renommer le dossier
|
||||||
caption: "Légende"
|
caption: "Légende"
|
||||||
photoCount(int count): "$count"
|
photoCount(int count): "$count"
|
||||||
|
addMenu:
|
||||||
|
upload: Téléverser des photos
|
||||||
|
camera: Prendre une photo
|
||||||
|
newFolder: Nouveau dossier
|
||||||
sort:
|
sort:
|
||||||
foldersFirst: Dossiers en premier
|
foldersFirst: Dossiers en premier
|
||||||
newestFirst: "Plus récents"
|
newestFirst: "Plus récents"
|
||||||
@@ -208,6 +238,17 @@ photoBoard:
|
|||||||
captionZA: "Légende Z–A"
|
captionZA: "Légende Z–A"
|
||||||
custom: "Personnalisé"
|
custom: "Personnalisé"
|
||||||
|
|
||||||
|
share:
|
||||||
|
title: Partager vers Pantry
|
||||||
|
chooseHouse: Choisir une maison
|
||||||
|
choosePhotoDestination: Téléverser vers
|
||||||
|
photoBoardRoot: Tableau photos
|
||||||
|
newFolder: Nouveau dossier
|
||||||
|
newFolderName: Nom du dossier
|
||||||
|
failedToCreateFolder: "Impossible de créer le dossier."
|
||||||
|
failedToOpenShare: "Impossible d'ouvrir le contenu partagé."
|
||||||
|
noHouses: "Aucune maison disponible. Créez d'abord une maison."
|
||||||
|
|
||||||
recurrence:
|
recurrence:
|
||||||
title: "Récurrence"
|
title: "Récurrence"
|
||||||
presets: "Préréglages"
|
presets: "Préréglages"
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ class MessagesHe extends Messages {
|
|||||||
ChecklistsMessagesHe get checklists => ChecklistsMessagesHe(this);
|
ChecklistsMessagesHe get checklists => ChecklistsMessagesHe(this);
|
||||||
NotesWallMessagesHe get notesWall => NotesWallMessagesHe(this);
|
NotesWallMessagesHe get notesWall => NotesWallMessagesHe(this);
|
||||||
PhotoBoardMessagesHe get photoBoard => PhotoBoardMessagesHe(this);
|
PhotoBoardMessagesHe get photoBoard => PhotoBoardMessagesHe(this);
|
||||||
|
ShareMessagesHe get share => ShareMessagesHe(this);
|
||||||
RecurrenceMessagesHe get recurrence => RecurrenceMessagesHe(this);
|
RecurrenceMessagesHe get recurrence => RecurrenceMessagesHe(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,6 +362,34 @@ class SettingsMessagesHe extends SettingsMessages {
|
|||||||
/// ```
|
/// ```
|
||||||
String get generalSection => """כללי""";
|
String get generalSection => """כללי""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "ממשק"
|
||||||
|
/// ```
|
||||||
|
String get interfaceSection => """ממשק""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "השלם פריטים בלחיצה על השורה"
|
||||||
|
/// ```
|
||||||
|
String get tapRowToComplete => """השלם פריטים בלחיצה על השורה""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "כאשר כבוי, פריטים מסומנים כהושלמו רק בלחיצה על תיבת הסימון."
|
||||||
|
/// ```
|
||||||
|
String get tapRowToCompleteBody =>
|
||||||
|
"""כאשר כבוי, פריטים מסומנים כהושלמו רק בלחיצה על תיבת הסימון.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "הצג רווח בין קטגוריות בפריטי הרשימה"
|
||||||
|
/// ```
|
||||||
|
String get categorySpacing => """הצג רווח בין קטגוריות בפריטי הרשימה""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "מוצג רק בעת מיון לפי קטגוריה"
|
||||||
|
/// ```
|
||||||
|
String get categorySpacingBody => """מוצג רק בעת מיון לפי קטגוריה""";
|
||||||
|
CategorySpacingNamesSettingsMessagesHe get categorySpacingNames =>
|
||||||
|
CategorySpacingNamesSettingsMessagesHe(this);
|
||||||
|
|
||||||
/// ```dart
|
/// ```dart
|
||||||
/// "שפה"
|
/// "שפה"
|
||||||
/// ```
|
/// ```
|
||||||
@@ -428,6 +457,27 @@ class SettingsMessagesHe extends SettingsMessages {
|
|||||||
"""הרשאת ההתראות נדחתה. הפעל אותה בהגדרות המערכת.""";
|
"""הרשאת ההתראות נדחתה. הפעל אותה בהגדרות המערכת.""";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CategorySpacingNamesSettingsMessagesHe
|
||||||
|
extends CategorySpacingNamesSettingsMessages {
|
||||||
|
final SettingsMessagesHe _parent;
|
||||||
|
const CategorySpacingNamesSettingsMessagesHe(this._parent) : super(_parent);
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "מושבת"
|
||||||
|
/// ```
|
||||||
|
String get disabled => """מושבת""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "רווח"
|
||||||
|
/// ```
|
||||||
|
String get space => """רווח""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "קו מפריד"
|
||||||
|
/// ```
|
||||||
|
String get divider => """קו מפריד""";
|
||||||
|
}
|
||||||
|
|
||||||
class LanguageNamesSettingsMessagesHe extends LanguageNamesSettingsMessages {
|
class LanguageNamesSettingsMessagesHe extends LanguageNamesSettingsMessages {
|
||||||
final SettingsMessagesHe _parent;
|
final SettingsMessagesHe _parent;
|
||||||
const LanguageNamesSettingsMessagesHe(this._parent) : super(_parent);
|
const LanguageNamesSettingsMessagesHe(this._parent) : super(_parent);
|
||||||
@@ -658,6 +708,92 @@ class ChecklistsMessagesHe extends ChecklistsMessages {
|
|||||||
/// ```
|
/// ```
|
||||||
String get moveFailed => """העברת הפריט נכשלה.""";
|
String get moveFailed => """העברת הפריט נכשלה.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "הפריט סומן כהושלם"
|
||||||
|
/// ```
|
||||||
|
String get itemMarkedDone => """הפריט סומן כהושלם""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "בטל"
|
||||||
|
/// ```
|
||||||
|
String get undo => """בטל""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "הצג אשפה"
|
||||||
|
/// ```
|
||||||
|
String get viewTrash => """הצג אשפה""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "צא מהאשפה"
|
||||||
|
/// ```
|
||||||
|
String get exitTrash => """צא מהאשפה""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "אשפה"
|
||||||
|
/// ```
|
||||||
|
String get trashTitle => """אשפה""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "האשפה ריקה."
|
||||||
|
/// ```
|
||||||
|
String get noTrashedItems => """האשפה ריקה.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "רוקן אשפה"
|
||||||
|
/// ```
|
||||||
|
String get emptyTrash => """רוקן אשפה""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "לרוקן את האשפה?"
|
||||||
|
/// ```
|
||||||
|
String get emptyTrashConfirm => """לרוקן את האשפה?""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "כל הפריטים באשפה יימחקו לצמיתות. לא ניתן לבטל פעולה זו."
|
||||||
|
/// ```
|
||||||
|
String get emptyTrashConfirmBody =>
|
||||||
|
"""כל הפריטים באשפה יימחקו לצמיתות. לא ניתן לבטל פעולה זו.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "ריקון האשפה נכשל."
|
||||||
|
/// ```
|
||||||
|
String get emptyTrashFailed => """ריקון האשפה נכשל.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "שחזר"
|
||||||
|
/// ```
|
||||||
|
String get restoreItem => """שחזר""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "מחק לצמיתות"
|
||||||
|
/// ```
|
||||||
|
String get permanentlyDeleteItem => """מחק לצמיתות""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "למחוק את הפריט לצמיתות?"
|
||||||
|
/// ```
|
||||||
|
String get permanentlyDeleteConfirm => """למחוק את הפריט לצמיתות?""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "לא ניתן לבטל פעולה זו."
|
||||||
|
/// ```
|
||||||
|
String get permanentlyDeleteConfirmBody => """לא ניתן לבטל פעולה זו.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "שחזור הפריט נכשל."
|
||||||
|
/// ```
|
||||||
|
String get restoreFailed => """שחזור הפריט נכשל.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "מחיקת הפריט נכשלה."
|
||||||
|
/// ```
|
||||||
|
String get permanentlyDeleteFailed => """מחיקת הפריט נכשלה.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "הפריט שוחזר"
|
||||||
|
/// ```
|
||||||
|
String get itemRestored => """הפריט שוחזר""";
|
||||||
|
|
||||||
/// ```dart
|
/// ```dart
|
||||||
/// "רשימה חדשה"
|
/// "רשימה חדשה"
|
||||||
/// ```
|
/// ```
|
||||||
@@ -1055,9 +1191,30 @@ class PhotoBoardMessagesHe extends PhotoBoardMessages {
|
|||||||
/// "$count"
|
/// "$count"
|
||||||
/// ```
|
/// ```
|
||||||
String photoCount(int count) => """$count""";
|
String photoCount(int count) => """$count""";
|
||||||
|
AddMenuPhotoBoardMessagesHe get addMenu => AddMenuPhotoBoardMessagesHe(this);
|
||||||
SortPhotoBoardMessagesHe get sort => SortPhotoBoardMessagesHe(this);
|
SortPhotoBoardMessagesHe get sort => SortPhotoBoardMessagesHe(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AddMenuPhotoBoardMessagesHe extends AddMenuPhotoBoardMessages {
|
||||||
|
final PhotoBoardMessagesHe _parent;
|
||||||
|
const AddMenuPhotoBoardMessagesHe(this._parent) : super(_parent);
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "העלאת תמונות"
|
||||||
|
/// ```
|
||||||
|
String get upload => """העלאת תמונות""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "צילום תמונה"
|
||||||
|
/// ```
|
||||||
|
String get camera => """צילום תמונה""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "תיקייה חדשה"
|
||||||
|
/// ```
|
||||||
|
String get newFolder => """תיקייה חדשה""";
|
||||||
|
}
|
||||||
|
|
||||||
class SortPhotoBoardMessagesHe extends SortPhotoBoardMessages {
|
class SortPhotoBoardMessagesHe extends SortPhotoBoardMessages {
|
||||||
final PhotoBoardMessagesHe _parent;
|
final PhotoBoardMessagesHe _parent;
|
||||||
const SortPhotoBoardMessagesHe(this._parent) : super(_parent);
|
const SortPhotoBoardMessagesHe(this._parent) : super(_parent);
|
||||||
@@ -1093,6 +1250,56 @@ class SortPhotoBoardMessagesHe extends SortPhotoBoardMessages {
|
|||||||
String get custom => """מותאם אישית""";
|
String get custom => """מותאם אישית""";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ShareMessagesHe extends ShareMessages {
|
||||||
|
final MessagesHe _parent;
|
||||||
|
const ShareMessagesHe(this._parent) : super(_parent);
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "שיתוף ל-Pantry"
|
||||||
|
/// ```
|
||||||
|
String get title => """שיתוף ל-Pantry""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "בחר בית"
|
||||||
|
/// ```
|
||||||
|
String get chooseHouse => """בחר בית""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "העלה אל"
|
||||||
|
/// ```
|
||||||
|
String get choosePhotoDestination => """העלה אל""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "לוח התמונות"
|
||||||
|
/// ```
|
||||||
|
String get photoBoardRoot => """לוח התמונות""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "תיקייה חדשה"
|
||||||
|
/// ```
|
||||||
|
String get newFolder => """תיקייה חדשה""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "שם התיקייה"
|
||||||
|
/// ```
|
||||||
|
String get newFolderName => """שם התיקייה""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "יצירת התיקייה נכשלה."
|
||||||
|
/// ```
|
||||||
|
String get failedToCreateFolder => """יצירת התיקייה נכשלה.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "לא ניתן לפתוח את התוכן ששותף."
|
||||||
|
/// ```
|
||||||
|
String get failedToOpenShare => """לא ניתן לפתוח את התוכן ששותף.""";
|
||||||
|
|
||||||
|
/// ```dart
|
||||||
|
/// "אין בתים זמינים. צור תחילה בית."
|
||||||
|
/// ```
|
||||||
|
String get noHouses => """אין בתים זמינים. צור תחילה בית.""";
|
||||||
|
}
|
||||||
|
|
||||||
class RecurrenceMessagesHe extends RecurrenceMessages {
|
class RecurrenceMessagesHe extends RecurrenceMessages {
|
||||||
final MessagesHe _parent;
|
final MessagesHe _parent;
|
||||||
const RecurrenceMessagesHe(this._parent) : super(_parent);
|
const RecurrenceMessagesHe(this._parent) : super(_parent);
|
||||||
@@ -1391,6 +1598,15 @@ Map<String, String> get messagesHeMap => {
|
|||||||
"""about.feedback""": """משוב ובעיות""",
|
"""about.feedback""": """משוב ובעיות""",
|
||||||
"""settings.title""": """הגדרות האפליקציה""",
|
"""settings.title""": """הגדרות האפליקציה""",
|
||||||
"""settings.generalSection""": """כללי""",
|
"""settings.generalSection""": """כללי""",
|
||||||
|
"""settings.interfaceSection""": """ממשק""",
|
||||||
|
"""settings.tapRowToComplete""": """השלם פריטים בלחיצה על השורה""",
|
||||||
|
"""settings.tapRowToCompleteBody""":
|
||||||
|
"""כאשר כבוי, פריטים מסומנים כהושלמו רק בלחיצה על תיבת הסימון.""",
|
||||||
|
"""settings.categorySpacing""": """הצג רווח בין קטגוריות בפריטי הרשימה""",
|
||||||
|
"""settings.categorySpacingBody""": """מוצג רק בעת מיון לפי קטגוריה""",
|
||||||
|
"""settings.categorySpacingNames.disabled""": """מושבת""",
|
||||||
|
"""settings.categorySpacingNames.space""": """רווח""",
|
||||||
|
"""settings.categorySpacingNames.divider""": """קו מפריד""",
|
||||||
"""settings.language""": """שפה""",
|
"""settings.language""": """שפה""",
|
||||||
"""settings.languageNames.system""": """ברירת מחדל (שפת המערכת)""",
|
"""settings.languageNames.system""": """ברירת מחדל (שפת המערכת)""",
|
||||||
"""settings.languageNames.english""": """English""",
|
"""settings.languageNames.english""": """English""",
|
||||||
@@ -1443,6 +1659,24 @@ Map<String, String> get messagesHeMap => {
|
|||||||
"""checklists.removeItem""": """הסר פריט""",
|
"""checklists.removeItem""": """הסר פריט""",
|
||||||
"""checklists.moveItem""": """העבר לרשימה""",
|
"""checklists.moveItem""": """העבר לרשימה""",
|
||||||
"""checklists.moveFailed""": """העברת הפריט נכשלה.""",
|
"""checklists.moveFailed""": """העברת הפריט נכשלה.""",
|
||||||
|
"""checklists.itemMarkedDone""": """הפריט סומן כהושלם""",
|
||||||
|
"""checklists.undo""": """בטל""",
|
||||||
|
"""checklists.viewTrash""": """הצג אשפה""",
|
||||||
|
"""checklists.exitTrash""": """צא מהאשפה""",
|
||||||
|
"""checklists.trashTitle""": """אשפה""",
|
||||||
|
"""checklists.noTrashedItems""": """האשפה ריקה.""",
|
||||||
|
"""checklists.emptyTrash""": """רוקן אשפה""",
|
||||||
|
"""checklists.emptyTrashConfirm""": """לרוקן את האשפה?""",
|
||||||
|
"""checklists.emptyTrashConfirmBody""":
|
||||||
|
"""כל הפריטים באשפה יימחקו לצמיתות. לא ניתן לבטל פעולה זו.""",
|
||||||
|
"""checklists.emptyTrashFailed""": """ריקון האשפה נכשל.""",
|
||||||
|
"""checklists.restoreItem""": """שחזר""",
|
||||||
|
"""checklists.permanentlyDeleteItem""": """מחק לצמיתות""",
|
||||||
|
"""checklists.permanentlyDeleteConfirm""": """למחוק את הפריט לצמיתות?""",
|
||||||
|
"""checklists.permanentlyDeleteConfirmBody""": """לא ניתן לבטל פעולה זו.""",
|
||||||
|
"""checklists.restoreFailed""": """שחזור הפריט נכשל.""",
|
||||||
|
"""checklists.permanentlyDeleteFailed""": """מחיקת הפריט נכשלה.""",
|
||||||
|
"""checklists.itemRestored""": """הפריט שוחזר""",
|
||||||
"""checklists.createList""": """רשימה חדשה""",
|
"""checklists.createList""": """רשימה חדשה""",
|
||||||
"""checklists.listName""": """שם הרשימה""",
|
"""checklists.listName""": """שם הרשימה""",
|
||||||
"""checklists.listDescription""": """תיאור (אופציונלי)""",
|
"""checklists.listDescription""": """תיאור (אופציונלי)""",
|
||||||
@@ -1513,12 +1747,24 @@ Map<String, String> get messagesHeMap => {
|
|||||||
"""photoBoard.folderName""": """שם התיקייה""",
|
"""photoBoard.folderName""": """שם התיקייה""",
|
||||||
"""photoBoard.renameFolder""": """שנה שם תיקייה""",
|
"""photoBoard.renameFolder""": """שנה שם תיקייה""",
|
||||||
"""photoBoard.caption""": """כיתוב""",
|
"""photoBoard.caption""": """כיתוב""",
|
||||||
|
"""photoBoard.addMenu.upload""": """העלאת תמונות""",
|
||||||
|
"""photoBoard.addMenu.camera""": """צילום תמונה""",
|
||||||
|
"""photoBoard.addMenu.newFolder""": """תיקייה חדשה""",
|
||||||
"""photoBoard.sort.foldersFirst""": """תיקיות קודם""",
|
"""photoBoard.sort.foldersFirst""": """תיקיות קודם""",
|
||||||
"""photoBoard.sort.newestFirst""": """החדש ביותר""",
|
"""photoBoard.sort.newestFirst""": """החדש ביותר""",
|
||||||
"""photoBoard.sort.oldestFirst""": """הישן ביותר""",
|
"""photoBoard.sort.oldestFirst""": """הישן ביותר""",
|
||||||
"""photoBoard.sort.captionAZ""": """כיתוב א–ת""",
|
"""photoBoard.sort.captionAZ""": """כיתוב א–ת""",
|
||||||
"""photoBoard.sort.captionZA""": """כיתוב ת–א""",
|
"""photoBoard.sort.captionZA""": """כיתוב ת–א""",
|
||||||
"""photoBoard.sort.custom""": """מותאם אישית""",
|
"""photoBoard.sort.custom""": """מותאם אישית""",
|
||||||
|
"""share.title""": """שיתוף ל-Pantry""",
|
||||||
|
"""share.chooseHouse""": """בחר בית""",
|
||||||
|
"""share.choosePhotoDestination""": """העלה אל""",
|
||||||
|
"""share.photoBoardRoot""": """לוח התמונות""",
|
||||||
|
"""share.newFolder""": """תיקייה חדשה""",
|
||||||
|
"""share.newFolderName""": """שם התיקייה""",
|
||||||
|
"""share.failedToCreateFolder""": """יצירת התיקייה נכשלה.""",
|
||||||
|
"""share.failedToOpenShare""": """לא ניתן לפתוח את התוכן ששותף.""",
|
||||||
|
"""share.noHouses""": """אין בתים זמינים. צור תחילה בית.""",
|
||||||
"""recurrence.title""": """חזרה""",
|
"""recurrence.title""": """חזרה""",
|
||||||
"""recurrence.presets""": """הגדרות מוכנות""",
|
"""recurrence.presets""": """הגדרות מוכנות""",
|
||||||
"""recurrence.daily""": """יומי""",
|
"""recurrence.daily""": """יומי""",
|
||||||
|
|||||||
@@ -59,6 +59,15 @@ about:
|
|||||||
settings:
|
settings:
|
||||||
title: הגדרות האפליקציה
|
title: הגדרות האפליקציה
|
||||||
generalSection: כללי
|
generalSection: כללי
|
||||||
|
interfaceSection: ממשק
|
||||||
|
tapRowToComplete: השלם פריטים בלחיצה על השורה
|
||||||
|
tapRowToCompleteBody: כאשר כבוי, פריטים מסומנים כהושלמו רק בלחיצה על תיבת הסימון.
|
||||||
|
categorySpacing: הצג רווח בין קטגוריות בפריטי הרשימה
|
||||||
|
categorySpacingBody: מוצג רק בעת מיון לפי קטגוריה
|
||||||
|
categorySpacingNames:
|
||||||
|
disabled: מושבת
|
||||||
|
space: רווח
|
||||||
|
divider: קו מפריד
|
||||||
language: שפה
|
language: שפה
|
||||||
languageNames:
|
languageNames:
|
||||||
system: ברירת מחדל (שפת המערכת)
|
system: ברירת מחדל (שפת המערכת)
|
||||||
@@ -120,6 +129,23 @@ checklists:
|
|||||||
removeItem: הסר פריט
|
removeItem: הסר פריט
|
||||||
moveItem: העבר לרשימה
|
moveItem: העבר לרשימה
|
||||||
moveFailed: העברת הפריט נכשלה.
|
moveFailed: העברת הפריט נכשלה.
|
||||||
|
itemMarkedDone: הפריט סומן כהושלם
|
||||||
|
undo: בטל
|
||||||
|
viewTrash: הצג אשפה
|
||||||
|
exitTrash: צא מהאשפה
|
||||||
|
trashTitle: אשפה
|
||||||
|
noTrashedItems: האשפה ריקה.
|
||||||
|
emptyTrash: רוקן אשפה
|
||||||
|
emptyTrashConfirm: לרוקן את האשפה?
|
||||||
|
emptyTrashConfirmBody: כל הפריטים באשפה יימחקו לצמיתות. לא ניתן לבטל פעולה זו.
|
||||||
|
emptyTrashFailed: ריקון האשפה נכשל.
|
||||||
|
restoreItem: שחזר
|
||||||
|
permanentlyDeleteItem: מחק לצמיתות
|
||||||
|
permanentlyDeleteConfirm: למחוק את הפריט לצמיתות?
|
||||||
|
permanentlyDeleteConfirmBody: לא ניתן לבטל פעולה זו.
|
||||||
|
restoreFailed: שחזור הפריט נכשל.
|
||||||
|
permanentlyDeleteFailed: מחיקת הפריט נכשלה.
|
||||||
|
itemRestored: הפריט שוחזר
|
||||||
createList: רשימה חדשה
|
createList: רשימה חדשה
|
||||||
listName: שם הרשימה
|
listName: שם הרשימה
|
||||||
listDescription: תיאור (אופציונלי)
|
listDescription: תיאור (אופציונלי)
|
||||||
@@ -200,6 +226,10 @@ photoBoard:
|
|||||||
renameFolder: שנה שם תיקייה
|
renameFolder: שנה שם תיקייה
|
||||||
caption: כיתוב
|
caption: כיתוב
|
||||||
photoCount(int count): "$count"
|
photoCount(int count): "$count"
|
||||||
|
addMenu:
|
||||||
|
upload: העלאת תמונות
|
||||||
|
camera: צילום תמונה
|
||||||
|
newFolder: תיקייה חדשה
|
||||||
sort:
|
sort:
|
||||||
foldersFirst: תיקיות קודם
|
foldersFirst: תיקיות קודם
|
||||||
newestFirst: החדש ביותר
|
newestFirst: החדש ביותר
|
||||||
@@ -208,6 +238,17 @@ photoBoard:
|
|||||||
captionZA: "כיתוב ת–א"
|
captionZA: "כיתוב ת–א"
|
||||||
custom: מותאם אישית
|
custom: מותאם אישית
|
||||||
|
|
||||||
|
share:
|
||||||
|
title: שיתוף ל-Pantry
|
||||||
|
chooseHouse: בחר בית
|
||||||
|
choosePhotoDestination: העלה אל
|
||||||
|
photoBoardRoot: לוח התמונות
|
||||||
|
newFolder: תיקייה חדשה
|
||||||
|
newFolderName: שם התיקייה
|
||||||
|
failedToCreateFolder: יצירת התיקייה נכשלה.
|
||||||
|
failedToOpenShare: לא ניתן לפתוח את התוכן ששותף.
|
||||||
|
noHouses: אין בתים זמינים. צור תחילה בית.
|
||||||
|
|
||||||
recurrence:
|
recurrence:
|
||||||
title: חזרה
|
title: חזרה
|
||||||
presets: הגדרות מוכנות
|
presets: הגדרות מוכנות
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ class ListItem {
|
|||||||
final int sortOrder;
|
final int sortOrder;
|
||||||
final int createdAt;
|
final int createdAt;
|
||||||
final int updatedAt;
|
final int updatedAt;
|
||||||
|
final int? deletedAt;
|
||||||
|
|
||||||
const ListItem({
|
const ListItem({
|
||||||
required this.id,
|
required this.id,
|
||||||
@@ -81,6 +82,7 @@ class ListItem {
|
|||||||
required this.sortOrder,
|
required this.sortOrder,
|
||||||
required this.createdAt,
|
required this.createdAt,
|
||||||
required this.updatedAt,
|
required this.updatedAt,
|
||||||
|
this.deletedAt,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory ListItem.fromJson(Map<String, dynamic> json) => ListItem(
|
factory ListItem.fromJson(Map<String, dynamic> json) => ListItem(
|
||||||
@@ -102,6 +104,7 @@ class ListItem {
|
|||||||
sortOrder: json['sortOrder'] as int,
|
sortOrder: json['sortOrder'] as int,
|
||||||
createdAt: json['createdAt'] as int,
|
createdAt: json['createdAt'] as int,
|
||||||
updatedAt: json['updatedAt'] as int,
|
updatedAt: json['updatedAt'] as int,
|
||||||
|
deletedAt: json['deletedAt'] as int?,
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
@@ -123,6 +126,7 @@ class ListItem {
|
|||||||
'sortOrder': sortOrder,
|
'sortOrder': sortOrder,
|
||||||
'createdAt': createdAt,
|
'createdAt': createdAt,
|
||||||
'updatedAt': updatedAt,
|
'updatedAt': updatedAt,
|
||||||
|
'deletedAt': deletedAt,
|
||||||
};
|
};
|
||||||
|
|
||||||
ListItem copyWith({bool? done, int? doneAt, String? doneBy}) => ListItem(
|
ListItem copyWith({bool? done, int? doneAt, String? doneBy}) => ListItem(
|
||||||
@@ -144,5 +148,6 @@ class ListItem {
|
|||||||
sortOrder: sortOrder,
|
sortOrder: sortOrder,
|
||||||
createdAt: createdAt,
|
createdAt: createdAt,
|
||||||
updatedAt: updatedAt,
|
updatedAt: updatedAt,
|
||||||
|
deletedAt: deletedAt,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,8 +34,11 @@ class ApiClient {
|
|||||||
|
|
||||||
Uri _uri(String path, [Map<String, String>? queryParameters]) {
|
Uri _uri(String path, [Map<String, String>? queryParameters]) {
|
||||||
final base = Uri.parse(_credentials.serverUrl);
|
final base = Uri.parse(_credentials.serverUrl);
|
||||||
|
final prefix = base.path.endsWith('/')
|
||||||
|
? base.path.substring(0, base.path.length - 1)
|
||||||
|
: base.path;
|
||||||
return base.replace(
|
return base.replace(
|
||||||
path: '$basePath$path',
|
path: '$prefix$basePath$path',
|
||||||
queryParameters: queryParameters,
|
queryParameters: queryParameters,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:io' show Platform;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
import 'package:pantry/models/notification.dart';
|
import 'package:pantry/models/notification.dart';
|
||||||
@@ -80,9 +82,15 @@ Future<void> markCurrentNotificationsAsSeen(List<int> ids) async {
|
|||||||
await storage.write(key: _seenIdsKey, value: ids.join(','));
|
await storage.write(key: _seenIdsKey, value: ids.join(','));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// workmanager only supports Android and iOS; other platforms throw
|
||||||
|
/// UnimplementedError. Gate every call so callers don't need to.
|
||||||
|
bool get _workmanagerSupported =>
|
||||||
|
!kIsWeb && (Platform.isAndroid || Platform.isIOS);
|
||||||
|
|
||||||
/// Schedule the periodic background poll using the user's configured
|
/// Schedule the periodic background poll using the user's configured
|
||||||
/// interval from [PrefsService] (minimum 15 minutes on Android).
|
/// interval from [PrefsService] (minimum 15 minutes on Android).
|
||||||
Future<void> registerBackgroundNotificationPoll() async {
|
Future<void> registerBackgroundNotificationPoll() async {
|
||||||
|
if (!_workmanagerSupported) return;
|
||||||
await Workmanager().initialize(backgroundCallbackDispatcher);
|
await Workmanager().initialize(backgroundCallbackDispatcher);
|
||||||
final minutes = PrefsService.instance.pollIntervalMinutes;
|
final minutes = PrefsService.instance.pollIntervalMinutes;
|
||||||
// Android enforces a 15-minute minimum for periodic tasks.
|
// Android enforces a 15-minute minimum for periodic tasks.
|
||||||
@@ -97,6 +105,7 @@ Future<void> registerBackgroundNotificationPoll() async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> cancelBackgroundNotificationPoll() async {
|
Future<void> cancelBackgroundNotificationPoll() async {
|
||||||
|
if (!_workmanagerSupported) return;
|
||||||
await Workmanager().cancelByUniqueName(notificationPollTaskName);
|
await Workmanager().cancelByUniqueName(notificationPollTaskName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -186,6 +186,44 @@ class ChecklistService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<List<ListItem>> getDeletedItems(
|
||||||
|
int houseId,
|
||||||
|
int listId, {
|
||||||
|
int limit = 200,
|
||||||
|
int offset = 0,
|
||||||
|
}) async {
|
||||||
|
return ApiClient.instance.get<List, List<ListItem>>(
|
||||||
|
'/houses/$houseId/lists/$listId/items/trash',
|
||||||
|
query: {'limit': limit.toString(), 'offset': offset.toString()},
|
||||||
|
fromJson: (data) => data
|
||||||
|
.map((e) => ListItem.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<ListItem> restoreItem(int houseId, int listId, int itemId) async {
|
||||||
|
return ApiClient.instance.post<Map<String, dynamic>, ListItem>(
|
||||||
|
'/houses/$houseId/lists/$listId/items/$itemId/restore',
|
||||||
|
fromJson: (data) => ListItem.fromJson(data),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> permanentlyDeleteItem(
|
||||||
|
int houseId,
|
||||||
|
int listId,
|
||||||
|
int itemId,
|
||||||
|
) async {
|
||||||
|
await ApiClient.instance.delete(
|
||||||
|
'/houses/$houseId/lists/$listId/items/$itemId/permanent',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> emptyTrash(int houseId, int listId) async {
|
||||||
|
await ApiClient.instance.delete(
|
||||||
|
'/houses/$houseId/lists/$listId/items/trash',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Future<ListItem> toggleItem(int houseId, int listId, int itemId) async {
|
Future<ListItem> toggleItem(int houseId, int listId, int itemId) async {
|
||||||
return ApiClient.instance.post<Map<String, dynamic>, ListItem>(
|
return ApiClient.instance.post<Map<String, dynamic>, ListItem>(
|
||||||
'/houses/$houseId/lists/$listId/items/$itemId/toggle',
|
'/houses/$houseId/lists/$listId/items/$itemId/toggle',
|
||||||
|
|||||||
@@ -19,14 +19,15 @@ class LocalNotificationsService {
|
|||||||
const androidSettings = AndroidInitializationSettings(
|
const androidSettings = AndroidInitializationSettings(
|
||||||
'@mipmap/ic_launcher',
|
'@mipmap/ic_launcher',
|
||||||
);
|
);
|
||||||
const iosSettings = DarwinInitializationSettings(
|
const darwinSettings = DarwinInitializationSettings(
|
||||||
requestAlertPermission: false,
|
requestAlertPermission: false,
|
||||||
requestBadgePermission: false,
|
requestBadgePermission: false,
|
||||||
requestSoundPermission: false,
|
requestSoundPermission: false,
|
||||||
);
|
);
|
||||||
const settings = InitializationSettings(
|
const settings = InitializationSettings(
|
||||||
android: androidSettings,
|
android: androidSettings,
|
||||||
iOS: iosSettings,
|
iOS: darwinSettings,
|
||||||
|
macOS: darwinSettings,
|
||||||
);
|
);
|
||||||
|
|
||||||
await _plugin.initialize(
|
await _plugin.initialize(
|
||||||
@@ -79,7 +80,19 @@ class LocalNotificationsService {
|
|||||||
await ios?.requestPermissions(alert: true, badge: true, sound: true) ??
|
await ios?.requestPermissions(alert: true, badge: true, sound: true) ??
|
||||||
true;
|
true;
|
||||||
|
|
||||||
return androidGranted && iosGranted;
|
final macos = _plugin
|
||||||
|
.resolvePlatformSpecificImplementation<
|
||||||
|
MacOSFlutterLocalNotificationsPlugin
|
||||||
|
>();
|
||||||
|
final macosGranted =
|
||||||
|
await macos?.requestPermissions(
|
||||||
|
alert: true,
|
||||||
|
badge: true,
|
||||||
|
sound: true,
|
||||||
|
) ??
|
||||||
|
true;
|
||||||
|
|
||||||
|
return androidGranted && iosGranted && macosGranted;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> show({
|
Future<void> show({
|
||||||
@@ -102,6 +115,7 @@ class LocalNotificationsService {
|
|||||||
priority: Priority.defaultPriority,
|
priority: Priority.defaultPriority,
|
||||||
),
|
),
|
||||||
iOS: DarwinNotificationDetails(),
|
iOS: DarwinNotificationDetails(),
|
||||||
|
macOS: DarwinNotificationDetails(),
|
||||||
),
|
),
|
||||||
payload: payload,
|
payload: payload,
|
||||||
);
|
);
|
||||||
|
|||||||
34
lib/services/pending_note_share_service.dart
Normal file
34
lib/services/pending_note_share_service.dart
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
|
/// A pending note to be created from an OS share intent. Held until the
|
||||||
|
/// notes wall picks it up and opens the new-note form prefilled.
|
||||||
|
class PendingNoteShare {
|
||||||
|
final int houseId;
|
||||||
|
final String content;
|
||||||
|
|
||||||
|
const PendingNoteShare({required this.houseId, required this.content});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cross-screen signal carrying a pending note share. The share router
|
||||||
|
/// pushes here, then asks the home view to switch to the notes tab; the
|
||||||
|
/// [NotesWallView] for the same house listens and opens the form.
|
||||||
|
class PendingNoteShareService extends ChangeNotifier {
|
||||||
|
PendingNoteShareService._();
|
||||||
|
static final PendingNoteShareService instance = PendingNoteShareService._();
|
||||||
|
|
||||||
|
PendingNoteShare? _pending;
|
||||||
|
PendingNoteShare? get pending => _pending;
|
||||||
|
|
||||||
|
void push(PendingNoteShare share) {
|
||||||
|
_pending = share;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the pending share if it matches [houseId] and clears it.
|
||||||
|
PendingNoteShare? takeForHouse(int houseId) {
|
||||||
|
if (_pending?.houseId != houseId) return null;
|
||||||
|
final taken = _pending;
|
||||||
|
_pending = null;
|
||||||
|
return taken;
|
||||||
|
}
|
||||||
|
}
|
||||||
40
lib/services/pending_photo_share_service.dart
Normal file
40
lib/services/pending_photo_share_service.dart
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
|
/// A pending photo upload originating from an OS share intent. Held in a
|
||||||
|
/// queue until the [PhotoBoardController] for the same house picks it up.
|
||||||
|
class PendingPhotoShare {
|
||||||
|
final int houseId;
|
||||||
|
final int? folderId;
|
||||||
|
final List<String> paths;
|
||||||
|
|
||||||
|
const PendingPhotoShare({
|
||||||
|
required this.houseId,
|
||||||
|
required this.folderId,
|
||||||
|
required this.paths,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cross-screen queue of pending photo uploads from share intents. The
|
||||||
|
/// share-router enqueues entries here, then asks the home view to switch
|
||||||
|
/// to the correct house + photo tab. The [PhotoBoardController] for that
|
||||||
|
/// house listens and consumes its matching entries.
|
||||||
|
class PendingPhotoShareService extends ChangeNotifier {
|
||||||
|
PendingPhotoShareService._();
|
||||||
|
static final PendingPhotoShareService instance = PendingPhotoShareService._();
|
||||||
|
|
||||||
|
final List<PendingPhotoShare> _queue = [];
|
||||||
|
|
||||||
|
void enqueue(PendingPhotoShare share) {
|
||||||
|
_queue.add(share);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove and return all pending uploads belonging to [houseId].
|
||||||
|
List<PendingPhotoShare> takeForHouse(int houseId) {
|
||||||
|
final taken = _queue.where((s) => s.houseId == houseId).toList();
|
||||||
|
if (taken.isNotEmpty) {
|
||||||
|
_queue.removeWhere((s) => s.houseId == houseId);
|
||||||
|
}
|
||||||
|
return taken;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
|
|
||||||
class PrefsService {
|
class PrefsService extends ChangeNotifier {
|
||||||
PrefsService._();
|
PrefsService._();
|
||||||
static final PrefsService instance = PrefsService._();
|
static final PrefsService instance = PrefsService._();
|
||||||
|
|
||||||
@@ -10,6 +11,8 @@ class PrefsService {
|
|||||||
static const _notificationsIntroSeenKey = 'notifications_intro_seen';
|
static const _notificationsIntroSeenKey = 'notifications_intro_seen';
|
||||||
static const _localeKey = 'locale';
|
static const _localeKey = 'locale';
|
||||||
static const _themeModeKey = 'theme_mode';
|
static const _themeModeKey = 'theme_mode';
|
||||||
|
static const _checklistTapRowToToggleKey = 'checklist_tap_row_to_toggle';
|
||||||
|
static const _checklistCategorySpacingKey = 'checklist_category_spacing';
|
||||||
final _storage = const FlutterSecureStorage();
|
final _storage = const FlutterSecureStorage();
|
||||||
|
|
||||||
int? _lastHouseId;
|
int? _lastHouseId;
|
||||||
@@ -32,6 +35,13 @@ class PrefsService {
|
|||||||
String? _themeMode;
|
String? _themeMode;
|
||||||
String? get themeMode => _themeMode;
|
String? get themeMode => _themeMode;
|
||||||
|
|
||||||
|
bool _checklistTapRowToToggle = false;
|
||||||
|
bool get checklistTapRowToToggle => _checklistTapRowToToggle;
|
||||||
|
|
||||||
|
/// "disabled", "space", "divider"
|
||||||
|
String _checklistCategorySpacing = 'disabled';
|
||||||
|
String get checklistCategorySpacing => _checklistCategorySpacing;
|
||||||
|
|
||||||
Future<void> load() async {
|
Future<void> load() async {
|
||||||
final lastHouse = await _storage.read(key: _lastHouseKey);
|
final lastHouse = await _storage.read(key: _lastHouseKey);
|
||||||
if (lastHouse != null) _lastHouseId = int.tryParse(lastHouse);
|
if (lastHouse != null) _lastHouseId = int.tryParse(lastHouse);
|
||||||
@@ -50,11 +60,21 @@ class PrefsService {
|
|||||||
|
|
||||||
_locale = await _storage.read(key: _localeKey);
|
_locale = await _storage.read(key: _localeKey);
|
||||||
_themeMode = await _storage.read(key: _themeModeKey);
|
_themeMode = await _storage.read(key: _themeModeKey);
|
||||||
|
|
||||||
|
final tapRow = await _storage.read(key: _checklistTapRowToToggleKey);
|
||||||
|
if (tapRow != null) _checklistTapRowToToggle = tapRow == 'true';
|
||||||
|
|
||||||
|
final spacing = await _storage.read(key: _checklistCategorySpacingKey);
|
||||||
|
if (spacing != null &&
|
||||||
|
(spacing == 'disabled' || spacing == 'space' || spacing == 'divider')) {
|
||||||
|
_checklistCategorySpacing = spacing;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setLastHouseId(int id) async {
|
Future<void> setLastHouseId(int id) async {
|
||||||
_lastHouseId = id;
|
_lastHouseId = id;
|
||||||
await _storage.write(key: _lastHouseKey, value: id.toString());
|
await _storage.write(key: _lastHouseKey, value: id.toString());
|
||||||
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setNotificationsEnabled(bool value) async {
|
Future<void> setNotificationsEnabled(bool value) async {
|
||||||
@@ -63,6 +83,7 @@ class PrefsService {
|
|||||||
key: _notificationsEnabledKey,
|
key: _notificationsEnabledKey,
|
||||||
value: value.toString(),
|
value: value.toString(),
|
||||||
);
|
);
|
||||||
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setPollIntervalMinutes(int minutes) async {
|
Future<void> setPollIntervalMinutes(int minutes) async {
|
||||||
@@ -71,6 +92,7 @@ class PrefsService {
|
|||||||
key: _pollIntervalMinutesKey,
|
key: _pollIntervalMinutesKey,
|
||||||
value: minutes.toString(),
|
value: minutes.toString(),
|
||||||
);
|
);
|
||||||
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setLocale(String? locale) async {
|
Future<void> setLocale(String? locale) async {
|
||||||
@@ -80,6 +102,7 @@ class PrefsService {
|
|||||||
} else {
|
} else {
|
||||||
await _storage.write(key: _localeKey, value: locale);
|
await _storage.write(key: _localeKey, value: locale);
|
||||||
}
|
}
|
||||||
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setThemeMode(String? mode) async {
|
Future<void> setThemeMode(String? mode) async {
|
||||||
@@ -89,6 +112,22 @@ class PrefsService {
|
|||||||
} else {
|
} else {
|
||||||
await _storage.write(key: _themeModeKey, value: mode);
|
await _storage.write(key: _themeModeKey, value: mode);
|
||||||
}
|
}
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setChecklistTapRowToToggle(bool value) async {
|
||||||
|
_checklistTapRowToToggle = value;
|
||||||
|
await _storage.write(
|
||||||
|
key: _checklistTapRowToToggleKey,
|
||||||
|
value: value.toString(),
|
||||||
|
);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setChecklistCategorySpacing(String value) async {
|
||||||
|
_checklistCategorySpacing = value;
|
||||||
|
await _storage.write(key: _checklistCategorySpacingKey, value: value);
|
||||||
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setNotificationsIntroSeen(bool value) async {
|
Future<void> setNotificationsIntroSeen(bool value) async {
|
||||||
@@ -97,6 +136,7 @@ class PrefsService {
|
|||||||
key: _notificationsIntroSeenKey,
|
key: _notificationsIntroSeenKey,
|
||||||
value: value.toString(),
|
value: value.toString(),
|
||||||
);
|
);
|
||||||
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> clear() async {
|
Future<void> clear() async {
|
||||||
@@ -106,11 +146,16 @@ class PrefsService {
|
|||||||
_notificationsIntroSeen = false;
|
_notificationsIntroSeen = false;
|
||||||
_locale = null;
|
_locale = null;
|
||||||
_themeMode = null;
|
_themeMode = null;
|
||||||
|
_checklistTapRowToToggle = false;
|
||||||
|
_checklistCategorySpacing = 'disabled';
|
||||||
await _storage.delete(key: _lastHouseKey);
|
await _storage.delete(key: _lastHouseKey);
|
||||||
await _storage.delete(key: _notificationsEnabledKey);
|
await _storage.delete(key: _notificationsEnabledKey);
|
||||||
await _storage.delete(key: _pollIntervalMinutesKey);
|
await _storage.delete(key: _pollIntervalMinutesKey);
|
||||||
await _storage.delete(key: _notificationsIntroSeenKey);
|
await _storage.delete(key: _notificationsIntroSeenKey);
|
||||||
await _storage.delete(key: _localeKey);
|
await _storage.delete(key: _localeKey);
|
||||||
await _storage.delete(key: _themeModeKey);
|
await _storage.delete(key: _themeModeKey);
|
||||||
|
await _storage.delete(key: _checklistTapRowToToggleKey);
|
||||||
|
await _storage.delete(key: _checklistCategorySpacingKey);
|
||||||
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
53
lib/services/share_intent_service.dart
Normal file
53
lib/services/share_intent_service.dart
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:io' show Platform;
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
|
||||||
|
|
||||||
|
/// Listens for incoming OS-level share intents (photos shared from Photos
|
||||||
|
/// app, plain text/URL shared from any app, etc.) and exposes the most
|
||||||
|
/// recent batch via a [ValueListenable]. Consumers should call [consume]
|
||||||
|
/// after navigating to the share handler so the same payload isn't
|
||||||
|
/// processed twice.
|
||||||
|
class ShareIntentService {
|
||||||
|
ShareIntentService._();
|
||||||
|
static final ShareIntentService instance = ShareIntentService._();
|
||||||
|
|
||||||
|
final ValueNotifier<List<SharedMediaFile>?> pending = ValueNotifier(null);
|
||||||
|
|
||||||
|
StreamSubscription<List<SharedMediaFile>>? _sub;
|
||||||
|
|
||||||
|
/// Begin listening for share intents. Idempotent.
|
||||||
|
Future<void> init() async {
|
||||||
|
if (kIsWeb || !(Platform.isAndroid || Platform.isIOS)) return;
|
||||||
|
|
||||||
|
_sub ??= ReceiveSharingIntent.instance.getMediaStream().listen(
|
||||||
|
(files) {
|
||||||
|
if (files.isNotEmpty) pending.value = files;
|
||||||
|
},
|
||||||
|
onError: (Object e) {
|
||||||
|
debugPrint('[ShareIntentService] stream error: $e');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
final initial = await ReceiveSharingIntent.instance.getInitialMedia();
|
||||||
|
if (initial.isNotEmpty) {
|
||||||
|
pending.value = initial;
|
||||||
|
}
|
||||||
|
// Clear the native cache so the same intent isn't re-delivered on
|
||||||
|
// subsequent cold starts.
|
||||||
|
await ReceiveSharingIntent.instance.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Take the most recent share payload and clear it.
|
||||||
|
List<SharedMediaFile>? consume() {
|
||||||
|
final v = pending.value;
|
||||||
|
pending.value = null;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> dispose() async {
|
||||||
|
await _sub?.cancel();
|
||||||
|
_sub = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
lib/utils/platform_info.dart
Normal file
12
lib/utils/platform_info.dart
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import 'dart:io' show Platform;
|
||||||
|
|
||||||
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
|
|
||||||
|
bool? _isiOSAppOnMacCache;
|
||||||
|
|
||||||
|
Future<bool> isiOSAppOnMac() async {
|
||||||
|
if (_isiOSAppOnMacCache != null) return _isiOSAppOnMacCache!;
|
||||||
|
if (!Platform.isIOS) return _isiOSAppOnMacCache = false;
|
||||||
|
final info = await DeviceInfoPlugin().iosInfo;
|
||||||
|
return _isiOSAppOnMacCache = info.isiOSAppOnMac;
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import 'package:package_info_plus/package_info_plus.dart';
|
|||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
import 'package:pantry/i18n.dart';
|
import 'package:pantry/i18n.dart';
|
||||||
|
import 'package:pantry/widgets/app_bar_back_leading.dart';
|
||||||
|
|
||||||
class AboutView extends StatefulWidget {
|
class AboutView extends StatefulWidget {
|
||||||
const AboutView({super.key});
|
const AboutView({super.key});
|
||||||
@@ -35,7 +36,7 @@ class _AboutViewState extends State<AboutView> {
|
|||||||
final a = m.about;
|
final a = m.about;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: Text(a.title)),
|
appBar: AppBar(leading: appBarBackLeading(context), title: Text(a.title)),
|
||||||
body: ListView(
|
body: ListView(
|
||||||
padding: const EdgeInsets.all(24),
|
padding: const EdgeInsets.all(24),
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:pantry/i18n.dart';
|
|||||||
import 'package:pantry/models/category.dart';
|
import 'package:pantry/models/category.dart';
|
||||||
import 'package:pantry/services/category_service.dart';
|
import 'package:pantry/services/category_service.dart';
|
||||||
import 'package:pantry/utils/category_icons.dart';
|
import 'package:pantry/utils/category_icons.dart';
|
||||||
|
import 'package:pantry/widgets/app_bar_back_leading.dart';
|
||||||
import 'package:pantry/widgets/create_category_dialog.dart';
|
import 'package:pantry/widgets/create_category_dialog.dart';
|
||||||
|
|
||||||
class CategoriesView extends StatefulWidget {
|
class CategoriesView extends StatefulWidget {
|
||||||
@@ -125,7 +126,10 @@ class _CategoriesViewState extends State<CategoriesView> {
|
|||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: Text(m.categories.manageTitle)),
|
appBar: AppBar(
|
||||||
|
leading: appBarBackLeading(context),
|
||||||
|
title: Text(m.categories.manageTitle),
|
||||||
|
),
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
onPressed: _create,
|
onPressed: _create,
|
||||||
child: const Icon(Icons.add),
|
child: const Icon(Icons.add),
|
||||||
|
|||||||
@@ -5,103 +5,141 @@ import 'package:pantry/models/category.dart' as models;
|
|||||||
import 'package:pantry/models/checklist.dart';
|
import 'package:pantry/models/checklist.dart';
|
||||||
import 'package:pantry/services/auth_service.dart';
|
import 'package:pantry/services/auth_service.dart';
|
||||||
import 'package:pantry/services/checklist_service.dart';
|
import 'package:pantry/services/checklist_service.dart';
|
||||||
|
import 'package:pantry/services/prefs_service.dart';
|
||||||
import 'package:pantry/utils/category_icons.dart';
|
import 'package:pantry/utils/category_icons.dart';
|
||||||
import 'package:pantry/utils/rrule.dart';
|
import 'package:pantry/utils/rrule.dart';
|
||||||
|
import 'package:pantry/widgets/context_menu_region.dart';
|
||||||
import 'package:pantry/widgets/image_preview.dart';
|
import 'package:pantry/widgets/image_preview.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class ChecklistItemTile extends StatelessWidget {
|
class ChecklistItemTile extends StatelessWidget {
|
||||||
final ListItem item;
|
final ListItem item;
|
||||||
final models.Category? category;
|
final models.Category? category;
|
||||||
final int houseId;
|
final int houseId;
|
||||||
|
final bool trashMode;
|
||||||
final ValueChanged<ListItem> onToggle;
|
final ValueChanged<ListItem> onToggle;
|
||||||
final ValueChanged<ListItem> onView;
|
final ValueChanged<ListItem> onView;
|
||||||
final ValueChanged<ListItem> onEdit;
|
final ValueChanged<ListItem> onEdit;
|
||||||
final ValueChanged<ListItem> onMove;
|
final ValueChanged<ListItem> onMove;
|
||||||
final ValueChanged<ListItem> onDelete;
|
final ValueChanged<ListItem> onDelete;
|
||||||
|
final ValueChanged<ListItem>? onRestore;
|
||||||
|
final ValueChanged<ListItem>? onPermanentDelete;
|
||||||
|
|
||||||
const ChecklistItemTile({
|
const ChecklistItemTile({
|
||||||
super.key,
|
super.key,
|
||||||
required this.item,
|
required this.item,
|
||||||
this.category,
|
this.category,
|
||||||
required this.houseId,
|
required this.houseId,
|
||||||
|
this.trashMode = false,
|
||||||
required this.onToggle,
|
required this.onToggle,
|
||||||
required this.onView,
|
required this.onView,
|
||||||
required this.onEdit,
|
required this.onEdit,
|
||||||
required this.onMove,
|
required this.onMove,
|
||||||
required this.onDelete,
|
required this.onDelete,
|
||||||
|
this.onRestore,
|
||||||
|
this.onPermanentDelete,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final dimmed = item.done;
|
final dimmed = item.done;
|
||||||
|
final tapRowToToggle = context
|
||||||
|
.watch<PrefsService>()
|
||||||
|
.checklistTapRowToToggle;
|
||||||
|
|
||||||
return Material(
|
return Material(
|
||||||
type: MaterialType.transparency,
|
type: MaterialType.transparency,
|
||||||
child: Opacity(
|
child: Opacity(
|
||||||
opacity: dimmed ? 0.5 : 1.0,
|
opacity: dimmed ? 0.5 : 1.0,
|
||||||
child: InkWell(
|
child: ContextMenuRegion<String>(
|
||||||
onTap: () => onToggle(item),
|
itemBuilder: _menuItems,
|
||||||
child: Padding(
|
onSelected: (value) => _onMenuSelected(value),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
child: InkWell(
|
||||||
child: Row(
|
onTap: trashMode
|
||||||
children: [
|
? () => onView(item)
|
||||||
Checkbox(value: item.done, onChanged: (_) => onToggle(item)),
|
: (tapRowToToggle ? () => onToggle(item) : null),
|
||||||
if (item.imageFileId != null) ...[
|
child: Padding(
|
||||||
GestureDetector(
|
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
||||||
onTap: () => _showImagePreview(context),
|
child: Row(
|
||||||
child: Hero(
|
children: [
|
||||||
tag: 'item-image-${item.id}',
|
if (trashMode)
|
||||||
child: _ItemImage(
|
Padding(
|
||||||
houseId: houseId,
|
padding: const EdgeInsetsDirectional.only(
|
||||||
fileId: item.imageFileId!,
|
start: 12,
|
||||||
owner: item.imageUploadedBy ?? '',
|
end: 12,
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
Icons.delete_outline,
|
||||||
|
color: theme.colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
Checkbox(
|
||||||
|
value: item.done,
|
||||||
|
onChanged: (_) => onToggle(item),
|
||||||
|
),
|
||||||
|
if (item.imageFileId != null) ...[
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () => _showImagePreview(context),
|
||||||
|
child: Hero(
|
||||||
|
tag: 'item-image-${item.id}',
|
||||||
|
child: _ItemImage(
|
||||||
|
houseId: houseId,
|
||||||
|
fileId: item.imageFileId!,
|
||||||
|
owner: item.imageUploadedBy ?? '',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(width: 8),
|
||||||
const SizedBox(width: 8),
|
],
|
||||||
],
|
Expanded(
|
||||||
Expanded(
|
child: Column(
|
||||||
child: Column(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
children: [
|
||||||
children: [
|
Text(
|
||||||
Text(
|
item.name,
|
||||||
item.name,
|
style: theme.textTheme.bodyLarge?.copyWith(
|
||||||
style: theme.textTheme.bodyLarge?.copyWith(
|
decoration: dimmed
|
||||||
decoration: dimmed
|
? TextDecoration.lineThrough
|
||||||
? TextDecoration.lineThrough
|
: null,
|
||||||
: null,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (_hasBadges)
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 2),
|
|
||||||
child: Wrap(
|
|
||||||
spacing: 4,
|
|
||||||
runSpacing: 4,
|
|
||||||
children: _buildBadges(context),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
if (_hasBadges)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 2),
|
||||||
|
child: Wrap(
|
||||||
|
spacing: 4,
|
||||||
|
runSpacing: 4,
|
||||||
|
children: _buildBadges(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
IconButton(
|
||||||
IconButton(
|
icon: Icon(
|
||||||
icon: Icon(
|
Icons.visibility_outlined,
|
||||||
Icons.visibility_outlined,
|
size: 20,
|
||||||
size: 20,
|
color: theme.colorScheme.onSurfaceVariant,
|
||||||
color: theme.colorScheme.onSurfaceVariant,
|
),
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
constraints: const BoxConstraints(),
|
||||||
|
onPressed: () => onView(item),
|
||||||
),
|
),
|
||||||
padding: EdgeInsets.zero,
|
PopupMenuButton<String>(
|
||||||
constraints: const BoxConstraints(),
|
icon: Icon(
|
||||||
onPressed: () => onView(item),
|
Icons.more_horiz,
|
||||||
),
|
size: 20,
|
||||||
_MoreMenuButton(
|
color: theme.colorScheme.onSurfaceVariant,
|
||||||
item: item,
|
),
|
||||||
onEdit: onEdit,
|
padding: EdgeInsets.zero,
|
||||||
onMove: onMove,
|
constraints: const BoxConstraints(),
|
||||||
onDelete: onDelete,
|
itemBuilder: (_) => _menuItems(),
|
||||||
),
|
onSelected: _onMenuSelected,
|
||||||
],
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -109,6 +147,80 @@ class ChecklistItemTile extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<PopupMenuEntry<String>> _menuItems() {
|
||||||
|
if (trashMode) {
|
||||||
|
return [
|
||||||
|
PopupMenuItem(
|
||||||
|
value: 'restore',
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.restore_from_trash, size: 18),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text(m.checklists.restoreItem),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
PopupMenuItem(
|
||||||
|
value: 'permanent',
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.delete_forever, size: 18),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text(m.checklists.permanentlyDeleteItem),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
PopupMenuItem(
|
||||||
|
value: 'edit',
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.edit, size: 18),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text(m.checklists.editItem),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
PopupMenuItem(
|
||||||
|
value: 'move',
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.drive_file_move_outlined, size: 18),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text(m.checklists.moveItem),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
PopupMenuItem(
|
||||||
|
value: 'remove',
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.delete, size: 18),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text(m.checklists.removeItem),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onMenuSelected(String value) {
|
||||||
|
switch (value) {
|
||||||
|
case 'edit':
|
||||||
|
onEdit(item);
|
||||||
|
case 'move':
|
||||||
|
onMove(item);
|
||||||
|
case 'remove':
|
||||||
|
onDelete(item);
|
||||||
|
case 'restore':
|
||||||
|
onRestore?.call(item);
|
||||||
|
case 'permanent':
|
||||||
|
onPermanentDelete?.call(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _showImagePreview(BuildContext context) {
|
void _showImagePreview(BuildContext context) {
|
||||||
final uri = ChecklistService.instance.itemImagePreviewUri(
|
final uri = ChecklistService.instance.itemImagePreviewUri(
|
||||||
houseId,
|
houseId,
|
||||||
@@ -255,72 +367,3 @@ class _Badge extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MoreMenuButton extends StatelessWidget {
|
|
||||||
final ListItem item;
|
|
||||||
final ValueChanged<ListItem> onEdit;
|
|
||||||
final ValueChanged<ListItem> onMove;
|
|
||||||
final ValueChanged<ListItem> onDelete;
|
|
||||||
|
|
||||||
const _MoreMenuButton({
|
|
||||||
required this.item,
|
|
||||||
required this.onEdit,
|
|
||||||
required this.onMove,
|
|
||||||
required this.onDelete,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return PopupMenuButton<String>(
|
|
||||||
icon: Icon(
|
|
||||||
Icons.more_horiz,
|
|
||||||
size: 20,
|
|
||||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
|
||||||
),
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
constraints: const BoxConstraints(),
|
|
||||||
itemBuilder: (context) => [
|
|
||||||
PopupMenuItem(
|
|
||||||
value: 'edit',
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
const Icon(Icons.edit, size: 18),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Text(m.checklists.editItem),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
PopupMenuItem(
|
|
||||||
value: 'move',
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
const Icon(Icons.drive_file_move_outlined, size: 18),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Text(m.checklists.moveItem),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
PopupMenuItem(
|
|
||||||
value: 'remove',
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
const Icon(Icons.delete, size: 18),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Text(m.checklists.removeItem),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
onSelected: (value) {
|
|
||||||
switch (value) {
|
|
||||||
case 'edit':
|
|
||||||
onEdit(item);
|
|
||||||
case 'move':
|
|
||||||
onMove(item);
|
|
||||||
case 'remove':
|
|
||||||
onDelete(item);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ class ChecklistsController extends ChangeNotifier {
|
|||||||
String _sortBy = 'custom';
|
String _sortBy = 'custom';
|
||||||
String get sortBy => _sortBy;
|
String get sortBy => _sortBy;
|
||||||
|
|
||||||
|
bool _isTrashMode = false;
|
||||||
|
bool get isTrashMode => _isTrashMode;
|
||||||
|
|
||||||
bool _isLoading = true;
|
bool _isLoading = true;
|
||||||
bool get isLoading => _isLoading;
|
bool get isLoading => _isLoading;
|
||||||
|
|
||||||
@@ -142,6 +145,14 @@ class ChecklistsController extends ChangeNotifier {
|
|||||||
_currentList = list;
|
_currentList = list;
|
||||||
_checklistService.selectedListId = list.id;
|
_checklistService.selectedListId = list.id;
|
||||||
|
|
||||||
|
if (_isTrashMode) {
|
||||||
|
_items = [];
|
||||||
|
_isLoading = true;
|
||||||
|
notifyListeners();
|
||||||
|
await _loadTrashItems(list);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Show cached items immediately, or spinner if no cache for this list
|
// Show cached items immediately, or spinner if no cache for this list
|
||||||
final cached = _checklistService.getCachedItems(list.id);
|
final cached = _checklistService.getCachedItems(list.id);
|
||||||
if (cached != null) {
|
if (cached != null) {
|
||||||
@@ -162,7 +173,7 @@ class ChecklistsController extends ChangeNotifier {
|
|||||||
sortBy: _sortBy,
|
sortBy: _sortBy,
|
||||||
);
|
);
|
||||||
_checklistService.cacheItems(list.id, freshItems);
|
_checklistService.cacheItems(list.id, freshItems);
|
||||||
if (_currentList?.id == list.id) {
|
if (_currentList?.id == list.id && !_isTrashMode) {
|
||||||
_items = freshItems;
|
_items = freshItems;
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
@@ -177,6 +188,38 @@ class ChecklistsController extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _loadTrashItems(ChecklistList list) async {
|
||||||
|
try {
|
||||||
|
final trashItems = await _checklistService.getDeletedItems(
|
||||||
|
houseId,
|
||||||
|
list.id,
|
||||||
|
);
|
||||||
|
if (_currentList?.id == list.id && _isTrashMode) {
|
||||||
|
_items = trashItems;
|
||||||
|
_error = null;
|
||||||
|
_isLoading = false;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('[ChecklistsController] Failed to load trash: $e');
|
||||||
|
if (_currentList?.id == list.id && _isTrashMode) {
|
||||||
|
_error = m.checklists.failedToLoadItems;
|
||||||
|
_isLoading = false;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setTrashMode(bool enabled) async {
|
||||||
|
if (_isTrashMode == enabled) return;
|
||||||
|
_isTrashMode = enabled;
|
||||||
|
if (_currentList != null) {
|
||||||
|
await selectList(_currentList!);
|
||||||
|
} else {
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> setSortBy(String sort) async {
|
Future<void> setSortBy(String sort) async {
|
||||||
if (sort == _sortBy) return;
|
if (sort == _sortBy) return;
|
||||||
_sortBy = sort;
|
_sortBy = sort;
|
||||||
@@ -389,6 +432,43 @@ class ChecklistsController extends ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<ListItem> restoreItem(ListItem item) async {
|
||||||
|
final restored = await _checklistService.restoreItem(
|
||||||
|
houseId,
|
||||||
|
item.listId,
|
||||||
|
item.id,
|
||||||
|
);
|
||||||
|
_items.removeWhere((i) => i.id == item.id);
|
||||||
|
if (!_isTrashMode) {
|
||||||
|
_items.add(restored);
|
||||||
|
_checklistService.cacheItems(_currentList!.id, List.of(_items));
|
||||||
|
}
|
||||||
|
notifyListeners();
|
||||||
|
return restored;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> permanentlyDeleteItem(ListItem item) async {
|
||||||
|
await _checklistService.permanentlyDeleteItem(
|
||||||
|
houseId,
|
||||||
|
item.listId,
|
||||||
|
item.id,
|
||||||
|
);
|
||||||
|
_items.removeWhere((i) => i.id == item.id);
|
||||||
|
if (!_isTrashMode) {
|
||||||
|
_checklistService.cacheItems(_currentList!.id, List.of(_items));
|
||||||
|
}
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> emptyTrash() async {
|
||||||
|
if (_currentList == null) return;
|
||||||
|
await _checklistService.emptyTrash(houseId, _currentList!.id);
|
||||||
|
if (_isTrashMode) {
|
||||||
|
_items = [];
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> toggleItem(ListItem item) async {
|
Future<void> toggleItem(ListItem item) async {
|
||||||
final index = _items.indexWhere((i) => i.id == item.id);
|
final index = _items.indexWhere((i) => i.id == item.id);
|
||||||
if (index == -1) return;
|
if (index == -1) return;
|
||||||
@@ -404,12 +484,23 @@ class ChecklistsController extends ChangeNotifier {
|
|||||||
item.listId,
|
item.listId,
|
||||||
item.id,
|
item.id,
|
||||||
);
|
);
|
||||||
_items[index] = updated;
|
// If toggling caused a soft-delete (deleteOnDone), drop it from active list.
|
||||||
|
if (updated.deletedAt != null) {
|
||||||
|
_items.removeWhere((i) => i.id == item.id);
|
||||||
|
} else {
|
||||||
|
final i = _items.indexWhere((x) => x.id == item.id);
|
||||||
|
if (i != -1) _items[i] = updated;
|
||||||
|
}
|
||||||
_checklistService.cacheItems(item.listId, List.of(_items));
|
_checklistService.cacheItems(item.listId, List.of(_items));
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Revert on failure
|
// Revert on failure
|
||||||
_items[index] = item;
|
final i = _items.indexWhere((x) => x.id == item.id);
|
||||||
|
if (i != -1) {
|
||||||
|
_items[i] = item;
|
||||||
|
} else {
|
||||||
|
_items.insert(index.clamp(0, _items.length), item);
|
||||||
|
}
|
||||||
_checklistService.cacheItems(item.listId, List.of(_items));
|
_checklistService.cacheItems(item.listId, List.of(_items));
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:pantry/models/category.dart' as models;
|
|||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import 'package:pantry/models/checklist.dart';
|
import 'package:pantry/models/checklist.dart';
|
||||||
|
import 'package:pantry/services/prefs_service.dart';
|
||||||
import 'package:pantry/utils/category_icons.dart';
|
import 'package:pantry/utils/category_icons.dart';
|
||||||
import 'package:pantry/utils/checklist_icons.dart';
|
import 'package:pantry/utils/checklist_icons.dart';
|
||||||
import 'package:pantry/widgets/checklist_selector.dart';
|
import 'package:pantry/widgets/checklist_selector.dart';
|
||||||
@@ -176,23 +177,39 @@ class _ChecklistsBodyState extends State<_ChecklistsBody> {
|
|||||||
lists: controller.lists,
|
lists: controller.lists,
|
||||||
currentList: controller.currentList,
|
currentList: controller.currentList,
|
||||||
onSelected: controller.selectList,
|
onSelected: controller.selectList,
|
||||||
|
onCreateNew: () => _createList(context, controller),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
IconButton(
|
if (!controller.isTrashMode)
|
||||||
icon: Icon(_searchOpen ? Icons.search_off : Icons.search),
|
IconButton(
|
||||||
onPressed: _toggleSearch,
|
icon: Icon(_searchOpen ? Icons.search_off : Icons.search),
|
||||||
),
|
onPressed: _toggleSearch,
|
||||||
ChecklistSortButton(
|
),
|
||||||
currentSort: controller.sortBy,
|
if (!controller.isTrashMode)
|
||||||
onSelected: controller.setSortBy,
|
ChecklistSortButton(
|
||||||
|
currentSort: controller.sortBy,
|
||||||
|
onSelected: controller.setSortBy,
|
||||||
|
),
|
||||||
|
PopupMenuButton<String>(
|
||||||
|
icon: Icon(
|
||||||
|
controller.isTrashMode ? Icons.delete : Icons.more_vert,
|
||||||
|
),
|
||||||
|
tooltip: controller.isTrashMode
|
||||||
|
? m.checklists.trashTitle
|
||||||
|
: null,
|
||||||
|
onSelected: (value) =>
|
||||||
|
_onListMenuSelected(context, controller, value),
|
||||||
|
itemBuilder: (_) => _listMenuItems(controller),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
if (controller.isTrashMode && controller.currentList != null)
|
||||||
|
_TrashBanner(onExit: () => controller.setTrashMode(false)),
|
||||||
AnimatedSize(
|
AnimatedSize(
|
||||||
duration: const Duration(milliseconds: 250),
|
duration: const Duration(milliseconds: 250),
|
||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOut,
|
||||||
alignment: Alignment.topCenter,
|
alignment: Alignment.topCenter,
|
||||||
child: _searchOpen
|
child: (_searchOpen && !controller.isTrashMode)
|
||||||
? _SearchPanel(
|
? _SearchPanel(
|
||||||
searchController: _searchController,
|
searchController: _searchController,
|
||||||
selectedCategoryIds: _selectedCategoryIds,
|
selectedCategoryIds: _selectedCategoryIds,
|
||||||
@@ -205,11 +222,12 @@ class _ChecklistsBodyState extends State<_ChecklistsBody> {
|
|||||||
Expanded(child: itemsArea),
|
Expanded(child: itemsArea),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (controller.currentList != null)
|
if (controller.currentList != null && !controller.isTrashMode)
|
||||||
PositionedDirectional(
|
PositionedDirectional(
|
||||||
end: 16,
|
end: 16,
|
||||||
bottom: 16,
|
bottom: 16,
|
||||||
child: FloatingActionButton(
|
child: FloatingActionButton(
|
||||||
|
heroTag: 'checklists-fab',
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final added = await Navigator.of(context).push<bool>(
|
final added = await Navigator.of(context).push<bool>(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
@@ -226,6 +244,149 @@ class _ChecklistsBodyState extends State<_ChecklistsBody> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _createList(
|
||||||
|
BuildContext context,
|
||||||
|
ChecklistsController controller,
|
||||||
|
) async {
|
||||||
|
final created = await showCreateListDialog(context, controller);
|
||||||
|
if (created != null) {
|
||||||
|
await controller.selectList(created);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<PopupMenuEntry<String>> _listMenuItems(ChecklistsController controller) {
|
||||||
|
if (controller.isTrashMode) {
|
||||||
|
return [
|
||||||
|
PopupMenuItem(
|
||||||
|
value: 'exit_trash',
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.arrow_back, size: 18),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text(m.checklists.exitTrash),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
PopupMenuItem(
|
||||||
|
value: 'empty_trash',
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.delete_forever, size: 18),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text(m.checklists.emptyTrash),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
PopupMenuItem(
|
||||||
|
value: 'view_trash',
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.delete_outline, size: 18),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text(m.checklists.viewTrash),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onListMenuSelected(
|
||||||
|
BuildContext context,
|
||||||
|
ChecklistsController controller,
|
||||||
|
String value,
|
||||||
|
) async {
|
||||||
|
switch (value) {
|
||||||
|
case 'view_trash':
|
||||||
|
if (_searchOpen) {
|
||||||
|
setState(() {
|
||||||
|
_searchOpen = false;
|
||||||
|
_searchController.clear();
|
||||||
|
_selectedCategoryIds.clear();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await controller.setTrashMode(true);
|
||||||
|
case 'exit_trash':
|
||||||
|
await controller.setTrashMode(false);
|
||||||
|
case 'empty_trash':
|
||||||
|
await _confirmEmptyTrash(context, controller);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _confirmEmptyTrash(
|
||||||
|
BuildContext context,
|
||||||
|
ChecklistsController controller,
|
||||||
|
) async {
|
||||||
|
final confirmed = await showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
builder: (ctx) => AlertDialog(
|
||||||
|
title: Text(m.checklists.emptyTrashConfirm),
|
||||||
|
content: Text(m.checklists.emptyTrashConfirmBody),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(ctx, false),
|
||||||
|
child: Text(m.common.cancel),
|
||||||
|
),
|
||||||
|
FilledButton(
|
||||||
|
onPressed: () => Navigator.pop(ctx, true),
|
||||||
|
child: Text(m.checklists.emptyTrash),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (confirmed != true) return;
|
||||||
|
try {
|
||||||
|
await controller.emptyTrash();
|
||||||
|
} catch (e) {
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(
|
||||||
|
context,
|
||||||
|
).showSnackBar(SnackBar(content: Text(m.checklists.emptyTrashFailed)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TrashBanner extends StatelessWidget {
|
||||||
|
final VoidCallback onExit;
|
||||||
|
|
||||||
|
const _TrashBanner({required this.onExit});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
color: theme.colorScheme.surfaceContainerHighest,
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(16, 8, 8, 8),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.delete_outline,
|
||||||
|
size: 18,
|
||||||
|
color: theme.colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
m.checklists.trashTitle,
|
||||||
|
style: theme.textTheme.labelLarge?.copyWith(
|
||||||
|
color: theme.colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextButton.icon(
|
||||||
|
onPressed: onExit,
|
||||||
|
icon: const Icon(Icons.close, size: 16),
|
||||||
|
label: Text(m.checklists.exitTrash),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SearchPanel extends StatelessWidget {
|
class _SearchPanel extends StatelessWidget {
|
||||||
@@ -441,25 +602,52 @@ class _ItemList extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final unchecked = items.where((i) => !i.done).toList();
|
|
||||||
final checked = items.where((i) => i.done).toList();
|
|
||||||
|
|
||||||
if (items.isEmpty) {
|
if (items.isEmpty) {
|
||||||
return ListView(
|
return ListView(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 100),
|
const SizedBox(height: 100),
|
||||||
Center(
|
Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
isFiltering ? m.checklists.noSearchResults : m.checklists.noItems,
|
controller.isTrashMode
|
||||||
|
? m.checklists.noTrashedItems
|
||||||
|
: (isFiltering
|
||||||
|
? m.checklists.noSearchResults
|
||||||
|
: m.checklists.noItems),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (controller.isTrashMode) {
|
||||||
|
return CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
_ReorderablePartition(
|
||||||
|
items: items,
|
||||||
|
controller: controller,
|
||||||
|
categorySpacing: 'disabled',
|
||||||
|
allowReorder: false,
|
||||||
|
),
|
||||||
|
const SliverToBoxAdapter(child: SizedBox(height: 88)),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final unchecked = items.where((i) => !i.done).toList();
|
||||||
|
final checked = items.where((i) => i.done).toList();
|
||||||
|
|
||||||
|
final spacingPref = context.watch<PrefsService>().checklistCategorySpacing;
|
||||||
|
final categorySpacing = controller.sortBy == 'category'
|
||||||
|
? spacingPref
|
||||||
|
: 'disabled';
|
||||||
|
|
||||||
return CustomScrollView(
|
return CustomScrollView(
|
||||||
slivers: [
|
slivers: [
|
||||||
_ReorderablePartition(items: unchecked, controller: controller),
|
_ReorderablePartition(
|
||||||
|
items: unchecked,
|
||||||
|
controller: controller,
|
||||||
|
categorySpacing: categorySpacing,
|
||||||
|
),
|
||||||
if (checked.isNotEmpty) ...[
|
if (checked.isNotEmpty) ...[
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: Column(
|
child: Column(
|
||||||
@@ -481,7 +669,11 @@ class _ItemList extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
_ReorderablePartition(items: checked, controller: controller),
|
_ReorderablePartition(
|
||||||
|
items: checked,
|
||||||
|
controller: controller,
|
||||||
|
categorySpacing: categorySpacing,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
const SliverToBoxAdapter(child: SizedBox(height: 88)),
|
const SliverToBoxAdapter(child: SizedBox(height: 88)),
|
||||||
],
|
],
|
||||||
@@ -492,8 +684,113 @@ class _ItemList extends StatelessWidget {
|
|||||||
class _ReorderablePartition extends StatelessWidget {
|
class _ReorderablePartition extends StatelessWidget {
|
||||||
final List<ListItem> items;
|
final List<ListItem> items;
|
||||||
final ChecklistsController controller;
|
final ChecklistsController controller;
|
||||||
|
final String categorySpacing;
|
||||||
|
final bool allowReorder;
|
||||||
|
|
||||||
const _ReorderablePartition({required this.items, required this.controller});
|
const _ReorderablePartition({
|
||||||
|
required this.items,
|
||||||
|
required this.controller,
|
||||||
|
this.categorySpacing = 'disabled',
|
||||||
|
this.allowReorder = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
void _toggleItem(
|
||||||
|
BuildContext context,
|
||||||
|
ChecklistsController controller,
|
||||||
|
ListItem item,
|
||||||
|
) {
|
||||||
|
final wasDone = item.done;
|
||||||
|
final wasDeleteOnDone = item.deleteOnDone;
|
||||||
|
controller.toggleItem(item);
|
||||||
|
if (wasDone) return;
|
||||||
|
|
||||||
|
final messenger = ScaffoldMessenger.of(context);
|
||||||
|
messenger.clearSnackBars();
|
||||||
|
messenger.showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(m.checklists.itemMarkedDone),
|
||||||
|
duration: const Duration(seconds: 6),
|
||||||
|
action: SnackBarAction(
|
||||||
|
label: m.checklists.undo,
|
||||||
|
onPressed: () async {
|
||||||
|
if (wasDeleteOnDone) {
|
||||||
|
try {
|
||||||
|
await controller.restoreItem(item);
|
||||||
|
} catch (e) {
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text(m.checklists.restoreFailed)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final current = controller.items.firstWhere(
|
||||||
|
(i) => i.id == item.id,
|
||||||
|
orElse: () => item.copyWith(done: true),
|
||||||
|
);
|
||||||
|
if (current.done) controller.toggleItem(current);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _restoreItem(
|
||||||
|
BuildContext context,
|
||||||
|
ChecklistsController controller,
|
||||||
|
ListItem item,
|
||||||
|
) async {
|
||||||
|
try {
|
||||||
|
await controller.restoreItem(item);
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(
|
||||||
|
context,
|
||||||
|
).showSnackBar(SnackBar(content: Text(m.checklists.itemRestored)));
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(
|
||||||
|
context,
|
||||||
|
).showSnackBar(SnackBar(content: Text(m.checklists.restoreFailed)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _permanentlyDelete(
|
||||||
|
BuildContext context,
|
||||||
|
ChecklistsController controller,
|
||||||
|
ListItem item,
|
||||||
|
) {
|
||||||
|
showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
builder: (ctx) => AlertDialog(
|
||||||
|
title: Text(m.checklists.permanentlyDeleteConfirm),
|
||||||
|
content: Text(m.checklists.permanentlyDeleteConfirmBody),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(ctx, false),
|
||||||
|
child: Text(m.common.cancel),
|
||||||
|
),
|
||||||
|
FilledButton(
|
||||||
|
onPressed: () => Navigator.pop(ctx, true),
|
||||||
|
child: Text(m.common.delete),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
).then((confirmed) async {
|
||||||
|
if (confirmed != true) return;
|
||||||
|
try {
|
||||||
|
await controller.permanentlyDeleteItem(item);
|
||||||
|
} catch (e) {
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text(m.checklists.permanentlyDeleteFailed)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void _viewItem(
|
void _viewItem(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
@@ -634,8 +931,52 @@ class _ReorderablePartition extends StatelessWidget {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _tileFor(BuildContext context, int index) {
|
||||||
|
final item = items[index];
|
||||||
|
final showSeparator =
|
||||||
|
categorySpacing != 'disabled' &&
|
||||||
|
index > 0 &&
|
||||||
|
items[index - 1].categoryId != item.categoryId;
|
||||||
|
final tile = ChecklistItemTile(
|
||||||
|
key: allowReorder ? null : ValueKey(item.id),
|
||||||
|
item: item,
|
||||||
|
category: item.categoryId != null
|
||||||
|
? controller.categories[item.categoryId]
|
||||||
|
: null,
|
||||||
|
houseId: controller.houseId,
|
||||||
|
trashMode: controller.isTrashMode,
|
||||||
|
onToggle: (item) => _toggleItem(context, controller, item),
|
||||||
|
onView: (item) => _viewItem(context, controller, item),
|
||||||
|
onEdit: (item) => _editItem(context, controller, item),
|
||||||
|
onMove: (item) => _moveItem(context, controller, item),
|
||||||
|
onDelete: (item) => _deleteItem(context, controller, item),
|
||||||
|
onRestore: (item) => _restoreItem(context, controller, item),
|
||||||
|
onPermanentDelete: (item) =>
|
||||||
|
_permanentlyDelete(context, controller, item),
|
||||||
|
);
|
||||||
|
return showSeparator
|
||||||
|
? Column(
|
||||||
|
children: [
|
||||||
|
if (categorySpacing == 'divider')
|
||||||
|
const Divider(height: 25)
|
||||||
|
else
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
tile,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: tile;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
if (!allowReorder) {
|
||||||
|
return SliverList(
|
||||||
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
(context, index) => _tileFor(context, index),
|
||||||
|
childCount: items.length,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
return SliverReorderableList(
|
return SliverReorderableList(
|
||||||
itemCount: items.length,
|
itemCount: items.length,
|
||||||
onReorder: (oldIndex, newIndex) {
|
onReorder: (oldIndex, newIndex) {
|
||||||
@@ -647,18 +988,7 @@ class _ReorderablePartition extends StatelessWidget {
|
|||||||
return ReorderableDelayedDragStartListener(
|
return ReorderableDelayedDragStartListener(
|
||||||
key: ValueKey(item.id),
|
key: ValueKey(item.id),
|
||||||
index: index,
|
index: index,
|
||||||
child: ChecklistItemTile(
|
child: _tileFor(context, index),
|
||||||
item: item,
|
|
||||||
category: item.categoryId != null
|
|
||||||
? controller.categories[item.categoryId]
|
|
||||||
: null,
|
|
||||||
houseId: controller.houseId,
|
|
||||||
onToggle: controller.toggleItem,
|
|
||||||
onView: (item) => _viewItem(context, controller, item),
|
|
||||||
onEdit: (item) => _editItem(context, controller, item),
|
|
||||||
onMove: (item) => _moveItem(context, controller, item),
|
|
||||||
onDelete: (item) => _deleteItem(context, controller, item),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_markdown_plus/flutter_markdown_plus.dart';
|
import 'package:flutter_markdown_plus/flutter_markdown_plus.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
import 'package:pantry/i18n.dart';
|
import 'package:pantry/i18n.dart';
|
||||||
import 'package:pantry/models/category.dart' as models;
|
import 'package:pantry/models/category.dart' as models;
|
||||||
import 'package:pantry/models/checklist.dart';
|
import 'package:pantry/models/checklist.dart';
|
||||||
@@ -10,6 +11,7 @@ import 'package:pantry/utils/category_icons.dart';
|
|||||||
import 'package:pantry/utils/date_format.dart';
|
import 'package:pantry/utils/date_format.dart';
|
||||||
import 'package:pantry/utils/rrule.dart';
|
import 'package:pantry/utils/rrule.dart';
|
||||||
import 'package:pantry/utils/text_direction.dart';
|
import 'package:pantry/utils/text_direction.dart';
|
||||||
|
import 'package:pantry/widgets/app_bar_back_leading.dart';
|
||||||
import 'checklists_controller.dart';
|
import 'checklists_controller.dart';
|
||||||
import 'item_form_view.dart';
|
import 'item_form_view.dart';
|
||||||
|
|
||||||
@@ -52,6 +54,8 @@ class ItemDetailView extends StatelessWidget {
|
|||||||
SliverAppBar(
|
SliverAppBar(
|
||||||
expandedHeight: hasImage ? 280 : 0,
|
expandedHeight: hasImage ? 280 : 0,
|
||||||
pinned: true,
|
pinned: true,
|
||||||
|
toolbarHeight: theme.appBarTheme.toolbarHeight ?? kToolbarHeight,
|
||||||
|
leading: appBarBackLeading(context),
|
||||||
title: Directionality(
|
title: Directionality(
|
||||||
textDirection: nameDir,
|
textDirection: nameDir,
|
||||||
child: Text(item.name),
|
child: Text(item.name),
|
||||||
@@ -77,6 +81,11 @@ class ItemDetailView extends StatelessWidget {
|
|||||||
child: MarkdownBody(
|
child: MarkdownBody(
|
||||||
data: item.description!,
|
data: item.description!,
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
|
onTapLink: (text, href, title) {
|
||||||
|
if (href != null) {
|
||||||
|
launchUrl(Uri.parse(href));
|
||||||
|
}
|
||||||
|
},
|
||||||
styleSheet: MarkdownStyleSheet.fromTheme(theme).copyWith(
|
styleSheet: MarkdownStyleSheet.fromTheme(theme).copyWith(
|
||||||
p: theme.textTheme.bodyMedium?.copyWith(
|
p: theme.textTheme.bodyMedium?.copyWith(
|
||||||
color: theme.colorScheme.onSurfaceVariant,
|
color: theme.colorScheme.onSurfaceVariant,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import 'package:pantry/models/checklist.dart';
|
|||||||
import 'package:pantry/services/auth_service.dart';
|
import 'package:pantry/services/auth_service.dart';
|
||||||
import 'package:pantry/services/checklist_service.dart';
|
import 'package:pantry/services/checklist_service.dart';
|
||||||
import 'package:pantry/utils/text_direction.dart';
|
import 'package:pantry/utils/text_direction.dart';
|
||||||
|
import 'package:pantry/widgets/app_bar_back_leading.dart';
|
||||||
import 'package:pantry/widgets/category_picker.dart';
|
import 'package:pantry/widgets/category_picker.dart';
|
||||||
import 'package:pantry/widgets/recurrence_dialog.dart';
|
import 'package:pantry/widgets/recurrence_dialog.dart';
|
||||||
import 'package:pantry/widgets/repeat_button.dart';
|
import 'package:pantry/widgets/repeat_button.dart';
|
||||||
@@ -151,7 +152,10 @@ class _ItemFormViewState extends State<ItemFormView> {
|
|||||||
final f = m.checklists.itemForm;
|
final f = m.checklists.itemForm;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: Text(_isEditing ? f.editTitle : f.addTitle)),
|
appBar: AppBar(
|
||||||
|
leading: appBarBackLeading(context),
|
||||||
|
title: Text(_isEditing ? f.editTitle : f.addTitle),
|
||||||
|
),
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
onPressed: _saving ? null : _save,
|
onPressed: _saving ? null : _save,
|
||||||
child: _saving
|
child: _saving
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
import 'dart:io' show Platform;
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
@@ -9,8 +12,10 @@ import 'package:pantry/models/house.dart';
|
|||||||
import 'package:pantry/services/deep_link_service.dart';
|
import 'package:pantry/services/deep_link_service.dart';
|
||||||
import 'package:pantry/views/notifications/notifications_controller.dart';
|
import 'package:pantry/views/notifications/notifications_controller.dart';
|
||||||
import 'package:pantry/views/notifications/notifications_view.dart';
|
import 'package:pantry/views/notifications/notifications_view.dart';
|
||||||
|
import 'package:pantry/services/share_intent_service.dart';
|
||||||
import 'package:pantry/views/photos/photo_board_view.dart';
|
import 'package:pantry/views/photos/photo_board_view.dart';
|
||||||
import 'package:pantry/views/settings/settings_view.dart';
|
import 'package:pantry/views/settings/settings_view.dart';
|
||||||
|
import 'package:pantry/views/share/share_router_view.dart';
|
||||||
import 'package:pantry/widgets/create_house_dialog.dart';
|
import 'package:pantry/widgets/create_house_dialog.dart';
|
||||||
import 'package:pantry/widgets/no_houses_view.dart';
|
import 'package:pantry/widgets/no_houses_view.dart';
|
||||||
import 'package:pantry/widgets/notifications_bell.dart';
|
import 'package:pantry/widgets/notifications_bell.dart';
|
||||||
@@ -66,26 +71,31 @@ class _HomeViewBodyState extends State<_HomeViewBody>
|
|||||||
final _pageController = PageController();
|
final _pageController = PageController();
|
||||||
final _notificationsController = NotificationsController();
|
final _notificationsController = NotificationsController();
|
||||||
|
|
||||||
|
static bool get _isMacOS => !kIsWeb && Platform.isMacOS;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
WidgetsBinding.instance.addObserver(this);
|
WidgetsBinding.instance.addObserver(this);
|
||||||
_notificationsController.load();
|
_notificationsController.load();
|
||||||
|
|
||||||
// Consume any deep link that arrived before we mounted (e.g. from a
|
// Consume any deep link or share intent that arrived before we
|
||||||
// cold-start notification tap).
|
// mounted (e.g. from a cold-start notification tap or share sheet).
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
_consumePendingDeepLink();
|
_consumePendingDeepLink();
|
||||||
|
_consumePendingShare();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Listen for deep links that arrive while the home view is mounted
|
// Listen for deep links and share intents that arrive while the home
|
||||||
// (notification tapped while app is in foreground or background).
|
// view is mounted.
|
||||||
DeepLinkService.instance.pending.addListener(_consumePendingDeepLink);
|
DeepLinkService.instance.pending.addListener(_consumePendingDeepLink);
|
||||||
|
ShareIntentService.instance.pending.addListener(_consumePendingShare);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
DeepLinkService.instance.pending.removeListener(_consumePendingDeepLink);
|
DeepLinkService.instance.pending.removeListener(_consumePendingDeepLink);
|
||||||
|
ShareIntentService.instance.pending.removeListener(_consumePendingShare);
|
||||||
WidgetsBinding.instance.removeObserver(this);
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
_pageController.dispose();
|
_pageController.dispose();
|
||||||
_notificationsController.dispose();
|
_notificationsController.dispose();
|
||||||
@@ -97,16 +107,32 @@ class _HomeViewBodyState extends State<_HomeViewBody>
|
|||||||
if (state == AppLifecycleState.resumed) {
|
if (state == AppLifecycleState.resumed) {
|
||||||
_notificationsController.refresh();
|
_notificationsController.refresh();
|
||||||
_consumePendingDeepLink();
|
_consumePendingDeepLink();
|
||||||
|
_consumePendingShare();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _consumePendingShare() {
|
||||||
|
final files = ShareIntentService.instance.consume();
|
||||||
|
if (files == null || files.isEmpty || !mounted) return;
|
||||||
|
Navigator.of(context).push(
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (_) => ShareRouterView(files: files),
|
||||||
|
fullscreenDialog: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void _goToTab(int index) {
|
void _goToTab(int index) {
|
||||||
if (index == _tabIndex) return;
|
if (index == _tabIndex) return;
|
||||||
_pageController.animateToPage(
|
if (_pageController.hasClients) {
|
||||||
index,
|
_pageController.animateToPage(
|
||||||
duration: const Duration(milliseconds: 280),
|
index,
|
||||||
curve: Curves.easeInOut,
|
duration: const Duration(milliseconds: 280),
|
||||||
);
|
curve: Curves.easeInOut,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
setState(() => _tabIndex = index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _consumePendingDeepLink() {
|
void _consumePendingDeepLink() {
|
||||||
@@ -144,65 +170,118 @@ class _HomeViewBodyState extends State<_HomeViewBody>
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final controller = context.watch<HomeController>();
|
final controller = context.watch<HomeController>();
|
||||||
|
|
||||||
final houseId = controller.currentHouse?.id;
|
final houseId = controller.currentHouse?.id;
|
||||||
|
final destinations = <_NavDestination>[
|
||||||
|
(icon: Icons.assignment_turned_in, label: m.nav.checklists),
|
||||||
|
(icon: Icons.photo, label: m.nav.photoBoard),
|
||||||
|
(icon: Icons.insert_drive_file, label: m.nav.notesWall),
|
||||||
|
];
|
||||||
|
|
||||||
return Scaffold(
|
return LayoutBuilder(
|
||||||
appBar: AppBar(
|
builder: (context, constraints) {
|
||||||
title: Text(_tabTitle),
|
final useRail = constraints.maxWidth >= 720;
|
||||||
actions: [
|
final extendedRail = constraints.maxWidth >= 1100;
|
||||||
if (_tabIndex == 0 && houseId != null)
|
final body = _buildBody(controller, useRail: useRail);
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.sell_outlined),
|
final appBar = AppBar(
|
||||||
tooltip: m.checklists.categories,
|
title: Text(_tabTitle),
|
||||||
onPressed: () {
|
actions: [
|
||||||
|
if (_tabIndex == 0 && houseId != null)
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.sell_outlined),
|
||||||
|
tooltip: m.checklists.categories,
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).push(
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (_) => CategoriesView(houseId: houseId),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
NotificationsBell(
|
||||||
|
controller: _notificationsController,
|
||||||
|
onTap: () {
|
||||||
Navigator.of(context).push(
|
Navigator.of(context).push(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (_) => CategoriesView(houseId: houseId),
|
builder: (_) =>
|
||||||
|
NotificationsView(controller: _notificationsController),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
NotificationsBell(
|
UserMenuButton(
|
||||||
controller: _notificationsController,
|
houses: controller.houses,
|
||||||
onTap: () {
|
currentHouse: controller.currentHouse,
|
||||||
Navigator.of(context).push(
|
onHouseSelected: controller.selectHouse,
|
||||||
MaterialPageRoute(
|
onCreateHouse: () => showCreateHouseDialog(context, controller),
|
||||||
builder: (_) =>
|
onOpenSettings: () {
|
||||||
NotificationsView(controller: _notificationsController),
|
Navigator.of(
|
||||||
),
|
context,
|
||||||
);
|
).push(MaterialPageRoute(builder: (_) => const SettingsView()));
|
||||||
},
|
},
|
||||||
|
onLogout: widget.onLogout,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (useRail) {
|
||||||
|
return Scaffold(
|
||||||
|
body: SafeArea(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
NavigationRail(
|
||||||
|
extended: extendedRail,
|
||||||
|
selectedIndex: _tabIndex,
|
||||||
|
onDestinationSelected: _goToTab,
|
||||||
|
labelType: extendedRail
|
||||||
|
? NavigationRailLabelType.none
|
||||||
|
: NavigationRailLabelType.all,
|
||||||
|
leading: _isMacOS ? const SizedBox(height: 24) : null,
|
||||||
|
destinations: [
|
||||||
|
for (final d in destinations)
|
||||||
|
NavigationRailDestination(
|
||||||
|
icon: Icon(d.icon),
|
||||||
|
label: Text(d.label),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const VerticalDivider(width: 1, thickness: 1),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
appBar,
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.only(
|
||||||
|
start: _tabIndex == 0 ? 0 : 16,
|
||||||
|
),
|
||||||
|
child: body,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: appBar,
|
||||||
|
body: body,
|
||||||
|
bottomNavigationBar: _AnimatedBottomNav(
|
||||||
|
pageController: _pageController,
|
||||||
|
currentIndex: _tabIndex,
|
||||||
|
onTap: _goToTab,
|
||||||
|
destinations: destinations,
|
||||||
),
|
),
|
||||||
UserMenuButton(
|
);
|
||||||
houses: controller.houses,
|
},
|
||||||
currentHouse: controller.currentHouse,
|
|
||||||
onHouseSelected: controller.selectHouse,
|
|
||||||
onCreateHouse: () => showCreateHouseDialog(context, controller),
|
|
||||||
onOpenSettings: () {
|
|
||||||
Navigator.of(
|
|
||||||
context,
|
|
||||||
).push(MaterialPageRoute(builder: (_) => const SettingsView()));
|
|
||||||
},
|
|
||||||
onLogout: widget.onLogout,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
body: _buildBody(controller),
|
|
||||||
bottomNavigationBar: _AnimatedBottomNav(
|
|
||||||
pageController: _pageController,
|
|
||||||
currentIndex: _tabIndex,
|
|
||||||
onTap: _goToTab,
|
|
||||||
destinations: [
|
|
||||||
(icon: Icons.assignment_turned_in, label: m.nav.checklists),
|
|
||||||
(icon: Icons.photo, label: m.nav.photoBoard),
|
|
||||||
(icon: Icons.insert_drive_file, label: m.nav.notesWall),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody(HomeController controller) {
|
Widget _buildBody(HomeController controller, {required bool useRail}) {
|
||||||
if (controller.isLoading) {
|
if (controller.isLoading) {
|
||||||
return const Center(child: CircularProgressIndicator());
|
return const Center(child: CircularProgressIndicator());
|
||||||
}
|
}
|
||||||
@@ -235,15 +314,19 @@ class _HomeViewBodyState extends State<_HomeViewBody>
|
|||||||
}
|
}
|
||||||
|
|
||||||
final houseId = controller.currentHouse!.id;
|
final houseId = controller.currentHouse!.id;
|
||||||
|
final pages = [
|
||||||
|
ChecklistsView(key: ValueKey('checklists-$houseId'), houseId: houseId),
|
||||||
|
PhotoBoardView(key: ValueKey('photos-$houseId'), houseId: houseId),
|
||||||
|
NotesWallView(key: ValueKey('notes-$houseId'), houseId: houseId),
|
||||||
|
];
|
||||||
|
if (useRail) {
|
||||||
|
return IndexedStack(index: _tabIndex, children: pages);
|
||||||
|
}
|
||||||
return PageView(
|
return PageView(
|
||||||
controller: _pageController,
|
controller: _pageController,
|
||||||
physics: const ClampingScrollPhysics(),
|
physics: const ClampingScrollPhysics(),
|
||||||
onPageChanged: (i) => setState(() => _tabIndex = i),
|
onPageChanged: (i) => setState(() => _tabIndex = i),
|
||||||
children: [
|
children: pages,
|
||||||
ChecklistsView(key: ValueKey('checklists-$houseId'), houseId: houseId),
|
|
||||||
PhotoBoardView(key: ValueKey('photos-$houseId'), houseId: houseId),
|
|
||||||
NotesWallView(key: ValueKey('notes-$houseId'), houseId: houseId),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,8 +81,8 @@ class LoginController extends ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
_onLoginSuccess?.call();
|
_onLoginSuccess?.call();
|
||||||
}
|
}
|
||||||
} catch (_) {
|
} catch (e, st) {
|
||||||
// Expected — 404 until login completes, or transient network errors
|
debugPrint('[LoginController] Poll error: $e\n$st');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_markdown_plus/flutter_markdown_plus.dart';
|
import 'package:flutter_markdown_plus/flutter_markdown_plus.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
import 'package:pantry/models/note.dart';
|
import 'package:pantry/models/note.dart';
|
||||||
import 'package:pantry/utils/text_direction.dart';
|
import 'package:pantry/utils/text_direction.dart';
|
||||||
import 'package:pantry/views/notes/note_form_view.dart';
|
import 'package:pantry/views/notes/note_form_view.dart';
|
||||||
import 'package:pantry/views/notes/notes_controller.dart';
|
import 'package:pantry/views/notes/notes_controller.dart';
|
||||||
|
import 'package:pantry/widgets/app_bar_back_leading.dart';
|
||||||
|
|
||||||
class NoteDetailView extends StatelessWidget {
|
class NoteDetailView extends StatelessWidget {
|
||||||
final Note note;
|
final Note note;
|
||||||
@@ -31,17 +33,11 @@ class NoteDetailView extends StatelessWidget {
|
|||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
backgroundColor: bgColor,
|
backgroundColor: bgColor,
|
||||||
foregroundColor: textColor,
|
foregroundColor: textColor,
|
||||||
title: Align(
|
leading: appBarBackLeading(context),
|
||||||
alignment: titleDir == TextDirection.rtl
|
title: Directionality(textDirection: titleDir, child: Text(note.title)),
|
||||||
? Alignment.centerRight
|
|
||||||
: Alignment.centerLeft,
|
|
||||||
child: Directionality(
|
|
||||||
textDirection: titleDir,
|
|
||||||
child: Text(note.title),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
|
heroTag: null,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).pushReplacement(
|
Navigator.of(context).pushReplacement(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
@@ -51,70 +47,84 @@ class NoteDetailView extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
child: const Icon(Icons.edit),
|
child: const Icon(Icons.edit),
|
||||||
),
|
),
|
||||||
body: note.content != null && note.content!.isNotEmpty
|
body: Hero(
|
||||||
? Directionality(
|
tag: 'note-${note.id}',
|
||||||
textDirection: contentDir,
|
child: Material(
|
||||||
child: Markdown(
|
color: bgColor,
|
||||||
data: note.content!,
|
child: note.content != null && note.content!.isNotEmpty
|
||||||
padding: const EdgeInsets.all(16),
|
? Directionality(
|
||||||
selectable: true,
|
textDirection: contentDir,
|
||||||
styleSheet: MarkdownStyleSheet.fromTheme(theme).copyWith(
|
child: Markdown(
|
||||||
p: theme.textTheme.bodyLarge?.copyWith(
|
data: note.content!,
|
||||||
color: textColor.withAlpha(230),
|
padding: const EdgeInsets.all(16),
|
||||||
),
|
selectable: true,
|
||||||
h1: theme.textTheme.headlineMedium?.copyWith(
|
onTapLink: (text, href, title) {
|
||||||
color: textColor,
|
if (href != null) {
|
||||||
fontWeight: FontWeight.bold,
|
launchUrl(Uri.parse(href));
|
||||||
),
|
}
|
||||||
h2: theme.textTheme.headlineSmall?.copyWith(
|
},
|
||||||
color: textColor,
|
styleSheet: MarkdownStyleSheet.fromTheme(theme).copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
p: theme.textTheme.bodyLarge?.copyWith(
|
||||||
),
|
color: textColor.withAlpha(230),
|
||||||
h3: theme.textTheme.titleLarge?.copyWith(
|
),
|
||||||
color: textColor,
|
h1: theme.textTheme.headlineMedium?.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
color: textColor,
|
||||||
),
|
fontWeight: FontWeight.bold,
|
||||||
h4: theme.textTheme.titleMedium?.copyWith(
|
),
|
||||||
color: textColor,
|
h2: theme.textTheme.headlineSmall?.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
color: textColor,
|
||||||
),
|
fontWeight: FontWeight.bold,
|
||||||
listBullet: theme.textTheme.bodyLarge?.copyWith(
|
),
|
||||||
color: textColor.withAlpha(230),
|
h3: theme.textTheme.titleLarge?.copyWith(
|
||||||
),
|
color: textColor,
|
||||||
code: TextStyle(
|
fontWeight: FontWeight.bold,
|
||||||
color: textColor,
|
),
|
||||||
backgroundColor: textColor.withAlpha(30),
|
h4: theme.textTheme.titleMedium?.copyWith(
|
||||||
fontFamily: 'monospace',
|
color: textColor,
|
||||||
),
|
fontWeight: FontWeight.bold,
|
||||||
codeblockDecoration: BoxDecoration(
|
),
|
||||||
color: textColor.withAlpha(30),
|
listBullet: theme.textTheme.bodyLarge?.copyWith(
|
||||||
borderRadius: BorderRadius.circular(6),
|
color: textColor.withAlpha(230),
|
||||||
),
|
),
|
||||||
blockquote: theme.textTheme.bodyLarge?.copyWith(
|
code: TextStyle(
|
||||||
color: textColor.withAlpha(180),
|
color: textColor,
|
||||||
fontStyle: FontStyle.italic,
|
backgroundColor: textColor.withAlpha(30),
|
||||||
),
|
fontFamily: 'monospace',
|
||||||
blockquoteDecoration: BoxDecoration(
|
),
|
||||||
border: Border(
|
codeblockDecoration: BoxDecoration(
|
||||||
left: BorderSide(
|
color: textColor.withAlpha(30),
|
||||||
color: textColor.withAlpha(100),
|
borderRadius: BorderRadius.circular(6),
|
||||||
width: 4,
|
),
|
||||||
|
blockquote: theme.textTheme.bodyLarge?.copyWith(
|
||||||
|
color: textColor.withAlpha(180),
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
),
|
||||||
|
blockquoteDecoration: BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
left: BorderSide(
|
||||||
|
color: textColor.withAlpha(100),
|
||||||
|
width: 4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
a: TextStyle(
|
||||||
|
color: textColor,
|
||||||
|
decoration: TextDecoration.underline,
|
||||||
|
),
|
||||||
|
strong: TextStyle(
|
||||||
|
color: textColor,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
em: TextStyle(
|
||||||
|
color: textColor,
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
a: TextStyle(
|
)
|
||||||
color: textColor,
|
: null,
|
||||||
decoration: TextDecoration.underline,
|
),
|
||||||
),
|
),
|
||||||
strong: TextStyle(
|
|
||||||
color: textColor,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
em: TextStyle(color: textColor, fontStyle: FontStyle.italic),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:pantry/i18n.dart';
|
|||||||
import 'package:pantry/models/note.dart';
|
import 'package:pantry/models/note.dart';
|
||||||
import 'package:pantry/utils/text_direction.dart';
|
import 'package:pantry/utils/text_direction.dart';
|
||||||
import 'package:pantry/views/notes/notes_controller.dart';
|
import 'package:pantry/views/notes/notes_controller.dart';
|
||||||
|
import 'package:pantry/widgets/app_bar_back_leading.dart';
|
||||||
|
|
||||||
const _colorOptions = <String?>[
|
const _colorOptions = <String?>[
|
||||||
null, // default / no color
|
null, // default / no color
|
||||||
@@ -29,7 +30,16 @@ class NoteFormView extends StatefulWidget {
|
|||||||
final NotesController controller;
|
final NotesController controller;
|
||||||
final Note? note;
|
final Note? note;
|
||||||
|
|
||||||
const NoteFormView({super.key, required this.controller, this.note});
|
/// When opening a new note seeded from an OS share intent, this holds
|
||||||
|
/// the shared text/URL to prefill into the content field.
|
||||||
|
final String? prefillContent;
|
||||||
|
|
||||||
|
const NoteFormView({
|
||||||
|
super.key,
|
||||||
|
required this.controller,
|
||||||
|
this.note,
|
||||||
|
this.prefillContent,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<NoteFormView> createState() => _NoteFormViewState();
|
State<NoteFormView> createState() => _NoteFormViewState();
|
||||||
@@ -50,11 +60,13 @@ class _NoteFormViewState extends State<NoteFormView> {
|
|||||||
super.initState();
|
super.initState();
|
||||||
_titleController = TextEditingController(text: widget.note?.title ?? '');
|
_titleController = TextEditingController(text: widget.note?.title ?? '');
|
||||||
_contentController = TextEditingController(
|
_contentController = TextEditingController(
|
||||||
text: widget.note?.content ?? '',
|
text: widget.note?.content ?? widget.prefillContent ?? '',
|
||||||
);
|
);
|
||||||
_selectedColor = widget.note?.color;
|
_selectedColor = widget.note?.color;
|
||||||
_titleDir = detectTextDirection(widget.note?.title);
|
_titleDir = detectTextDirection(widget.note?.title);
|
||||||
_contentDir = detectTextDirection(widget.note?.content);
|
_contentDir = detectTextDirection(
|
||||||
|
widget.note?.content ?? widget.prefillContent,
|
||||||
|
);
|
||||||
_titleController.addListener(() {
|
_titleController.addListener(() {
|
||||||
final dir = detectTextDirection(_titleController.text);
|
final dir = detectTextDirection(_titleController.text);
|
||||||
if (dir != _titleDir) setState(() => _titleDir = dir);
|
if (dir != _titleDir) setState(() => _titleDir = dir);
|
||||||
@@ -104,10 +116,26 @@ class _NoteFormViewState extends State<NoteFormView> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Color get _bgColor {
|
||||||
|
if (_selectedColor != null && _selectedColor!.isNotEmpty) {
|
||||||
|
final hex = _selectedColor!.replaceFirst('#', '');
|
||||||
|
final value = int.tryParse('FF$hex', radix: 16);
|
||||||
|
if (value != null) return Color(value);
|
||||||
|
}
|
||||||
|
return Theme.of(context).colorScheme.surfaceContainerHighest;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final bgColor = _bgColor;
|
||||||
|
final textColor = _contrastColor(bgColor);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
backgroundColor: bgColor,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
|
backgroundColor: bgColor,
|
||||||
|
foregroundColor: textColor,
|
||||||
|
leading: appBarBackLeading(context),
|
||||||
title: Text(_isEditing ? m.notesWall.editNote : m.notesWall.newNote),
|
title: Text(_isEditing ? m.notesWall.editNote : m.notesWall.newNote),
|
||||||
),
|
),
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
@@ -120,76 +148,92 @@ class _NoteFormViewState extends State<NoteFormView> {
|
|||||||
)
|
)
|
||||||
: const Icon(Icons.check),
|
: const Icon(Icons.check),
|
||||||
),
|
),
|
||||||
body: ListView(
|
body: Column(
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
children: [
|
children: [
|
||||||
TextField(
|
Padding(
|
||||||
controller: _titleController,
|
padding: const EdgeInsetsDirectional.fromSTEB(16, 16, 16, 0),
|
||||||
decoration: InputDecoration(
|
child: TextField(
|
||||||
labelText: m.notesWall.title,
|
controller: _titleController,
|
||||||
border: const OutlineInputBorder(),
|
decoration: InputDecoration(
|
||||||
|
hintText: m.notesWall.title,
|
||||||
|
hintStyle: TextStyle(color: textColor.withAlpha(100)),
|
||||||
|
border: InputBorder.none,
|
||||||
|
),
|
||||||
|
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
|
||||||
|
color: textColor,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
autofocus: !_isEditing,
|
||||||
|
textCapitalization: TextCapitalization.sentences,
|
||||||
|
textInputAction: TextInputAction.next,
|
||||||
|
textDirection: _titleDir,
|
||||||
),
|
),
|
||||||
autofocus: !_isEditing,
|
|
||||||
textCapitalization: TextCapitalization.sentences,
|
|
||||||
textInputAction: TextInputAction.next,
|
|
||||||
textDirection: _titleDir,
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
Expanded(
|
||||||
TextField(
|
child: Padding(
|
||||||
controller: _contentController,
|
padding: const EdgeInsetsDirectional.fromSTEB(16, 0, 16, 0),
|
||||||
decoration: InputDecoration(
|
child: TextField(
|
||||||
labelText: m.notesWall.content,
|
controller: _contentController,
|
||||||
border: const OutlineInputBorder(),
|
decoration: InputDecoration(
|
||||||
alignLabelWithHint: true,
|
hintText: m.notesWall.content,
|
||||||
),
|
hintStyle: TextStyle(color: textColor.withAlpha(100)),
|
||||||
textCapitalization: TextCapitalization.sentences,
|
border: InputBorder.none,
|
||||||
maxLines: 10,
|
|
||||||
minLines: 4,
|
|
||||||
textDirection: _contentDir,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
Text(
|
|
||||||
m.notesWall.color,
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
Wrap(
|
|
||||||
spacing: 8,
|
|
||||||
runSpacing: 8,
|
|
||||||
children: _colorOptions.map((hex) {
|
|
||||||
final color = hex != null
|
|
||||||
? Color(
|
|
||||||
int.parse('FF${hex.replaceFirst('#', '')}', radix: 16),
|
|
||||||
)
|
|
||||||
: Theme.of(context).colorScheme.surfaceContainerHighest;
|
|
||||||
final isSelected = _selectedColor == hex;
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: () => setState(() => _selectedColor = hex),
|
|
||||||
child: Container(
|
|
||||||
width: 36,
|
|
||||||
height: 36,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: color,
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
border: isSelected
|
|
||||||
? Border.all(
|
|
||||||
color: Theme.of(context).colorScheme.primary,
|
|
||||||
width: 3,
|
|
||||||
)
|
|
||||||
: Border.all(
|
|
||||||
color: Theme.of(context).colorScheme.outlineVariant,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: isSelected
|
|
||||||
? Icon(
|
|
||||||
Icons.check,
|
|
||||||
size: 18,
|
|
||||||
color: _contrastColor(color),
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
),
|
),
|
||||||
);
|
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
|
||||||
}).toList(),
|
color: textColor.withAlpha(230),
|
||||||
|
),
|
||||||
|
textCapitalization: TextCapitalization.sentences,
|
||||||
|
maxLines: null,
|
||||||
|
expands: true,
|
||||||
|
textAlignVertical: TextAlignVertical.top,
|
||||||
|
textDirection: _contentDir,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SingleChildScrollView(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(16, 8, 80, 48),
|
||||||
|
child: Row(
|
||||||
|
children: _colorOptions.map((hex) {
|
||||||
|
final color = hex != null
|
||||||
|
? Color(
|
||||||
|
int.parse('FF${hex.replaceFirst('#', '')}', radix: 16),
|
||||||
|
)
|
||||||
|
: Theme.of(context).colorScheme.surfaceContainerHighest;
|
||||||
|
final isSelected = _selectedColor == hex;
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.only(end: 8),
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () => setState(() => _selectedColor = hex),
|
||||||
|
child: CustomPaint(
|
||||||
|
foregroundPainter: hex == null
|
||||||
|
? _DiagonalLinePainter(
|
||||||
|
color: textColor.withAlpha(120),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
child: Container(
|
||||||
|
width: 36,
|
||||||
|
height: 36,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: color,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
border: isSelected
|
||||||
|
? Border.all(color: textColor, width: 3)
|
||||||
|
: Border.all(color: textColor.withAlpha(60)),
|
||||||
|
),
|
||||||
|
child: isSelected
|
||||||
|
? Icon(
|
||||||
|
Icons.check,
|
||||||
|
size: 18,
|
||||||
|
color: _contrastColor(color),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -200,3 +244,34 @@ class _NoteFormViewState extends State<NoteFormView> {
|
|||||||
return bg.computeLuminance() > 0.5 ? Colors.black87 : Colors.white;
|
return bg.computeLuminance() > 0.5 ? Colors.black87 : Colors.white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _DiagonalLinePainter extends CustomPainter {
|
||||||
|
final Color color;
|
||||||
|
|
||||||
|
_DiagonalLinePainter({required this.color});
|
||||||
|
|
||||||
|
@override
|
||||||
|
void paint(Canvas canvas, Size size) {
|
||||||
|
final paint = Paint()
|
||||||
|
..color = color
|
||||||
|
..strokeWidth = 2
|
||||||
|
..style = PaintingStyle.stroke;
|
||||||
|
final center = size.center(Offset.zero);
|
||||||
|
final radius = size.width / 2;
|
||||||
|
canvas.clipRRect(
|
||||||
|
RRect.fromRectAndRadius(
|
||||||
|
Rect.fromCircle(center: center, radius: radius),
|
||||||
|
Radius.circular(radius),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
canvas.drawLine(
|
||||||
|
Offset(size.width * 0.15, size.height * 0.85),
|
||||||
|
Offset(size.width * 0.85, size.height * 0.15),
|
||||||
|
paint,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldRepaint(_DiagonalLinePainter oldDelegate) =>
|
||||||
|
color != oldDelegate.color;
|
||||||
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user