Compare commits

..

123 commits

Author SHA1 Message Date
Tobi
944fc1eb6c
Merge pull request #374 from twonlyapp/dev
Some checks are pending
Publish on Github / build_and_publish (push) Waiting to run
- Multiple Bug fixes
2026-01-15 22:44:18 +01:00
otsmr
b1802111f5 update readme 2026-01-15 22:43:40 +01:00
otsmr
52952babfc fix plan limit
Some checks failed
Flutter analyze & test / flutter_analyze_and_test (push) Has been cancelled
2026-01-14 23:47:13 +01:00
otsmr
085702c0bb add limit check
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2026-01-14 23:28:31 +01:00
otsmr
285859cee6 change submodule url
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2026-01-14 23:15:48 +01:00
otsmr
2249c63c2f Merge remote-tracking branch 'origin/main' into dev 2026-01-14 23:14:42 +01:00
otsmr
772ec8aff1 bump version 2026-01-14 23:13:52 +01:00
otsmr
e9fcfbefd9 fixed some small issues 2026-01-14 23:12:48 +01:00
otsmr
5b2e91964f fix #373 2026-01-14 23:04:27 +01:00
otsmr
70fbf6abbb fix #369
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2026-01-14 22:55:01 +01:00
otsmr
e9c5d49938 fix #370
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2026-01-14 22:37:49 +01:00
otsmr
13f62934b7 fix #371 2026-01-14 22:33:58 +01:00
otsmr
36e309d58a add new workflow for additional users 2026-01-14 22:32:04 +01:00
otsmr
d2b881e281 fix typo
Some checks failed
Flutter analyze & test / flutter_analyze_and_test (push) Has been cancelled
2026-01-10 14:51:04 +01:00
otsmr
585f577f89 add flame counter test
Some checks failed
Flutter analyze & test / flutter_analyze_and_test (push) Has been cancelled
2025-12-30 19:58:32 +01:00
otsmr
ad0ef841cc improved log view
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-30 11:59:03 +01:00
otsmr
e97f0a910f fix smaller issues
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-30 11:21:43 +01:00
otsmr
6b353d8a66 remove error log
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-29 23:31:16 +01:00
otsmr
24f45ce9bd move storing of the images into the mediafile service 2025-12-29 23:24:14 +01:00
Tobi
1f8bdaa32d
Merge pull request #365 from twonlyapp/dev
Some checks failed
Publish on Github / build_and_publish (push) Has been cancelled
- Added an option in the settings to automatically save all sent images
- Hides duplicate images in the memory
- Fixes a bug where messages were not being received
- Several other minor improvements
2025-12-29 23:11:00 +01:00
otsmr
d067a3c931 bump version
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-29 23:09:15 +01:00
otsmr
b3c25dd160 fix #364 2025-12-29 23:06:09 +01:00
otsmr
3899c8e6e4 fix #363
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-29 22:27:44 +01:00
otsmr
87187843fa fix #360
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-29 21:22:32 +01:00
otsmr
ebf53a5ab4 fix #362 2025-12-29 16:13:57 +01:00
Tobi
6a104e9468
Merge pull request #359 from twonlyapp/dev
Some checks failed
Publish on Github / build_and_publish (push) Has been cancelled
- Fixes the issue where black/blank images were sometimes received
- Fixes an issue in the image editor
2025-12-28 15:49:31 +01:00
otsmr
ea68dcaf1c bump version
Some checks failed
Flutter analyze & test / flutter_analyze_and_test (push) Has been cancelled
2025-12-28 15:49:03 +01:00
otsmr
4b5a4387d1 fix #356 2025-12-28 15:46:21 +01:00
otsmr
85d6bdfcc9 fixes bug
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-27 23:02:48 +01:00
Tobi
41dfd54e81
Merge pull request #358 from twonlyapp/dev
Some checks are pending
Publish on Github / build_and_publish (push) Waiting to run
- Share images/videos directly from other applications
- More customization options in the appearance settings
- Improved UI for changing the display time of images
- Several minor UI improvements
- Several bug fixes
2025-12-27 21:32:35 +01:00
otsmr
20a2d61751 bump version
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-27 21:31:53 +01:00
otsmr
57c73a86ac fix #305
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-27 16:24:31 +01:00
otsmr
230809290a fixes #340 and continue with #333
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-27 15:09:36 +01:00
otsmr
0984eaf347 fix #355
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-26 22:49:45 +01:00
otsmr
b093a7acdb fix #354
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-26 22:43:24 +01:00
otsmr
6dc9aa10bc fix #350
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-26 22:08:39 +01:00
otsmr
11aa4c4202 fix #351
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-26 21:46:48 +01:00
otsmr
987a55dc65 fix analyzer
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-26 21:11:26 +01:00
otsmr
910f5f79fa make images visible before sending #356 and remove dependencies #333 2025-12-26 21:10:32 +01:00
otsmr
27483bccd6 workaround for #349
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-26 12:12:56 +01:00
otsmr
abd689f1fa fix #352
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-26 10:20:46 +01:00
otsmr
027871290d fix #348
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-26 09:07:41 +01:00
otsmr
82f4c9af9f fix #353
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-26 08:20:42 +01:00
otsmr
7007e7b063 fix null pointer
Some checks failed
Flutter analyze & test / flutter_analyze_and_test (push) Has been cancelled
2025-12-22 15:08:11 +01:00
Tobi
333f033993
Merge pull request #347 from twonlyapp/dev
Dev
2025-12-22 15:05:43 +01:00
otsmr
e17e39ef41 fix proof of work issue
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-21 21:56:54 +01:00
otsmr
b9bb074ba6 fix analyzer 2025-12-21 17:22:05 +01:00
Tobi
2713f092eb
Merge pull request #345 from twonlyapp/dev
Some checks failed
Publish on Github / build_and_publish (push) Has been cancelled
- Fixes multiple user-ability issues
- Implemented payment system with Google Play and App Store
- Fixing multiple bugs
2025-12-21 17:21:26 +01:00
otsmr
c91c53dd8b fixed some smaller issues
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-21 17:19:40 +01:00
otsmr
049507cd25 fix additional users
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-21 16:37:48 +01:00
otsmr
fa953b8928 adds google and apple payment #162
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-21 03:33:20 +01:00
otsmr
074ead8b4f fixing multiple use-ability issues #343 #342
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-21 00:06:10 +01:00
otsmr
9fe55ab62d fix some minor issues
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-20 02:51:24 +01:00
otsmr
2db1775d1f starting with in app purchases
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-20 02:14:01 +01:00
otsmr
189ed26dd7 add billing plugin 2025-12-17 19:41:30 +01:00
otsmr
39d406d156 add heavy impact
Some checks failed
Flutter analyze & test / flutter_analyze_and_test (push) Has been cancelled
2025-12-17 19:15:00 +01:00
otsmr
6b2cc85e81 add billing permission 2025-12-17 19:14:50 +01:00
otsmr
0ed264f152 fixing 32-bit integer
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-17 02:05:12 +01:00
Tobi
5645baaae8
Merge pull request #336 from twonlyapp/dev
Some checks failed
Publish on Github / build_and_publish (push) Has been cancelled
- Improving uploading speed
- Fixing issue with ffmpeg for android
2025-12-16 10:06:18 +01:00
otsmr
4f27bfba01 fixing video issue for pixel 10
Some checks failed
Flutter analyze & test / flutter_analyze_and_test (push) Has been cancelled
2025-12-16 01:03:31 +01:00
otsmr
618d4a3fb3 fix for scanning himself
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-15 20:56:18 +01:00
otsmr
54f049496d maybe solving the issue on ios 2025-12-15 20:53:22 +01:00
Tobi
ab103a98ae
Merge pull request #335 from twonlyapp/dev
Some checks are pending
Publish on Github / build_and_publish (push) Waiting to run
- Integrated QR code scanner in the main camera
- New profile share page
- New workflow for checking the security number
- Improved user interface for creating voice messages
2025-12-15 20:44:11 +01:00
otsmr
1798ba321b bump version 2025-12-15 20:42:53 +01:00
Tobi
7768362eb5
Merge pull request #334 from twonlyapp/dev
Dev
2025-12-15 20:36:12 +01:00
otsmr
05c2e8d677 update gitmodules
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-15 20:24:51 +01:00
otsmr
1a2aa5edb9 finishes #332 2025-12-15 20:20:30 +01:00
otsmr
25114daee2 fix #326
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-15 19:12:25 +01:00
otsmr
bc1c61c8f8 finishing #327
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-15 17:02:51 +01:00
otsmr
36e11c206c add qr view #327
Some checks failed
Flutter analyze & test / flutter_analyze_and_test (push) Has been cancelled
2025-12-08 00:06:45 +01:00
otsmr
332c19e880 fix analyzer
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-07 18:14:01 +01:00
otsmr
b3ec419411 splitting the logic for #327 2025-12-07 18:12:59 +01:00
otsmr
3265b6259c start with dependency checking
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-07 16:46:12 +01:00
otsmr
76b617e63a add barcode scanner and remove tutorial 2025-12-07 16:02:08 +01:00
otsmr
9667ea21b6 starting with #327
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-07 03:23:54 +01:00
otsmr
3cb9f7bf4b starting with #327 2025-12-07 03:23:50 +01:00
otsmr
004f00f308 fixing #321
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-07 01:56:42 +01:00
otsmr
a63343ccdd fix #323
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-07 00:51:43 +01:00
otsmr
35a90ace0a improve layout for smaller devices
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-12-06 21:20:13 +01:00
otsmr
38ab86f5e8 #329 2025-12-06 21:19:26 +01:00
otsmr
24edf896c5 workaround for #329 2025-12-06 21:19:20 +01:00
otsmr
6ab11c4e69 fix #324 2025-12-06 21:18:46 +01:00
otsmr
b8c063cc29 twonlies can not be stored
Some checks failed
Flutter analyze & test / flutter_analyze_and_test (push) Has been cancelled
2025-12-04 17:10:36 +01:00
otsmr
febf236147 fix null pointer issue
Some checks failed
Flutter analyze & test / flutter_analyze_and_test (push) Has been cancelled
2025-11-30 13:48:28 +01:00
Tobi
b306165681
Merge pull request #325 from twonlyapp/dev
Some checks failed
Publish on Github / build_and_publish (push) Has been cancelled
Multiple bug fixes
2025-11-30 12:54:52 +01:00
otsmr
ef4b799861 bump version 2025-11-30 12:53:34 +01:00
otsmr
83d57c638b update dependency
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-11-30 12:38:10 +01:00
otsmr
03df9634aa fix #322 2025-11-30 12:28:03 +01:00
otsmr
6ed8a3eff5 fix typo 2025-11-30 12:27:49 +01:00
otsmr
7aeaa97a68 improve logging 2025-11-30 12:27:40 +01:00
otsmr
108a58ffe1 improve logging 2025-11-30 12:27:21 +01:00
otsmr
9cb2503cdb maybe fixing #316
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-11-30 11:00:55 +01:00
otsmr
5758749bd1 improve logging 2025-11-30 10:27:13 +01:00
otsmr
d2b7e4cf9e fix #318 2025-11-30 09:19:38 +01:00
otsmr
2624df9b99 fix #317 2025-11-30 09:15:08 +01:00
otsmr
004c0e116c fix #319 2025-11-30 09:12:40 +01:00
otsmr
c6cc518de1 fix #320 2025-11-30 09:01:39 +01:00
otsmr
e7e413a9f1 test commit 2025-11-27 10:14:03 +01:00
otsmr
1f54423a10 add download buttons 2025-11-24 20:13:59 +01:00
otsmr
92fa2cdff5 update metadata 2025-11-24 19:40:21 +01:00
otsmr
819c8201d2 fix keyboard switch to emoji
Some checks failed
Flutter analyze & test / flutter_analyze_and_test (push) Has been cancelled
2025-11-23 15:13:48 +01:00
Tobi
a99a52cdb0
Merge pull request #315 from twonlyapp/dev
Some checks failed
Publish on Github / build_and_publish (push) Has been cancelled
- UI Performance improvements
- Multiple Bug fixes
2025-11-19 00:09:13 +01:00
otsmr
7268e990bc bump version
Some checks failed
Flutter analyze & test / flutter_analyze_and_test (push) Has been cancelled
2025-11-18 23:39:25 +01:00
otsmr
89e12fe24f fix #313 2025-11-18 23:38:55 +01:00
otsmr
66fb320355 add missing key and fix height 2025-11-18 23:35:59 +01:00
otsmr
c3e92ac7d1 fix avatar render issues, fix list update issues
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
2025-11-18 22:56:42 +01:00
Tobi
f50add6530
Merge pull request #312 from twonlyapp/dev
Fixes #311 and #310.
2025-11-15 00:15:27 +01:00
otsmr
e00700d4e3 bump version 2025-11-15 00:14:23 +01:00
otsmr
4623487556 fix #311 2025-11-15 00:13:53 +01:00
otsmr
72495b4c2a fix #310 2025-11-15 00:01:47 +01:00
otsmr
eb8b7d31de fix analyzer 2025-11-14 00:02:00 +01:00
Tobi
39c8d4990f
Merge pull request #309 from twonlyapp/dev
- Option to export and import memories
- iOS support for ultra-wide-angle camera
- Support Android Monochrome Icon
- Multiple layout issues fixed
- Multiple bug fixes
2025-11-13 23:57:31 +01:00
otsmr
8a4632c4c4 fix #303 and bump version 2025-11-13 23:57:01 +01:00
otsmr
fa85dbd6e2 fix #302 2025-11-13 22:46:23 +01:00
otsmr
58b286526d fix #308 2025-11-13 22:14:01 +01:00
otsmr
fc2513ddba fix #306 2025-11-13 22:03:15 +01:00
otsmr
7977d171c7 fix #307 2025-11-13 21:28:57 +01:00
otsmr
1eaa1a5edd add monochrome icon 2025-11-12 23:56:52 +01:00
otsmr
570d820ada make backups smaller 2025-11-11 21:40:17 +01:00
otsmr
1e14905682 fix issue 2025-11-11 00:43:23 +01:00
otsmr
f57c2fec79 improve logging 2025-11-11 00:42:57 +01:00
otsmr
5371114e21 fixing wide angle on ios 2025-11-11 00:05:59 +01:00
otsmr
2a9414ae4f wrap whole main function into sentry 2025-11-10 14:37:44 +01:00
289 changed files with 52614 additions and 9036 deletions

11
.gitmodules vendored
View file

@ -1,3 +1,8 @@
[submodule "dependencies/flutter_zxing"]
path = dependencies/flutter_zxing [submodule "dependencies"]
url = https://github.com/khoren93/flutter_zxing.git path = dependencies
url = https://github.com/twonlyapp/twonly-app-dependencies.git
[submodule "lib/src/localization/translations"]
path = lib/src/localization/translations
# url = ssh://git@git.twonly.eu:22222/twonly/twonly-translations.git
url = https://git.twonly.eu/twonly/twonly-translations

11
.vscode/launch.json vendored
View file

@ -1,11 +0,0 @@
{
"configurations": [
{
"name": "Flutter",
"type": "dart",
"request": "launch",
"program": "lib/main.dart",
"flutterMode": "profile"
}
]
}

View file

@ -1,5 +1,50 @@
# Changelog # Changelog
## 0.0.83
- Improved view of the diagnostic log
- Several bug fixes
## 0.0.82
- Added an option in the settings to automatically save all sent images
- Hides duplicate images in the memory
- Fixes a bug where messages were not being received
- Several other minor improvements
## 0.0.81
- Fixes the issue where black/blank images were sometimes received
- Fixes an issue in the image editor
## 0.0.80
- Share images/videos directly from other applications
- More customization options in the appearance settings
- Improved UI for changing the display time of images
- Several minor UI improvements
- Several bug fixes
## 0.0.74
- Improving uploading speed
- Fixing issue with ffmpeg for android
## 0.0.73
- Integrated QR code scanner in the main camera
- New profile share page
- New workflow for checking the security number
- Improved user interface for creating voice messages
## 0.0.69
- Option to export and import memories
- iOS support for ultra-wide-angle camera
- Support Android Monochrome Icon
- Multiple layout issues fixed
- Multiple bug fixes
## 0.0.67 ## 0.0.67
- Adds crash reports (optional). Please consider enabling this under Settings > Help > “Share errors and crashes with us.” - Adds crash reports (optional). Please consider enabling this under Settings > Help > “Share errors and crashes with us.”

View file

@ -4,12 +4,35 @@
This repository contains the complete source code of the [twonly](https://twonly.eu) apps. This repository contains the complete source code of the [twonly](https://twonly.eu) apps.
<!-- <a href="https://testflight.apple.com/join/U9B3v2rk" >
<img alt="Get it on Testflight button" src="https://twonly.eu/assets/buttons/get-it-on-testflight.png"
width="100px" />
</a> -->
<div class="my-5 space-x-4">
<div class="flex gap-5 items-center justify-center">
<a href="https://apps.apple.com/de/app/twonly/id6743774441">
<img alt="Get it on App Store button" src="https://twonly.eu/assets/buttons/download-on-the-app-store.svg"
width="100px" />
</a>
<a href="https://play.google.com/store/apps/details?id=eu.twonly">
<img alt="Get it on Google-Play button" src="https://twonly.eu/assets/buttons/get-it-in-google-play.webp"
width="110px" />
</a>
<a href="https://github.com/twonlyapp/twonly-app/releases">
<img alt="Get it on Github button" src="https://twonly.eu/assets/buttons/get-it-on-github.webp" width="110px" />
</a>
<a href="https://releases.twonly.eu/fdroid/repo/">
<img alt="Get it on F-Droid button" src="https://twonly.eu/assets/buttons/get-it-on-f-droid.webp" width="105px" />
</a>
</div>
</div>
## Features ## Features
- Offer a Snapchat™ like experience - Offer a Snapchat™ like experience
- End-to-End encryption using the [Signal Protocol](https://de.wikipedia.org/wiki/Signal-Protokoll) - End-to-End encryption using the [Signal Protocol](https://de.wikipedia.org/wiki/Signal-Protokoll)
- twonly is Open Source and can be downloaded directly from GitHub - Open Source and can be downloaded directly from GitHub
- Developed by humans not by AI or Vibe Coding
- No email or phone number required to register - No email or phone number required to register
- Privacy friendly - Everything is stored on the device - Privacy friendly - Everything is stored on the device
- The backend is hosted exclusively in Europe - The backend is hosted exclusively in Europe
@ -21,6 +44,7 @@ This repository contains the complete source code of the [twonly](https://twonly
- Implementing [Sealed Sender](https://signal.org/blog/sealed-sender/) to minimize metadata - Implementing [Sealed Sender](https://signal.org/blog/sealed-sender/) to minimize metadata
## Security Issues ## Security Issues
If you discover a security issue in twonly, please adhere to the coordinated vulnerability disclosure model. Please send If you discover a security issue in twonly, please adhere to the coordinated vulnerability disclosure model. Please send
us your report to security@twonly.eu. We also offer for critical security issues a small bug bounties, but we can not us your report to security@twonly.eu. We also offer for critical security issues a small bug bounties, but we can not
guarantee a bounty currently :/ guarantee a bounty currently :/
@ -54,7 +78,7 @@ run-as eu.twonly.testing ls /data/user/0/eu.twonly.testing/
## Signing Keys ## Signing Keys
When you download the app **via GitHub** you can verify the signing keys using for example the [AppVerifyer](https://github.com/soupslurpr/AppVerifier) and the following SHA-256 fingerprint of the signing certificate. When you download the app **via GitHub or F-Droid** you can verify the signing keys using for example the [AppVerifyer](https://github.com/soupslurpr/AppVerifier) and the following SHA-256 fingerprint of the signing certificate.
eu.twonly eu.twonly
E3:C4:4D:56:8C:67:F9:32:AC:8C:33:90:99:8A:B9:5E:E8:FF:2D:7A:07:3C:24:E3:66:77:93:E6:EA:CD:77:0A E3:C4:4D:56:8C:67:F9:32:AC:8C:33:90:99:8A:B9:5E:E8:FF:2D:7A:07:3C:24:E3:66:77:93:E6:EA:CD:77:0A

View file

@ -16,6 +16,8 @@ analyzer:
- "lib/src/model/protobuf/api/websocket/**" - "lib/src/model/protobuf/api/websocket/**"
- "lib/generated/**" - "lib/generated/**"
- "dependencies/**" - "dependencies/**"
- "pubspec.yaml"
- "*.arb"
- "test/drift/**" - "test/drift/**"
- "**.g.dart" - "**.g.dart"

View file

@ -19,7 +19,7 @@ android {
// compileSdk = flutter.compileSdkVersion // compileSdk = flutter.compileSdkVersion
compileSdk 36 compileSdk 36
//ndkVersion = flutter.ndkVersion //ndkVersion = flutter.ndkVersion
ndkVersion = "27.0.12077973" ndkVersion = "28.2.13676358"
compileOptions { compileOptions {
coreLibraryDesugaringEnabled true coreLibraryDesugaringEnabled true

View file

@ -1,9 +1,15 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
<!-- The INTERNET permission is required for development. Specifically, <!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc. to allow setting breakpoints, to provide hot reload, etc.
--> -->
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<application android:usesCleartextTraffic="true" > <application android:usesCleartextTraffic="true" >
</application> <!-- // https://github.com/juliansteenbakker/mobile_scanner/issues/553 -->
<meta-data android:name="firebase_performance_collection_deactivated" android:value="true" />
<!-- <service
android:name="com.google.android.datatransport.runtime.scheduling.jobscheduling.JobInfoSchedulerService"
tools:node="remove">
</service> -->
</application>
</manifest> </manifest>

View file

@ -1,4 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
<application <application
android:label="twonly" android:label="twonly"
android:name="${applicationName}" android:name="${applicationName}"
@ -26,6 +26,23 @@
<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 android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" android:host="me.twonly.eu" />
<data android:scheme="https" />
</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" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="video/*" />
</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 -->
@ -33,19 +50,17 @@
android:name="flutterEmbedding" android:name="flutterEmbedding"
android:value="2" /> android:value="2" />
<!-- // https://github.com/juliansteenbakker/mobile_scanner/issues/553 -->
<!-- <service <meta-data android:name="firebase_performance_collection_deactivated" android:value="true" />
android:name="com.pravera.flutter_foreground_task.service.ForegroundService" <service
android:foregroundServiceType="dataSync|remoteMessaging" android:name="com.google.android.datatransport.runtime.scheduling.jobscheduling.JobInfoSchedulerService"
android:exported="false" /> --> tools:node="remove">
</service>
<meta-data <meta-data
android:name="eu.twonly.service.TWONLY_LOGO" android:name="eu.twonly.service.TWONLY_LOGO"
android:resource="@drawable/ic_launcher_foreground" /> android:resource="@drawable/ic_launcher_foreground" />
</application> </application>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/> <uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.CAMERA"/>
@ -53,6 +68,7 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="com.android.vending.BILLING" />
<!-- Required to query activities that can process text, see: <!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and https://developer.android.com/training/package-visibility and

View file

@ -1,12 +1,27 @@
package eu.twonly package eu.twonly
import android.content.ContentValues
import android.content.Context
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import io.flutter.embedding.android.FlutterFragmentActivity import io.flutter.embedding.android.FlutterFragmentActivity
import android.view.KeyEvent import android.view.KeyEvent
import dev.darttools.flutter_android_volume_keydown.FlutterAndroidVolumeKeydownPlugin.eventSink import dev.darttools.flutter_android_volume_keydown.FlutterAndroidVolumeKeydownPlugin.eventSink
import android.view.KeyEvent.KEYCODE_VOLUME_DOWN import android.view.KeyEvent.KEYCODE_VOLUME_DOWN
import android.view.KeyEvent.KEYCODE_VOLUME_UP import android.view.KeyEvent.KEYCODE_VOLUME_UP
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
import java.io.OutputStream
class MainActivity : FlutterFragmentActivity() { class MainActivity : FlutterFragmentActivity() {
private val MEDIA_STORE_CHANNEL = "eu.twonly/mediaStore"
private lateinit var channel: MethodChannel
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
if (keyCode == KEYCODE_VOLUME_DOWN && eventSink != null) { if (keyCode == KEYCODE_VOLUME_DOWN && eventSink != null) {
eventSink!!.success(true) eventSink!!.success(true)
@ -18,4 +33,84 @@ class MainActivity : FlutterFragmentActivity() {
} }
return super.onKeyDown(keyCode, event) return super.onKeyDown(keyCode, event)
} }
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, MEDIA_STORE_CHANNEL)
channel.setMethodCallHandler {call, result ->
try {
if (call.method == "safeFileToDownload") {
val arguments = call.arguments<Map<String, String>>() as Map<String, String>
val sourceFile = arguments["sourceFile"]
if (sourceFile == null) {
result.success(false)
} else {
val context = applicationContext
val inputStream = FileInputStream(File(sourceFile))
val outputName = File(sourceFile).name.takeIf { it.isNotEmpty() } ?: "memories.zip"
val savedUri = saveZipToDownloads(context, outputName, inputStream)
if (savedUri != null) {
result.success(savedUri.toString())
} else {
result.error("SAVE_FAILED", "Could not save ZIP", null)
}
}
} else {
result.notImplemented()
}
} catch (e: Exception) {
result.error("EXCEPTION", e.message, null)
}
}
}
}
fun saveZipToDownloads(
context: Context,
fileName: String = "archive.zip",
sourceStream: InputStream
): android.net.Uri? {
val resolver = context.contentResolver
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
put(MediaStore.MediaColumns.MIME_TYPE, "application/zip")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
put(MediaStore.MediaColumns.IS_PENDING, 1)
}
}
val collection = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
} else {
MediaStore.Files.getContentUri("external")
}
val uri = resolver.insert(collection, contentValues) ?: return null
try {
resolver.openOutputStream(uri).use { out: OutputStream? ->
requireNotNull(out) { "Unable to open output stream" }
sourceStream.use { input ->
input.copyTo(out)
}
out.flush()
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val done = ContentValues().apply { put(MediaStore.MediaColumns.IS_PENDING, 0) }
resolver.update(uri, done, null, null)
}
return uri
} catch (e: Exception) {
try { resolver.delete(uri, null, null) } catch (_: Exception) {}
return null
}
} }

View file

@ -0,0 +1,6 @@
package eu.twonly
class MyMediaStorageProxy {
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View file

@ -6,4 +6,9 @@
android:drawable="@drawable/ic_launcher_foreground" android:drawable="@drawable/ic_launcher_foreground"
android:inset="16%" /> android:inset="16%" />
</foreground> </foreground>
<monochrome>
<inset
android:drawable="@drawable/ic_launcher_monochrome"
android:inset="16%" />
</monochrome>
</adaptive-icon> </adaptive-icon>

View file

@ -8,4 +8,5 @@
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.CAMERA"/>
<application android:usesCleartextTraffic="true" > <application android:usesCleartextTraffic="true" >
</application> </application>
<meta-data android:name="firebase_performance_collection_deactivated" android:value="true" />
</manifest> </manifest>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
5cde0a78d118f9e043e7443ceca0f306

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

View file

@ -12,3 +12,4 @@ targets:
databases: databases:
twonly_db: lib/src/database/twonly.db.dart twonly_db: lib/src/database/twonly.db.dart
twonly_database: lib/src/database/twonly_database_old.dart twonly_database: lib/src/database/twonly_database_old.dart
schema_dir: lib/src/database/schemas

1
dependencies Submodule

@ -0,0 +1 @@
Subproject commit 7930d9727019344238297d810661bc3e8f724c37

@ -1 +0,0 @@
Subproject commit ba65f2fb4a09f4e68f6de64aa1de41ba3dc4977e

View file

@ -209,11 +209,11 @@ func getPushNotificationText(pushNotification: PushNotification) -> (String, Str
let systemLanguage = Locale.current.language.languageCode?.identifier ?? "en" // Get the current system language let systemLanguage = Locale.current.language.languageCode?.identifier ?? "en" // Get the current system language
var pushNotificationText: [PushKind: String] = [:] var pushNotificationText: [PushKind: String] = [:]
var title = "Someone" var title = "[Unknown]"
// Define the messages based on the system language // Define the messages based on the system language
if systemLanguage.contains("de") { // German if systemLanguage.contains("de") { // German
title = "Jemand" title = "[Unbekannt]"
pushNotificationText = [ pushNotificationText = [
.text: "hat eine Nachricht{inGroup} gesendet.", .text: "hat eine Nachricht{inGroup} gesendet.",
.twonly: "hat ein twonly{inGroup} gesendet.", .twonly: "hat ein twonly{inGroup} gesendet.",
@ -238,7 +238,7 @@ func getPushNotificationText(pushNotification: PushNotification) -> (String, Str
.text: "sent a message{inGroup}.", .text: "sent a message{inGroup}.",
.twonly: "sent a twonly{inGroup}.", .twonly: "sent a twonly{inGroup}.",
.video: "sent a video{inGroup}.", .video: "sent a video{inGroup}.",
.image: "sent a image{inGroup}.", .image: "sent an image{inGroup}.",
.audio: "sent a voice message{inGroup}.", .audio: "sent a voice message{inGroup}.",
.contactRequest: "wants to connect with you.", .contactRequest: "wants to connect with you.",
.acceptRequest: "is now connected with you.", .acceptRequest: "is now connected with you.",

View file

@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project # Uncomment this line to define a global platform for your project
platform :ios, '15.0' platform :ios, '15.5'
use_frameworks! use_frameworks!
# CocoaPods analytics sends network stats synchronously affecting flutter build latency. # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
@ -43,6 +43,13 @@ target 'Runner' do
target 'RunnerTests' do target 'RunnerTests' do
inherit! :search_paths inherit! :search_paths
end end
# Share Extension is name of Extension which you created which is in this case 'Share Extension'
target 'ShareExtension' do
inherit! :search_paths
# flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end
end end
post_install do |installer| post_install do |installer|

View file

@ -1,4 +1,6 @@
PODS: PODS:
- app_links (7.0.0):
- Flutter
- audio_waveforms (0.0.1): - audio_waveforms (0.0.1):
- Flutter - Flutter
- background_downloader (0.0.1): - background_downloader (0.0.1):
@ -11,6 +13,37 @@ PODS:
- Flutter - Flutter
- device_info_plus (0.0.1): - device_info_plus (0.0.1):
- Flutter - 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
- emoji_picker_flutter (0.0.1): - emoji_picker_flutter (0.0.1):
- Flutter - Flutter
- ffmpeg_kit_flutter_new (1.0.0): - ffmpeg_kit_flutter_new (1.0.0):
@ -18,55 +51,58 @@ PODS:
- Flutter - Flutter
- ffmpeg_kit_flutter_new/full-gpl (1.0.0): - ffmpeg_kit_flutter_new/full-gpl (1.0.0):
- Flutter - Flutter
- Firebase (12.4.0): - file_picker (0.0.1):
- Firebase/Core (= 12.4.0) - DKImagePickerController/PhotoGallery
- Firebase/Core (12.4.0):
- Firebase/CoreOnly
- FirebaseAnalytics (~> 12.4.0)
- Firebase/CoreOnly (12.4.0):
- FirebaseCore (~> 12.4.0)
- Firebase/Messaging (12.4.0):
- Firebase/CoreOnly
- FirebaseMessaging (~> 12.4.0)
- firebase_core (4.2.1):
- Firebase/CoreOnly (= 12.4.0)
- Flutter - Flutter
- firebase_messaging (16.0.4): - Firebase (12.6.0):
- Firebase/Messaging (= 12.4.0) - Firebase/Core (= 12.6.0)
- Firebase/Core (12.6.0):
- Firebase/CoreOnly
- FirebaseAnalytics (~> 12.6.0)
- Firebase/CoreOnly (12.6.0):
- FirebaseCore (~> 12.6.0)
- Firebase/Messaging (12.6.0):
- Firebase/CoreOnly
- FirebaseMessaging (~> 12.6.0)
- firebase_core (4.3.0):
- Firebase/CoreOnly (= 12.6.0)
- Flutter
- firebase_messaging (16.1.0):
- Firebase/Messaging (= 12.6.0)
- firebase_core - firebase_core
- Flutter - Flutter
- FirebaseAnalytics (12.4.0): - FirebaseAnalytics (12.6.0):
- FirebaseAnalytics/Default (= 12.4.0) - FirebaseAnalytics/Default (= 12.6.0)
- FirebaseCore (~> 12.4.0) - FirebaseCore (~> 12.6.0)
- FirebaseInstallations (~> 12.4.0) - FirebaseInstallations (~> 12.6.0)
- GoogleUtilities/AppDelegateSwizzler (~> 8.1) - GoogleUtilities/AppDelegateSwizzler (~> 8.1)
- GoogleUtilities/MethodSwizzler (~> 8.1) - GoogleUtilities/MethodSwizzler (~> 8.1)
- GoogleUtilities/Network (~> 8.1) - GoogleUtilities/Network (~> 8.1)
- "GoogleUtilities/NSData+zlib (~> 8.1)" - "GoogleUtilities/NSData+zlib (~> 8.1)"
- nanopb (~> 3.30910.0) - nanopb (~> 3.30910.0)
- FirebaseAnalytics/Default (12.4.0): - FirebaseAnalytics/Default (12.6.0):
- FirebaseCore (~> 12.4.0) - FirebaseCore (~> 12.6.0)
- FirebaseInstallations (~> 12.4.0) - FirebaseInstallations (~> 12.6.0)
- GoogleAppMeasurement/Default (= 12.4.0) - GoogleAppMeasurement/Default (= 12.6.0)
- GoogleUtilities/AppDelegateSwizzler (~> 8.1) - GoogleUtilities/AppDelegateSwizzler (~> 8.1)
- GoogleUtilities/MethodSwizzler (~> 8.1) - GoogleUtilities/MethodSwizzler (~> 8.1)
- GoogleUtilities/Network (~> 8.1) - GoogleUtilities/Network (~> 8.1)
- "GoogleUtilities/NSData+zlib (~> 8.1)" - "GoogleUtilities/NSData+zlib (~> 8.1)"
- nanopb (~> 3.30910.0) - nanopb (~> 3.30910.0)
- FirebaseCore (12.4.0): - FirebaseCore (12.6.0):
- FirebaseCoreInternal (~> 12.4.0) - FirebaseCoreInternal (~> 12.6.0)
- GoogleUtilities/Environment (~> 8.1) - GoogleUtilities/Environment (~> 8.1)
- GoogleUtilities/Logger (~> 8.1) - GoogleUtilities/Logger (~> 8.1)
- FirebaseCoreInternal (12.4.0): - FirebaseCoreInternal (12.6.0):
- "GoogleUtilities/NSData+zlib (~> 8.1)" - "GoogleUtilities/NSData+zlib (~> 8.1)"
- FirebaseInstallations (12.4.0): - FirebaseInstallations (12.6.0):
- FirebaseCore (~> 12.4.0) - FirebaseCore (~> 12.6.0)
- GoogleUtilities/Environment (~> 8.1) - GoogleUtilities/Environment (~> 8.1)
- GoogleUtilities/UserDefaults (~> 8.1) - GoogleUtilities/UserDefaults (~> 8.1)
- PromisesObjC (~> 2.4) - PromisesObjC (~> 2.4)
- FirebaseMessaging (12.4.0): - FirebaseMessaging (12.6.0):
- FirebaseCore (~> 12.4.0) - FirebaseCore (~> 12.6.0)
- FirebaseInstallations (~> 12.4.0) - FirebaseInstallations (~> 12.6.0)
- GoogleDataTransport (~> 10.1) - GoogleDataTransport (~> 10.1)
- GoogleUtilities/AppDelegateSwizzler (~> 8.1) - GoogleUtilities/AppDelegateSwizzler (~> 8.1)
- GoogleUtilities/Environment (~> 8.1) - GoogleUtilities/Environment (~> 8.1)
@ -86,35 +122,42 @@ PODS:
- flutter_secure_storage_darwin (10.0.0): - flutter_secure_storage_darwin (10.0.0):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
- flutter_volume_controller (0.0.1): - flutter_sharing_intent (1.0.1):
- Flutter - Flutter
- flutter_zxing (0.0.1): - flutter_volume_controller (0.0.1):
- Flutter - Flutter
- gal (1.0.0): - gal (1.0.0):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
- GoogleAdsOnDeviceConversion (3.1.0): - google_mlkit_barcode_scanning (0.14.1):
- Flutter
- google_mlkit_commons
- GoogleMLKit/BarcodeScanning (~> 7.0.0)
- google_mlkit_commons (0.11.0):
- Flutter
- MLKitVision
- GoogleAdsOnDeviceConversion (3.2.0):
- GoogleUtilities/Environment (~> 8.1) - GoogleUtilities/Environment (~> 8.1)
- GoogleUtilities/Logger (~> 8.1) - GoogleUtilities/Logger (~> 8.1)
- GoogleUtilities/Network (~> 8.1) - GoogleUtilities/Network (~> 8.1)
- nanopb (~> 3.30910.0) - nanopb (~> 3.30910.0)
- GoogleAppMeasurement/Core (12.4.0): - GoogleAppMeasurement/Core (12.6.0):
- GoogleUtilities/AppDelegateSwizzler (~> 8.1) - GoogleUtilities/AppDelegateSwizzler (~> 8.1)
- GoogleUtilities/MethodSwizzler (~> 8.1) - GoogleUtilities/MethodSwizzler (~> 8.1)
- GoogleUtilities/Network (~> 8.1) - GoogleUtilities/Network (~> 8.1)
- "GoogleUtilities/NSData+zlib (~> 8.1)" - "GoogleUtilities/NSData+zlib (~> 8.1)"
- nanopb (~> 3.30910.0) - nanopb (~> 3.30910.0)
- GoogleAppMeasurement/Default (12.4.0): - GoogleAppMeasurement/Default (12.6.0):
- GoogleAdsOnDeviceConversion (~> 3.1.0) - GoogleAdsOnDeviceConversion (~> 3.2.0)
- GoogleAppMeasurement/Core (= 12.4.0) - GoogleAppMeasurement/Core (= 12.6.0)
- GoogleAppMeasurement/IdentitySupport (= 12.4.0) - GoogleAppMeasurement/IdentitySupport (= 12.6.0)
- GoogleUtilities/AppDelegateSwizzler (~> 8.1) - GoogleUtilities/AppDelegateSwizzler (~> 8.1)
- GoogleUtilities/MethodSwizzler (~> 8.1) - GoogleUtilities/MethodSwizzler (~> 8.1)
- GoogleUtilities/Network (~> 8.1) - GoogleUtilities/Network (~> 8.1)
- "GoogleUtilities/NSData+zlib (~> 8.1)" - "GoogleUtilities/NSData+zlib (~> 8.1)"
- nanopb (~> 3.30910.0) - nanopb (~> 3.30910.0)
- GoogleAppMeasurement/IdentitySupport (12.4.0): - GoogleAppMeasurement/IdentitySupport (12.6.0):
- GoogleAppMeasurement/Core (= 12.4.0) - GoogleAppMeasurement/Core (= 12.6.0)
- GoogleUtilities/AppDelegateSwizzler (~> 8.1) - GoogleUtilities/AppDelegateSwizzler (~> 8.1)
- GoogleUtilities/MethodSwizzler (~> 8.1) - GoogleUtilities/MethodSwizzler (~> 8.1)
- GoogleUtilities/Network (~> 8.1) - GoogleUtilities/Network (~> 8.1)
@ -123,6 +166,16 @@ PODS:
- GoogleDataTransport (10.1.0): - GoogleDataTransport (10.1.0):
- nanopb (~> 3.30910.0) - nanopb (~> 3.30910.0)
- PromisesObjC (~> 2.4) - PromisesObjC (~> 2.4)
- GoogleMLKit/BarcodeScanning (7.0.0):
- GoogleMLKit/MLKitCore
- MLKitBarcodeScanning (~> 6.0.0)
- GoogleMLKit/MLKitCore (7.0.0):
- MLKitCommon (~> 12.0.0)
- GoogleToolboxForMac/Defines (4.2.1)
- GoogleToolboxForMac/Logger (4.2.1):
- GoogleToolboxForMac/Defines (= 4.2.1)
- "GoogleToolboxForMac/NSData+zlib (4.2.1)":
- GoogleToolboxForMac/Defines (= 4.2.1)
- GoogleUtilities (8.1.0): - GoogleUtilities (8.1.0):
- GoogleUtilities/AppDelegateSwizzler (= 8.1.0) - GoogleUtilities/AppDelegateSwizzler (= 8.1.0)
- GoogleUtilities/Environment (= 8.1.0) - GoogleUtilities/Environment (= 8.1.0)
@ -163,8 +216,12 @@ PODS:
- GoogleUtilities/UserDefaults (8.1.0): - GoogleUtilities/UserDefaults (8.1.0):
- GoogleUtilities/Logger - GoogleUtilities/Logger
- GoogleUtilities/Privacy - GoogleUtilities/Privacy
- GTMSessionFetcher/Core (3.5.0)
- image_picker_ios (0.0.1): - image_picker_ios (0.0.1):
- Flutter - Flutter
- in_app_purchase_storekit (0.0.1):
- Flutter
- FlutterMacOS
- libwebp (1.5.0): - libwebp (1.5.0):
- libwebp/demux (= 1.5.0) - libwebp/demux (= 1.5.0)
- libwebp/mux (= 1.5.0) - libwebp/mux (= 1.5.0)
@ -183,12 +240,29 @@ PODS:
- Mantle (2.2.0): - Mantle (2.2.0):
- Mantle/extobjc (= 2.2.0) - Mantle/extobjc (= 2.2.0)
- Mantle/extobjc (2.2.0) - Mantle/extobjc (2.2.0)
- MLImage (1.0.0-beta6)
- MLKitBarcodeScanning (6.0.0):
- MLKitCommon (~> 12.0)
- MLKitVision (~> 8.0)
- MLKitCommon (12.0.0):
- GoogleDataTransport (~> 10.0)
- GoogleToolboxForMac/Logger (< 5.0, >= 4.2.1)
- "GoogleToolboxForMac/NSData+zlib (< 5.0, >= 4.2.1)"
- GoogleUtilities/Logger (~> 8.0)
- GoogleUtilities/UserDefaults (~> 8.0)
- GTMSessionFetcher/Core (< 4.0, >= 3.3.2)
- MLKitVision (8.0.0):
- GoogleToolboxForMac/Logger (< 5.0, >= 4.2.1)
- "GoogleToolboxForMac/NSData+zlib (< 5.0, >= 4.2.1)"
- GTMSessionFetcher/Core (< 4.0, >= 3.3.2)
- MLImage (= 1.0.0-beta6)
- MLKitCommon (~> 12.0)
- nanopb (3.30910.0): - nanopb (3.30910.0):
- nanopb/decode (= 3.30910.0) - nanopb/decode (= 3.30910.0)
- nanopb/encode (= 3.30910.0) - nanopb/encode (= 3.30910.0)
- nanopb/decode (3.30910.0) - nanopb/decode (3.30910.0)
- nanopb/encode (3.30910.0) - nanopb/encode (3.30910.0)
- "no_screenshot (0.0.1+4)": - no_screenshot (0.3.2-beta.3):
- Flutter - Flutter
- ScreenProtectorKit (~> 1.3.1) - ScreenProtectorKit (~> 1.3.1)
- objective_c (0.0.1): - objective_c (0.0.1):
@ -204,10 +278,10 @@ PODS:
- restart_app (0.0.1): - restart_app (0.0.1):
- Flutter - Flutter
- ScreenProtectorKit (1.3.1) - ScreenProtectorKit (1.3.1)
- SDWebImage (5.21.3): - SDWebImage (5.21.5):
- SDWebImage/Core (= 5.21.3) - SDWebImage/Core (= 5.21.5)
- SDWebImage/Core (5.21.3) - SDWebImage/Core (5.21.5)
- SDWebImageWebPCoder (0.14.6): - SDWebImageWebPCoder (0.15.0):
- libwebp (~> 1.0) - libwebp (~> 1.0)
- SDWebImage/Core (~> 5.17) - SDWebImage/Core (~> 5.17)
- Sentry/HybridSDK (8.56.2) - Sentry/HybridSDK (8.56.2)
@ -248,7 +322,8 @@ PODS:
- sqlite3/perf-threadsafe - sqlite3/perf-threadsafe
- sqlite3/rtree - sqlite3/rtree
- sqlite3/session - sqlite3/session
- SwiftProtobuf (1.33.1) - SwiftProtobuf (1.33.3)
- SwiftyGif (5.4.5)
- url_launcher_ios (0.0.1): - url_launcher_ios (0.0.1):
- Flutter - Flutter
- video_player_avfoundation (0.0.1): - video_player_avfoundation (0.0.1):
@ -256,6 +331,7 @@ PODS:
- FlutterMacOS - FlutterMacOS
DEPENDENCIES: DEPENDENCIES:
- app_links (from `.symlinks/plugins/app_links/ios`)
- audio_waveforms (from `.symlinks/plugins/audio_waveforms/ios`) - audio_waveforms (from `.symlinks/plugins/audio_waveforms/ios`)
- background_downloader (from `.symlinks/plugins/background_downloader/ios`) - background_downloader (from `.symlinks/plugins/background_downloader/ios`)
- camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`) - camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`)
@ -264,6 +340,7 @@ DEPENDENCIES:
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
- emoji_picker_flutter (from `.symlinks/plugins/emoji_picker_flutter/ios`) - emoji_picker_flutter (from `.symlinks/plugins/emoji_picker_flutter/ios`)
- ffmpeg_kit_flutter_new (from `.symlinks/plugins/ffmpeg_kit_flutter_new/ios`) - ffmpeg_kit_flutter_new (from `.symlinks/plugins/ffmpeg_kit_flutter_new/ios`)
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- Firebase - Firebase
- firebase_core (from `.symlinks/plugins/firebase_core/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`)
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
@ -275,11 +352,14 @@ DEPENDENCIES:
- flutter_keyboard_visibility_temp_fork (from `.symlinks/plugins/flutter_keyboard_visibility_temp_fork/ios`) - flutter_keyboard_visibility_temp_fork (from `.symlinks/plugins/flutter_keyboard_visibility_temp_fork/ios`)
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/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`)
- flutter_sharing_intent (from `.symlinks/plugins/flutter_sharing_intent/ios`)
- flutter_volume_controller (from `.symlinks/plugins/flutter_volume_controller/ios`) - flutter_volume_controller (from `.symlinks/plugins/flutter_volume_controller/ios`)
- flutter_zxing (from `.symlinks/plugins/flutter_zxing/ios`)
- gal (from `.symlinks/plugins/gal/darwin`) - gal (from `.symlinks/plugins/gal/darwin`)
- google_mlkit_barcode_scanning (from `.symlinks/plugins/google_mlkit_barcode_scanning/ios`)
- google_mlkit_commons (from `.symlinks/plugins/google_mlkit_commons/ios`)
- GoogleUtilities - GoogleUtilities
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- in_app_purchase_storekit (from `.symlinks/plugins/in_app_purchase_storekit/darwin`)
- local_auth_darwin (from `.symlinks/plugins/local_auth_darwin/darwin`) - local_auth_darwin (from `.symlinks/plugins/local_auth_darwin/darwin`)
- no_screenshot (from `.symlinks/plugins/no_screenshot/ios`) - no_screenshot (from `.symlinks/plugins/no_screenshot/ios`)
- objective_c (from `.symlinks/plugins/objective_c/ios`) - objective_c (from `.symlinks/plugins/objective_c/ios`)
@ -298,6 +378,8 @@ DEPENDENCIES:
SPEC REPOS: SPEC REPOS:
trunk: trunk:
- DKImagePickerController
- DKPhotoGallery
- Firebase - Firebase
- FirebaseAnalytics - FirebaseAnalytics
- FirebaseCore - FirebaseCore
@ -307,9 +389,16 @@ SPEC REPOS:
- GoogleAdsOnDeviceConversion - GoogleAdsOnDeviceConversion
- GoogleAppMeasurement - GoogleAppMeasurement
- GoogleDataTransport - GoogleDataTransport
- GoogleMLKit
- GoogleToolboxForMac
- GoogleUtilities - GoogleUtilities
- GTMSessionFetcher
- libwebp - libwebp
- Mantle - Mantle
- MLImage
- MLKitBarcodeScanning
- MLKitCommon
- MLKitVision
- nanopb - nanopb
- PromisesObjC - PromisesObjC
- ScreenProtectorKit - ScreenProtectorKit
@ -318,8 +407,11 @@ SPEC REPOS:
- Sentry - Sentry
- sqlite3 - sqlite3
- SwiftProtobuf - SwiftProtobuf
- SwiftyGif
EXTERNAL SOURCES: EXTERNAL SOURCES:
app_links:
:path: ".symlinks/plugins/app_links/ios"
audio_waveforms: audio_waveforms:
:path: ".symlinks/plugins/audio_waveforms/ios" :path: ".symlinks/plugins/audio_waveforms/ios"
background_downloader: background_downloader:
@ -336,6 +428,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/emoji_picker_flutter/ios" :path: ".symlinks/plugins/emoji_picker_flutter/ios"
ffmpeg_kit_flutter_new: ffmpeg_kit_flutter_new:
:path: ".symlinks/plugins/ffmpeg_kit_flutter_new/ios" :path: ".symlinks/plugins/ffmpeg_kit_flutter_new/ios"
file_picker:
:path: ".symlinks/plugins/file_picker/ios"
firebase_core: firebase_core:
:path: ".symlinks/plugins/firebase_core/ios" :path: ".symlinks/plugins/firebase_core/ios"
firebase_messaging: firebase_messaging:
@ -350,14 +444,20 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/flutter_local_notifications/ios" :path: ".symlinks/plugins/flutter_local_notifications/ios"
flutter_secure_storage_darwin: flutter_secure_storage_darwin:
:path: ".symlinks/plugins/flutter_secure_storage_darwin/darwin" :path: ".symlinks/plugins/flutter_secure_storage_darwin/darwin"
flutter_sharing_intent:
:path: ".symlinks/plugins/flutter_sharing_intent/ios"
flutter_volume_controller: flutter_volume_controller:
:path: ".symlinks/plugins/flutter_volume_controller/ios" :path: ".symlinks/plugins/flutter_volume_controller/ios"
flutter_zxing:
:path: ".symlinks/plugins/flutter_zxing/ios"
gal: gal:
:path: ".symlinks/plugins/gal/darwin" :path: ".symlinks/plugins/gal/darwin"
google_mlkit_barcode_scanning:
:path: ".symlinks/plugins/google_mlkit_barcode_scanning/ios"
google_mlkit_commons:
:path: ".symlinks/plugins/google_mlkit_commons/ios"
image_picker_ios: image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios" :path: ".symlinks/plugins/image_picker_ios/ios"
in_app_purchase_storekit:
:path: ".symlinks/plugins/in_app_purchase_storekit/darwin"
local_auth_darwin: local_auth_darwin:
:path: ".symlinks/plugins/local_auth_darwin/darwin" :path: ".symlinks/plugins/local_auth_darwin/darwin"
no_screenshot: no_screenshot:
@ -388,40 +488,54 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/video_player_avfoundation/darwin" :path: ".symlinks/plugins/video_player_avfoundation/darwin"
SPEC CHECKSUMS: SPEC CHECKSUMS:
app_links: a754cbec3c255bd4bbb4d236ecc06f28cd9a7ce8
audio_waveforms: a6dde7fe7c0ea05f06ffbdb0f7c1b2b2ba6cedcf audio_waveforms: a6dde7fe7c0ea05f06ffbdb0f7c1b2b2ba6cedcf
background_downloader: 50e91d979067b82081aba359d7d916b3ba5fadad background_downloader: 50e91d979067b82081aba359d7d916b3ba5fadad
camera_avfoundation: 5675ca25298b6f81fa0a325188e7df62cc217741 camera_avfoundation: 5675ca25298b6f81fa0a325188e7df62cc217741
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
cryptography_flutter_plus: 44f4e9e4079395fcbb3e7809c0ac2c6ae2d9576f cryptography_flutter_plus: 44f4e9e4079395fcbb3e7809c0ac2c6ae2d9576f
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
emoji_picker_flutter: ece213fc274bdddefb77d502d33080dc54e616cc emoji_picker_flutter: ece213fc274bdddefb77d502d33080dc54e616cc
ffmpeg_kit_flutter_new: 12426a19f10ac81186c67c6ebc4717f8f4364b7f ffmpeg_kit_flutter_new: 12426a19f10ac81186c67c6ebc4717f8f4364b7f
Firebase: f07b15ae5a6ec0f93713e30b923d9970d144af3e file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
firebase_core: f1aafb21c14f497e5498f7ffc4dc63cbb52b2594 Firebase: a451a7b61536298fd5cbfe3a746fd40443a50679
firebase_messaging: c17a29984eafce4b2997fe078bb0a9e0b06f5dde firebase_core: ba00a168e719694f38960502ceb560285603d073
FirebaseAnalytics: 0fc2b20091f0ddd21bf73397cf8f0eb5346dc24f firebase_messaging: bf0e29321927edc02a563c984dbfa5b063864b15
FirebaseCore: bb595f3114953664e3c1dc032f008a244147cfd3 FirebaseAnalytics: d0a97a0db6425e5a5d966340b87f92ca7b13a557
FirebaseCoreInternal: d7f5a043c2cd01a08103ab586587c1468047bca6 FirebaseCore: 0e38ad5d62d980a47a64b8e9301ffa311457be04
FirebaseInstallations: ae9f4902cb5bf1d0c5eaa31ec1f4e5495a0714e2 FirebaseCoreInternal: 69bf1306a05b8ac43004f6cc1f804bb7b05b229e
FirebaseMessaging: d33971b7bb252745ea6cd31ab190d1a1df4b8ed5 FirebaseInstallations: 631b38da2e11a83daa4bfb482f79d286a5dfa7ad
FirebaseMessaging: a61bc42dcab3f7a346d94bbb54dab2c9435b18b2
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1 flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1
flutter_keyboard_visibility_temp_fork: 95b2d534bacf6ac62e7fcbe5c2a9e2c2a17ce06f flutter_keyboard_visibility_temp_fork: 95b2d534bacf6ac62e7fcbe5c2a9e2c2a17ce06f
flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb
flutter_secure_storage_darwin: ce237a8775b39723566dc72571190a3769d70468 flutter_secure_storage_darwin: acdb3f316ed05a3e68f856e0353b133eec373a23
flutter_sharing_intent: 0c1e53949f09fa8df8ac2268505687bde8ff264c
flutter_volume_controller: c2be490cb0487e8b88d0d9fc2b7e1c139a4ebccb flutter_volume_controller: c2be490cb0487e8b88d0d9fc2b7e1c139a4ebccb
flutter_zxing: e8bcc43bd3056c70c271b732ed94e7a16fd62f93
gal: baecd024ebfd13c441269ca7404792a7152fde89 gal: baecd024ebfd13c441269ca7404792a7152fde89
GoogleAdsOnDeviceConversion: e03a386840803ea7eef3fd22a061930142c039c1 google_mlkit_barcode_scanning: 8f5987f244a43fe1167689c548342a5174108159
GoogleAppMeasurement: 1e718274b7e015cefd846ac1fcf7820c70dc017d google_mlkit_commons: 2abe6a70e1824e431d16a51085cb475b672c8aab
GoogleAdsOnDeviceConversion: d68c69dd9581a0f5da02617b6f377e5be483970f
GoogleAppMeasurement: 3bf40aff49a601af5da1c3345702fcb4991d35ee
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
GoogleMLKit: eff9e23ec1d90ea4157a1ee2e32a4f610c5b3318
GoogleToolboxForMac: d1a2cbf009c453f4d6ded37c105e2f67a32206d8
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6
image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326 image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326
in_app_purchase_storekit: 22cca7d08eebca9babdf4d07d0baccb73325d3c8
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8 libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
local_auth_darwin: c3ee6cce0a8d56be34c8ccb66ba31f7f180aaebb local_auth_darwin: c3ee6cce0a8d56be34c8ccb66ba31f7f180aaebb
Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d
MLImage: 0ad1c5f50edd027672d8b26b0fee78a8b4a0fc56
MLKitBarcodeScanning: 0a3064da0a7f49ac24ceb3cb46a5bc67496facd2
MLKitCommon: 07c2c33ae5640e5380beaaa6e4b9c249a205542d
MLKitVision: 45e79d68845a2de77e2dd4d7f07947f0ed157b0e
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
no_screenshot: 6d183496405a3ab709a67a54e5cd0f639e94729e no_screenshot: 89e778ede9f1e39cc3fb9404d782a42712f2a0b2
objective_c: 89e720c30d716b036faf9c9684022048eee1eee2 objective_c: 89e720c30d716b036faf9c9684022048eee1eee2
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880 path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
@ -429,8 +543,8 @@ SPEC CHECKSUMS:
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
restart_app: 9cda5378aacc5000e3f66ee76a9201534e7d3ecf restart_app: 9cda5378aacc5000e3f66ee76a9201534e7d3ecf
ScreenProtectorKit: 83a6281b02c7a5902ee6eac4f5045f674e902ae4 ScreenProtectorKit: 83a6281b02c7a5902ee6eac4f5045f674e902ae4
SDWebImage: 16309af6d214ba3f77a7c6f6fdda888cb313a50a SDWebImage: e9c98383c7572d713c1a0d7dd2783b10599b9838
SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380 SDWebImageWebPCoder: 0e06e365080397465cc73a7a9b472d8a3bd0f377
Sentry: b53951377b78e21a734f5dc8318e333dbfc682d7 Sentry: b53951377b78e21a734f5dc8318e333dbfc682d7
sentry_flutter: 4c33648b7e83310aa1fdb1b10c5491027d9643f0 sentry_flutter: 4c33648b7e83310aa1fdb1b10c5491027d9643f0
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
@ -438,10 +552,11 @@ SPEC CHECKSUMS:
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
sqlite3: 73513155ec6979715d3904ef53a8d68892d4032b sqlite3: 73513155ec6979715d3904ef53a8d68892d4032b
sqlite3_flutter_libs: 83f8e9f5b6554077f1d93119fe20ebaa5f3a9ef1 sqlite3_flutter_libs: 83f8e9f5b6554077f1d93119fe20ebaa5f3a9ef1
SwiftProtobuf: 533a18409c3ca3a6156b2b1e46afd0f69e751aba SwiftProtobuf: e1b437c8e31a4c5577b643249a0bb62ed4f02153
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
video_player_avfoundation: dd410b52df6d2466a42d28550e33e4146928280a video_player_avfoundation: dd410b52df6d2466a42d28550e33e4146928280a
PODFILE CHECKSUM: 47470fbd5b59affa461eaf943ac57acce81e0ee8 PODFILE CHECKSUM: ae041999f13ba7b2285ff9ad9bc688ed647bbcb7
COCOAPODS: 1.16.2 COCOAPODS: 1.16.2

View file

@ -10,6 +10,7 @@
05CF222065FC24670B05B6D0 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1EE71614E1B4F84D6FDC2D /* Pods_RunnerTests.framework */; }; 05CF222065FC24670B05B6D0 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1EE71614E1B4F84D6FDC2D /* Pods_RunnerTests.framework */; };
06AA21445BEAF2C45DC9DCDF /* Pods_NotificationService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A198C9B5D90584C4F96206B2 /* Pods_NotificationService.framework */; }; 06AA21445BEAF2C45DC9DCDF /* Pods_NotificationService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A198C9B5D90584C4F96206B2 /* Pods_NotificationService.framework */; };
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
30EBDD0F93DC44E774F3B785 /* Pods_ShareExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E190E82D9973B318A389650B /* Pods_ShareExtension.framework */; };
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 */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
@ -18,6 +19,8 @@
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
CA4FDF5DD8F229C30DE512AF /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EE2CCFEE4ABECF33852F7735 /* Pods_Runner.framework */; }; CA4FDF5DD8F229C30DE512AF /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EE2CCFEE4ABECF33852F7735 /* Pods_Runner.framework */; };
D21FCEAB2D9F2B750088701D /* NotificationService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D21FCEA42D9F2B750088701D /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; D21FCEAB2D9F2B750088701D /* NotificationService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D21FCEA42D9F2B750088701D /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
D25D4D1E2EF626E30029F805 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D25D4D1D2EF626E30029F805 /* StoreKit.framework */; };
D25D4D7A2EFF41DB0029F805 /* ShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D25D4D702EFF41DB0029F805 /* ShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
F3C66D726A2EB28484DF0B10 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 16FBC6F5B58E1C6646F5D447 /* GoogleService-Info.plist */; }; F3C66D726A2EB28484DF0B10 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 16FBC6F5B58E1C6646F5D447 /* GoogleService-Info.plist */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
@ -36,6 +39,13 @@
remoteGlobalIDString = D21FCEA32D9F2B750088701D; remoteGlobalIDString = D21FCEA32D9F2B750088701D;
remoteInfo = NotificationService; remoteInfo = NotificationService;
}; };
D25D4D782EFF41DB0029F805 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
proxyType = 1;
remoteGlobalIDString = D25D4D6F2EFF41DB0029F805;
remoteInfo = ShareExtension;
};
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
@ -55,6 +65,7 @@
dstPath = ""; dstPath = "";
dstSubfolderSpec = 13; dstSubfolderSpec = 13;
files = ( files = (
D25D4D7A2EFF41DB0029F805 /* ShareExtension.appex in Embed Foundation Extensions */,
D21FCEAB2D9F2B750088701D /* NotificationService.appex in Embed Foundation Extensions */, D21FCEAB2D9F2B750088701D /* NotificationService.appex in Embed Foundation Extensions */,
); );
name = "Embed Foundation Extensions"; name = "Embed Foundation Extensions";
@ -66,10 +77,12 @@
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>"; };
1581CC44342D555EFB889768 /* 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>"; }; 1581CC44342D555EFB889768 /* 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>"; };
15CEF849B61A620CFB2DC5F1 /* Pods-ShareExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShareExtension.debug.xcconfig"; path = "Target Support Files/Pods-ShareExtension/Pods-ShareExtension.debug.xcconfig"; sourceTree = "<group>"; };
16FBC6F5B58E1C6646F5D447 /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = "<group>"; }; 16FBC6F5B58E1C6646F5D447 /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = "<group>"; };
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; };
35366FD433E0EFC6EF19A452 /* Pods-NotificationService.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.release.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.release.xcconfig"; sourceTree = "<group>"; }; 35366FD433E0EFC6EF19A452 /* Pods-NotificationService.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.release.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.release.xcconfig"; sourceTree = "<group>"; };
39FB86A38393489D58A01B0B /* Pods-ShareExtension.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShareExtension.profile.xcconfig"; path = "Target Support Files/Pods-ShareExtension/Pods-ShareExtension.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>"; };
4D78471482626812FE2468E9 /* Pods-NotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.debug.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.debug.xcconfig"; sourceTree = "<group>"; }; 4D78471482626812FE2468E9 /* Pods-NotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.debug.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.debug.xcconfig"; sourceTree = "<group>"; };
6EB462F87F0A23758713308F /* 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>"; }; 6EB462F87F0A23758713308F /* 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>"; };
@ -86,10 +99,15 @@
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>"; };
A198C9B5D90584C4F96206B2 /* Pods_NotificationService.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_NotificationService.framework; sourceTree = BUILT_PRODUCTS_DIR; }; A198C9B5D90584C4F96206B2 /* Pods_NotificationService.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_NotificationService.framework; sourceTree = BUILT_PRODUCTS_DIR; };
A22BD564F16069E5FCB60767 /* Pods-ShareExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShareExtension.release.xcconfig"; path = "Target Support Files/Pods-ShareExtension/Pods-ShareExtension.release.xcconfig"; sourceTree = "<group>"; };
B3B27B7FBEEA31DB7793A0C2 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; }; B3B27B7FBEEA31DB7793A0C2 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
D21FCEA42D9F2B750088701D /* NotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; }; D21FCEA42D9F2B750088701D /* NotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; };
D2265DD42D920142000D99BB /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; }; D2265DD42D920142000D99BB /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
D25D4D1D2EF626E30029F805 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
D25D4D702EFF41DB0029F805 /* ShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
D25D4D802EFF437F0029F805 /* RunnerDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerDebug.entitlements; sourceTree = "<group>"; };
DC1EE71614E1B4F84D6FDC2D /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DC1EE71614E1B4F84D6FDC2D /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
E190E82D9973B318A389650B /* Pods_ShareExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ShareExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; };
E96A5ACA32A7118204F050A5 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; }; E96A5ACA32A7118204F050A5 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
EE2CCFEE4ABECF33852F7735 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; EE2CCFEE4ABECF33852F7735 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
F02F7A1D63544AA9F23A1085 /* Pods-NotificationService.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.profile.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.profile.xcconfig"; sourceTree = "<group>"; }; F02F7A1D63544AA9F23A1085 /* Pods-NotificationService.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.profile.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.profile.xcconfig"; sourceTree = "<group>"; };
@ -103,6 +121,13 @@
); );
target = D21FCEA32D9F2B750088701D /* NotificationService */; target = D21FCEA32D9F2B750088701D /* NotificationService */;
}; };
D25D4D7E2EFF41DB0029F805 /* Exceptions for "ShareExtension" folder in "ShareExtension" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Info.plist,
);
target = D25D4D6F2EFF41DB0029F805 /* ShareExtension */;
};
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
/* Begin PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFileSystemSynchronizedRootGroup section */
@ -114,6 +139,14 @@
path = NotificationService; path = NotificationService;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
D25D4D712EFF41DB0029F805 /* ShareExtension */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
D25D4D7E2EFF41DB0029F805 /* Exceptions for "ShareExtension" folder in "ShareExtension" target */,
);
path = ShareExtension;
sourceTree = "<group>";
};
/* End PBXFileSystemSynchronizedRootGroup section */ /* End PBXFileSystemSynchronizedRootGroup section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -130,6 +163,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
CA4FDF5DD8F229C30DE512AF /* Pods_Runner.framework in Frameworks */, CA4FDF5DD8F229C30DE512AF /* Pods_Runner.framework in Frameworks */,
D25D4D1E2EF626E30029F805 /* StoreKit.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -141,6 +175,14 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
D25D4D6D2EFF41DB0029F805 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
30EBDD0F93DC44E774F3B785 /* Pods_ShareExtension.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
@ -169,6 +211,7 @@
9740EEB11CF90186004384FC /* Flutter */, 9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */, 97C146F01CF9000F007C117D /* Runner */,
D21FCEA52D9F2B750088701D /* NotificationService */, D21FCEA52D9F2B750088701D /* NotificationService */,
D25D4D712EFF41DB0029F805 /* ShareExtension */,
97C146EF1CF9000F007C117D /* Products */, 97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */, 331C8082294A63A400263BE5 /* RunnerTests */,
16FBC6F5B58E1C6646F5D447 /* GoogleService-Info.plist */, 16FBC6F5B58E1C6646F5D447 /* GoogleService-Info.plist */,
@ -183,6 +226,7 @@
97C146EE1CF9000F007C117D /* Runner.app */, 97C146EE1CF9000F007C117D /* Runner.app */,
331C8081294A63A400263BE5 /* RunnerTests.xctest */, 331C8081294A63A400263BE5 /* RunnerTests.xctest */,
D21FCEA42D9F2B750088701D /* NotificationService.appex */, D21FCEA42D9F2B750088701D /* NotificationService.appex */,
D25D4D702EFF41DB0029F805 /* ShareExtension.appex */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@ -190,6 +234,7 @@
97C146F01CF9000F007C117D /* Runner */ = { 97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
D25D4D802EFF437F0029F805 /* RunnerDebug.entitlements */,
D2265DD42D920142000D99BB /* Runner.entitlements */, D2265DD42D920142000D99BB /* Runner.entitlements */,
97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FD1CF9000F007C117D /* Assets.xcassets */,
@ -206,9 +251,11 @@
E5079CCEE4804DB65AA3F23F /* Frameworks */ = { E5079CCEE4804DB65AA3F23F /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
D25D4D1D2EF626E30029F805 /* StoreKit.framework */,
A198C9B5D90584C4F96206B2 /* Pods_NotificationService.framework */, A198C9B5D90584C4F96206B2 /* Pods_NotificationService.framework */,
EE2CCFEE4ABECF33852F7735 /* Pods_Runner.framework */, EE2CCFEE4ABECF33852F7735 /* Pods_Runner.framework */,
DC1EE71614E1B4F84D6FDC2D /* Pods_RunnerTests.framework */, DC1EE71614E1B4F84D6FDC2D /* Pods_RunnerTests.framework */,
E190E82D9973B318A389650B /* Pods_ShareExtension.framework */,
); );
name = Frameworks; name = Frameworks;
sourceTree = "<group>"; sourceTree = "<group>";
@ -225,6 +272,9 @@
4D78471482626812FE2468E9 /* Pods-NotificationService.debug.xcconfig */, 4D78471482626812FE2468E9 /* Pods-NotificationService.debug.xcconfig */,
35366FD433E0EFC6EF19A452 /* Pods-NotificationService.release.xcconfig */, 35366FD433E0EFC6EF19A452 /* Pods-NotificationService.release.xcconfig */,
F02F7A1D63544AA9F23A1085 /* Pods-NotificationService.profile.xcconfig */, F02F7A1D63544AA9F23A1085 /* Pods-NotificationService.profile.xcconfig */,
15CEF849B61A620CFB2DC5F1 /* Pods-ShareExtension.debug.xcconfig */,
A22BD564F16069E5FCB60767 /* Pods-ShareExtension.release.xcconfig */,
39FB86A38393489D58A01B0B /* Pods-ShareExtension.profile.xcconfig */,
); );
path = Pods; path = Pods;
sourceTree = "<group>"; sourceTree = "<group>";
@ -270,6 +320,7 @@
); );
dependencies = ( dependencies = (
D21FCEAA2D9F2B750088701D /* PBXTargetDependency */, D21FCEAA2D9F2B750088701D /* PBXTargetDependency */,
D25D4D792EFF41DB0029F805 /* PBXTargetDependency */,
); );
name = Runner; name = Runner;
productName = Runner; productName = Runner;
@ -297,6 +348,27 @@
productReference = D21FCEA42D9F2B750088701D /* NotificationService.appex */; productReference = D21FCEA42D9F2B750088701D /* NotificationService.appex */;
productType = "com.apple.product-type.app-extension"; productType = "com.apple.product-type.app-extension";
}; };
D25D4D6F2EFF41DB0029F805 /* ShareExtension */ = {
isa = PBXNativeTarget;
buildConfigurationList = D25D4D7F2EFF41DB0029F805 /* Build configuration list for PBXNativeTarget "ShareExtension" */;
buildPhases = (
627F39EA1643E08048D23996 /* [CP] Check Pods Manifest.lock */,
D25D4D6C2EFF41DB0029F805 /* Sources */,
D25D4D6D2EFF41DB0029F805 /* Frameworks */,
D25D4D6E2EFF41DB0029F805 /* Resources */,
);
buildRules = (
);
dependencies = (
);
fileSystemSynchronizedGroups = (
D25D4D712EFF41DB0029F805 /* ShareExtension */,
);
name = ShareExtension;
productName = ShareExtension;
productReference = D25D4D702EFF41DB0029F805 /* ShareExtension.appex */;
productType = "com.apple.product-type.app-extension";
};
/* End PBXNativeTarget section */ /* End PBXNativeTarget section */
/* Begin PBXProject section */ /* Begin PBXProject section */
@ -304,7 +376,7 @@
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
BuildIndependentTargetsInParallel = YES; BuildIndependentTargetsInParallel = YES;
LastSwiftUpdateCheck = 1620; LastSwiftUpdateCheck = 2610;
LastUpgradeCheck = 1510; LastUpgradeCheck = 1510;
ORGANIZATIONNAME = ""; ORGANIZATIONNAME = "";
TargetAttributes = { TargetAttributes = {
@ -319,6 +391,9 @@
D21FCEA32D9F2B750088701D = { D21FCEA32D9F2B750088701D = {
CreatedOnToolsVersion = 16.2; CreatedOnToolsVersion = 16.2;
}; };
D25D4D6F2EFF41DB0029F805 = {
CreatedOnToolsVersion = 26.1.1;
};
}; };
}; };
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
@ -337,6 +412,7 @@
97C146ED1CF9000F007C117D /* Runner */, 97C146ED1CF9000F007C117D /* Runner */,
331C8080294A63A400263BE5 /* RunnerTests */, 331C8080294A63A400263BE5 /* RunnerTests */,
D21FCEA32D9F2B750088701D /* NotificationService */, D21FCEA32D9F2B750088701D /* NotificationService */,
D25D4D6F2EFF41DB0029F805 /* ShareExtension */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
@ -368,6 +444,13 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
D25D4D6E2EFF41DB0029F805 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */ /* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */
@ -448,6 +531,28 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n"; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n";
}; };
627F39EA1643E08048D23996 /* [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-ShareExtension-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;
};
9740EEB61CF901F6004384FC /* Run Script */ = { 9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1; alwaysOutOfDate = 1;
@ -529,6 +634,13 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
D25D4D6C2EFF41DB0029F805 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */ /* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */ /* Begin PBXTargetDependency section */
@ -542,6 +654,11 @@
target = D21FCEA32D9F2B750088701D /* NotificationService */; target = D21FCEA32D9F2B750088701D /* NotificationService */;
targetProxy = D21FCEA92D9F2B750088701D /* PBXContainerItemProxy */; targetProxy = D21FCEA92D9F2B750088701D /* PBXContainerItemProxy */;
}; };
D25D4D792EFF41DB0029F805 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D25D4D6F2EFF41DB0029F805 /* ShareExtension */;
targetProxy = D25D4D782EFF41DB0029F805 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */ /* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */ /* Begin PBXVariantGroup section */
@ -627,6 +744,7 @@
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
CUSTOM_GROUP_ID = group.eu.twonly.shareIntent;
DEVELOPMENT_TEAM = CN332ZUGRP; DEVELOPMENT_TEAM = CN332ZUGRP;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
@ -823,8 +941,9 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/RunnerDebug.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
CUSTOM_GROUP_ID = group.eu.twonly.shareIntent;
DEVELOPMENT_TEAM = CN332ZUGRP; DEVELOPMENT_TEAM = CN332ZUGRP;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
@ -859,6 +978,7 @@
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
CUSTOM_GROUP_ID = group.eu.twonly.shareIntent;
DEVELOPMENT_TEAM = CN332ZUGRP; DEVELOPMENT_TEAM = CN332ZUGRP;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
@ -1000,6 +1120,133 @@
}; };
name = Profile; name = Profile;
}; };
D25D4D7B2EFF41DB0029F805 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 15CEF849B61A620CFB2DC5F1 /* Pods-ShareExtension.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
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 = ShareExtension/ShareExtensionDebug.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
CUSTOM_GROUP_ID = group.eu.twonly.shareIntent;
DEVELOPMENT_TEAM = CN332ZUGRP;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = ShareExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 26.1;
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 = eu.twonly.ShareExtension;
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;
};
D25D4D7C2EFF41DB0029F805 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = A22BD564F16069E5FCB60767 /* Pods-ShareExtension.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
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_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
CUSTOM_GROUP_ID = group.eu.twonly.shareIntent;
DEVELOPMENT_TEAM = CN332ZUGRP;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = ShareExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 26.1;
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 = eu.twonly.ShareExtension;
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 = Release;
};
D25D4D7D2EFF41DB0029F805 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 39FB86A38393489D58A01B0B /* Pods-ShareExtension.profile.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
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_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
CUSTOM_GROUP_ID = group.eu.twonly.shareIntent;
DEVELOPMENT_TEAM = CN332ZUGRP;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = ShareExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 26.1;
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 = eu.twonly.ShareExtension;
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;
};
/* End XCBuildConfiguration section */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */ /* Begin XCConfigurationList section */
@ -1043,6 +1290,16 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
D25D4D7F2EFF41DB0029F805 /* Build configuration list for PBXNativeTarget "ShareExtension" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D25D4D7B2EFF41DB0029F805 /* Debug */,
D25D4D7C2EFF41DB0029F805 /* Release */,
D25D4D7D2EFF41DB0029F805 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */ /* End XCConfigurationList section */
}; };
rootObject = 97C146E61CF9000F007C117D /* Project object */; rootObject = 97C146E61CF9000F007C117D /* Project object */;

View file

@ -52,7 +52,7 @@
</Testables> </Testables>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Release" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"

View file

@ -1,37 +1,49 @@
import CryptoKit
import Flutter import Flutter
import Foundation
import UIKit import UIKit
import UserNotifications import UserNotifications
import CryptoKit import flutter_sharing_intent
import Foundation
@main @main
@objc class AppDelegate: FlutterAppDelegate { @objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
override func application( override func application(
_ application: UIApplication, _ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool { ) -> Bool {
if #available(iOS 10.0, *) {
//UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate
}
UNUserNotificationCenter.current().delegate = self UNUserNotificationCenter.current().delegate = self
// if (@available(iOS 10.0, *)) {
// [UNUserNotificationCenter currentNotificationCenter].delegate = (id<UNUserNotificationCenterDelegate>) self;
// }
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions) return super.application(application, didFinishLaunchingWithOptions: launchOptions)
} }
override func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { override func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
NSLog("Application delegate method userNotificationCenter:didReceive:withCompletionHandler: is called with user info: %@", response.notification.request.content.userInfo)
let sharingIntent = SwiftFlutterSharingIntentPlugin.instance
if sharingIntent.hasSameSchemePrefix(url: url) {
return sharingIntent.application(app, open: url, options: options)
}
// Proceed url handling for other Flutter libraries like app_links
return super.application(app, open: url, options:options)
}
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
}
override func userNotificationCenter(
_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void
) {
NSLog(
"Application delegate method userNotificationCenter:didReceive:withCompletionHandler: is called with user info: %@",
response.notification.request.content.userInfo)
//... //...
} }
override func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { override func userNotificationCenter(
_ center: UNUserNotificationCenter, willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
) {
NSLog("userNotificationCenter:willPresent") NSLog("userNotificationCenter:willPresent")
/* /*

View file

@ -2,6 +2,27 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneClassName</key>
<string>UIWindowScene</string>
<key>UISceneDelegateClassName</key>
<string>FlutterSceneDelegate</string>
<key>UISceneConfigurationName</key>
<string>flutter</string>
<key>UISceneStoryboardFile</key>
<string>Main</string>
</dict>
</array>
</dict>
</dict>
<key>CADisableMinimumFrameDurationOnPhone</key> <key>CADisableMinimumFrameDurationOnPhone</key>
<true/> <true/>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
@ -28,6 +49,8 @@
<false/> <false/>
<key>FirebaseAutomaticScreenReportingEnabled</key> <key>FirebaseAutomaticScreenReportingEnabled</key>
<false/> <false/>
<key>FlutterDeepLinkingEnabled</key>
<false/>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>ITSAppUsesNonExemptEncryption</key> <key>ITSAppUsesNonExemptEncryption</key>
@ -64,5 +87,21 @@
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>firebase_performance_collection_deactivated</key>
<true/>
<key>AppGroupId</key>
<string>$(CUSTOM_GROUP_ID)</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>SharingMedia-$(PRODUCT_BUNDLE_IDENTIFIER)</string>
</array>
</dict>
</array>
</dict> </dict>
</plist> </plist>

View file

@ -4,6 +4,10 @@
<dict> <dict>
<key>aps-environment</key> <key>aps-environment</key>
<string>development</string> <string>development</string>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:me.twonly.eu</string>
</array>
<key>keychain-access-groups</key> <key>keychain-access-groups</key>
<array> <array>
<string>$(AppIdentifierPrefix)eu.twonly.shared</string> <string>$(AppIdentifierPrefix)eu.twonly.shared</string>

View file

@ -0,0 +1,20 @@
<?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>aps-environment</key>
<string>development</string>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:me.twonly.eu</string>
</array>
<key>com.apple.security.application-groups</key>
<array>
<string>group.eu.twonly.shareIntent</string>
</array>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)eu.twonly.shared</string>
</array>
</dict>
</plist>

View 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>

View file

@ -0,0 +1,553 @@
// SOURCE: https://github.com/bhagat-techind/flutter_sharing_intent/blob/main/example/ios/Share%20Extension/FSIShareViewController.swift
// FSIShareViewController.swift
// Merged, optimized controller: uses RSI architecture with all FSI features preserved
// Uses model name `SharingFile` (same fields as SharedMediaFile) where `value` = path
import AVFoundation
import MobileCoreServices
import Social
import UIKit
import UniformTypeIdentifiers
public let kSchemePrefix = "SharingMedia"
public let kUserDefaultsKey = "SharingKey"
public let kUserDefaultsMessageKey = "SharingMessageKey"
public let kAppGroupIdKey = "AppGroupId"
public let kAppChannel = "flutter_sharing_intent"
@available(swift, introduced: 5.0)
open class FSIShareViewController: SLComposeServiceViewController {
// MARK: - Config
private(set) var hostAppBundleIdentifier: String = ""
private(set) var appGroupId: String = ""
// Results
private var sharedMedia: [SharingFile] = []
// Debug
private let debugLogs = false
// MARK: - Lifecycle
open override func viewDidLoad() {
super.viewDidLoad()
loadIds()
}
open override func isContentValid() -> Bool {
return true
}
open override func didSelectPost() {
if self.sharedMedia.isEmpty {
if let text = self.contentText, !text.isEmpty {
self.sharedMedia.append(
SharingFile(value: text, thumbnail: nil, duration: nil, type: .text)
)
self.saveAndRedirect(message: text)
return
}
self.completeAndExit()
} else {
self.saveAndRedirect()
}
}
open override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Process attachments automatically on appear like original FSI
processAttachments()
}
// MARK: - Load Ids
private func loadIds() {
let shareExtId = Bundle.main.bundleIdentifier ?? ""
if let idx = shareExtId.lastIndex(of: ".") {
hostAppBundleIdentifier = String(shareExtId[..<idx])
} else {
hostAppBundleIdentifier = shareExtId
}
let custom = Bundle.main.object(forInfoDictionaryKey: kAppGroupIdKey) as? String
appGroupId = custom ?? "group.\(hostAppBundleIdentifier)"
log("loaded host=\(hostAppBundleIdentifier) group=\(appGroupId)")
}
// MARK: - Attachment processing (clean RSI style, preserve FSI features)
private func processAttachments() {
guard let content = extensionContext?.inputItems.first as? NSExtensionItem else {
completeAndExit()
return
}
guard let attachments = content.attachments, !attachments.isEmpty else {
completeAndExit()
return
}
// Use DispatchGroup to wait for async loads
let group = DispatchGroup()
for (index, provider) in attachments.enumerated() {
group.enter()
// Try all SharedMediaType options similar to RSI but preserve explicit FSI order
if provider.isImage {
provider.loadItem(forTypeIdentifier: UType.image, options: nil) { [weak self] data, error in
defer { group.leave() }
guard let self = self, error == nil else { self?.dismissWithError(); return }
self.handleImageItem(data: data, index: index, total: attachments.count)
}
continue
}
if provider.isMovie {
provider.loadItem(forTypeIdentifier: UType.movie, options: nil) { [weak self] data, error in
defer { group.leave() }
guard let self = self, error == nil else { self?.dismissWithError(); return }
self.handleVideoItem(data: data, index: index, total: attachments.count)
}
continue
}
if provider.isFile {
provider.loadItem(forTypeIdentifier: UType.fileURL, options: nil) { [weak self] data, error in
defer { group.leave() }
guard let self = self, error == nil else { self?.dismissWithError(); return }
self.handleFileItem(data: data, index: index, total: attachments.count)
}
continue
}
if provider.isURL {
provider.loadItem(forTypeIdentifier: UType.url, options: nil) { [weak self] data, error in
defer { group.leave() }
guard let self = self, error == nil else { self?.dismissWithError(); return }
self.handleUrlItem(data: data, index: index, total: attachments.count)
}
continue
}
if provider.isText {
let id = provider.hasItemConformingToTypeIdentifier(UType.plainText)
? UType.plainText
: UType.text
provider.loadItem(forTypeIdentifier: id, options: nil) { [weak self] data, error in
defer { group.leave() }
guard let self = self, error == nil else { self?.dismissWithError(); return }
self.handleTextItem(data: data, index: index, total: attachments.count)
}
continue
}
if provider.isData {
provider.loadItem(forTypeIdentifier: UType.data, options: nil) { [weak self] data, error in
defer { group.leave() }
guard let self = self, error == nil else { self?.dismissWithError(); return }
self.handleFileItem(data: data, index: index, total: attachments.count)
}
continue
}
if provider.isItem {
provider.loadItem(forTypeIdentifier: UType.item, options: nil) { [weak self] data, error in
defer { group.leave() }
guard let self = self, error == nil else { self?.dismissWithError(); return }
self.handleFileItem(data: data, index: index, total: attachments.count)
}
continue
}
log("Unknown provider type: \(provider.registeredTypeIdentifiers)")
// Unknown type: just leave
group.leave()
}
group.notify(queue: .main) { [weak self] in
guard let self = self else { return }
// if we have media -> media, else fallback to complete
if !self.sharedMedia.isEmpty {
self.saveAndRedirect()
} else {
print("FSIShare: No shared media → stopping.")
self.completeAndExit()
}
}
}
// MARK: - Individual handlers (preserve FSI behavior)
private func handleTextItem(data: NSSecureCoding?, index: Int, total: Int) {
if let s = data as? String {
sharedMedia.append(SharingFile(value: s, thumbnail: nil, duration: nil, type: .text))
} else if let url = data as? URL {
sharedMedia.append(SharingFile(value: url.absoluteString, thumbnail: nil, duration: nil, type: .url))
}
}
private func handleUrlItem(data: NSSecureCoding?, index: Int, total: Int) {
if let url = data as? URL {
sharedMedia.append(SharingFile(value: url.absoluteString, thumbnail: nil, duration: nil, type: .url))
} else if let s = data as? String {
sharedMedia.append(SharingFile(value: s, thumbnail: nil, duration: nil, type: .text))
}
}
private func handleImageItem(data: NSSecureCoding?, index: Int, total: Int) {
// data can be URL, UIImage, or Data
if let url = data as? URL {
let filename = getFileName(from: url, type: .image)
if let dst = containerURL()?.appendingPathComponent(filename) {
if copyFile(at: url, to: dst) {
sharedMedia.append(SharingFile(value: dst.absoluteString, mimeType: url.mimeType(), thumbnail: nil, duration: nil, type: .image))
}
}
} else if let img = data as? UIImage {
if let saved = writeTempImage(img) {
sharedMedia.append(saved)
}
} else if let raw = data as? Data, let img = UIImage(data: raw) {
if let saved = writeTempImage(img) {
sharedMedia.append(saved)
}
}
}
private func handleVideoItem(data: NSSecureCoding?, index: Int, total: Int) {
if let url = data as? URL {
let filename = getFileName(from: url, type: .video)
if let dst = containerURL()?.appendingPathComponent(filename) {
if copyFile(at: url, to: dst) {
if let m = getSharedMediaFile(forVideo: dst) {
sharedMedia.append(m)
}
}
}
}
}
private func handleFileItem(data: NSSecureCoding?, index: Int, total: Int) {
if let url = data as? URL {
let filename = getFileName(from: url, type: .file)
if let dst = containerURL()?.appendingPathComponent(filename) {
if copyFile(at: url, to: dst) {
sharedMedia.append(SharingFile(value: dst.absoluteString, mimeType: url.mimeType(), thumbnail: nil, duration: nil, type: .file))
}
}
}
else if let raw = data as? Data {
let filename = "File_\(UUID().uuidString)"
if let dst = containerURL()?.appendingPathComponent(filename) {
do {
try raw.write(to: dst)
sharedMedia.append(SharingFile(value: dst.absoluteString, mimeType: "application/octet-stream", thumbnail: nil, duration: nil, type: .file))
} catch {}
}
}
}
// MARK: - Helpers: write temp image
private func writeTempImage(_ image: UIImage) -> SharingFile? {
guard let container = containerURL() else { return nil }
let tempName = "TempImage_\(UUID().uuidString).png"
let dst = container.appendingPathComponent(tempName)
do {
if let d = image.pngData() {
try d.write(to: dst)
let decoded = dst.absoluteString.removingPercentEncoding ?? dst.absoluteString
return SharingFile(value: decoded, mimeType: "image/png", thumbnail: nil, duration: nil, type: .image)
}
} catch {
log("writeTempImage error: \(error)")
}
return nil
}
private func saveAndRedirect(message: String? = nil) {
let ud = UserDefaults(suiteName: appGroupId)
if !sharedMedia.isEmpty {
if let data = try? JSONEncoder().encode(sharedMedia) {
ud?.set(data, forKey: kUserDefaultsKey)
}
}
ud?.set(message, forKey: kUserDefaultsMessageKey)
ud?.synchronize()
redirectToHostApp()
}
private func redirectToHostApp() {
// kept for compatibility (RSI style)
loadIds()
// let raw = "\(kSchemePrefix)-\(hostAppBundleIdentifier):share"
let raw = "\(kSchemePrefix)-\(hostAppBundleIdentifier)://dataUrl=\(kUserDefaultsKey)"
guard let url = URL(string: raw.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? raw) else { completeAndExit(); return }
var responder: UIResponder? = self
if #available(iOS 18.0, *) {
while responder != nil {
if let app = responder as? UIApplication { app.open(url, options: [:], completionHandler: nil) }
responder = responder?.next
}
} else {
let sel = sel_registerName("openURL:")
while responder != nil {
if responder?.responds(to: sel) ?? false { _ = responder?.perform(sel, with: url) }
responder = responder?.next
}
}
extensionContext?.completeRequest(returningItems: [], completionHandler: nil)
}
// MARK: - File / thumbnail / metadata helpers
func getExtension(from url: URL, type: SharingFileType) -> String {
let parts = url.lastPathComponent.components(separatedBy: ".")
var ex: String? = nil
if parts.count > 1 { ex = parts.last }
if ex == nil {
switch type {
case .image: ex = "png"
case .video: ex = "mp4"
case .file: ex = "txt"
case .text: ex = "txt"
case .url: ex = "txt"
}
}
return ex ?? "bin"
}
func getFileName(from url: URL, type: SharingFileType) -> String {
var name = url.lastPathComponent
if name.isEmpty { name = UUID().uuidString + "." + getExtension(from: url, type: type) }
return name
}
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)
return true
} catch {
log("copyFile error: \(error)")
return false
}
}
private func getSharedMediaFile(forVideo: URL) -> SharingFile? {
let asset = AVAsset(url: forVideo)
let duration = (CMTimeGetSeconds(asset.duration) * 1000).rounded()
let thumbnailPath = getThumbnailPath(for: forVideo)
if FileManager.default.fileExists(atPath: thumbnailPath.path) {
return SharingFile(value: forVideo.absoluteString, mimeType: forVideo.mimeType(), thumbnail: thumbnailPath.absoluteString, duration: Int(duration), type: .video)
}
let gen = AVAssetImageGenerator(asset: asset)
gen.appliesPreferredTrackTransform = true
gen.maximumSize = CGSize(width: 360, height: 360)
// Use first second or zero
let time = CMTime(seconds: min(1.0, CMTimeGetSeconds(asset.duration)), preferredTimescale: 600)
do {
let cg = try gen.copyCGImage(at: time, actualTime: nil)
if let data = UIImage(cgImage: cg).jpegData(compressionQuality: 0.8) {
try data.write(to: thumbnailPath)
return SharingFile(value: forVideo.absoluteString, mimeType: forVideo.mimeType(), thumbnail: thumbnailPath.absoluteString, duration: Int(duration), type: .video)
}
} catch {
log("getSharedMediaFile thumbnail error: \(error)")
}
// fallback
return SharingFile(value: forVideo.absoluteString, mimeType: forVideo.mimeType(), thumbnail: nil, duration: Int(duration), type: .video)
}
private func getThumbnailPath(for url: URL) -> URL {
guard let container = containerURL() else { fatalError("App group not configured or missing") }
let fileName = Data(url.lastPathComponent.utf8).base64EncodedString().replacingOccurrences(of: "=", with: "")
return container.appendingPathComponent("\(fileName).jpg")
}
private func containerURL() -> URL? {
FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupId)
}
private func completeAndExit() {
extensionContext?.completeRequest(returningItems: [], completionHandler: nil)
}
private func dismissWithError() {
log("[ERROR] Error loading data!")
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 writeTempFile(_ image: UIImage, to dstURL: URL) -> Bool {
do {
if FileManager.default.fileExists(atPath: dstURL.path) { try FileManager.default.removeItem(at: dstURL) }
let pngData = image.pngData()
try pngData?.write(to: dstURL)
return true
} catch (let error) {
log("writeTempFile error: \(error)")
return false
}
}
private func saveToUserDefaults(data: [SharingFile]) {
let ud = UserDefaults(suiteName: appGroupId)
if let enc = try? JSONEncoder().encode(data) { ud?.set(enc, forKey: kUserDefaultsKey); ud?.synchronize() }
}
// MARK: - Logging
private func log(_ s: String) { if debugLogs { print("[FSIShareVC] \(s)") } }
}
// MARK: - Extensions
extension URL {
func mimeType() -> String {
if #available(iOS 14.0, *) {
if let ut = UTType(filenameExtension: self.pathExtension), let m = ut.preferredMIMEType { return m }
} else {
if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, self.pathExtension as NSString, nil)?.takeRetainedValue() {
if let mimetype = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue() { return mimetype as String }
}
}
return "application/octet-stream"
}
}
extension NSItemProvider {
var isImage: Bool { return hasItemConformingToTypeIdentifier(UType.image) }
var isMovie: Bool { return hasItemConformingToTypeIdentifier(UType.movie) }
var isText: Bool {
hasItemConformingToTypeIdentifier(UType.plainText) || hasItemConformingToTypeIdentifier(UType.text)
}
var isURL: Bool { return hasItemConformingToTypeIdentifier(UType.url) }
var isFile: Bool { return hasItemConformingToTypeIdentifier(UType.fileURL) }
var isData:Bool { return hasItemConformingToTypeIdentifier(UType.data) }
var isItem: Bool { hasItemConformingToTypeIdentifier(UType.item) }
}
extension Array {
subscript(safe index: UInt) -> Element? { return Int(index) < count ? self[Int(index)] : nil }
}
class SharingFile: Codable {
var value: String
var mimeType: String?
var thumbnail: String?; // video thumbnail
var duration: Int?; // video duration in milliseconds
var type: SharingFileType;
var message: String? // post message
enum CodingKeys: String, CodingKey {
case value
case mimeType
case thumbnail
case duration
case type
case message
}
init(value: String, mimeType: String? = nil, thumbnail: String?, duration: Int?,
type: SharingFileType, message: String?=nil) {
self.value = value
self.mimeType = mimeType
self.thumbnail = thumbnail
self.duration = duration
self.type = type
self.message = message
}
// Debug method to print out SharedMediaFile details in the console
func toString() {
print("[SharingFile] \n\tvalue: \(self.value)\n\tthumbnail: \(self.thumbnail ?? "--" )\n\tduration: \(self.duration ?? 0)\n\ttype: \(self.type)\n\tmimeType: \(String(describing: self.mimeType))\n\tmessage: \(String(describing: self.message))")
}
}
enum SharingFileType: Int, Codable {
case text
case url
case image
case video
case file
}
// Unified UTType works on iOS 1118
enum UType {
static var image: String {
if #available(iOS 14.0, *) {
return UTType.image.identifier
} else {
return kUTTypeImage as String // old API
}
}
static var movie: String {
if #available(iOS 14.0, *) {
return UTType.movie.identifier
} else {
return kUTTypeMovie as String
}
}
static var url: String {
if #available(iOS 14.0, *) {
return UTType.url.identifier
} else {
return kUTTypeURL as String
}
}
static var fileURL: String {
if #available(iOS 14.0, *) {
return UTType.fileURL.identifier
} else {
return kUTTypeFileURL as String
}
}
static var text: String {
if #available(iOS 14.0, *) {
return UTType.text.identifier
} else {
return kUTTypeText as String
}
}
static var plainText: String {
if #available(iOS 14.0, *) {
return UTType.plainText.identifier
} else {
return kUTTypePlainText as String
}
}
static var data: String {
if #available(iOS 14.0, *) {
return UTType.data.identifier
} else {
return kUTTypeData as String
}
}
static var item: String {
if #available(iOS 14.0, *) {
return UTType.item.identifier
} else {
return kUTTypeItem as String
}
}
}

View file

@ -0,0 +1,35 @@
<?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>AppGroupId</key>
<string>$(CUSTOM_GROUP_ID)</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionMainStoryboard</key>
<string>MainInterface</string>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.share-services</string>
<key>NSExtensionAttributes</key>
<dict>
<key>PHSupportedMediaTypes</key>
<array>
<string>Video</string>
<string>Image</string>
</array>
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
<integer>1</integer>
<key>NSExtensionActivationSupportsMovieWithMaxCount</key>
<integer>1</integer>
</dict>
</dict>
</dict>
</dict>
</plist>

View 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.eu.twonly.shareIntent</string>
</array>
</dict>
</plist>

View file

@ -0,0 +1,3 @@
class ShareViewController: FSIShareViewController {
}

View file

@ -1,5 +1,5 @@
arb-dir: lib/src/localization arb-dir: lib/src/localization/translations
template-arb-file: app_en.arb template-arb-file: en.arb
output-localization-file: app_localizations.dart output-localization-file: app_localizations.dart
untranslated-messages-file: build/l10n.log untranslated-messages-file: build/l10n.log
output-dir: lib/src/localization/generated output-dir: lib/src/localization/generated

View file

@ -1,10 +1,12 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/localization/generated/app_localizations.dart'; import 'package:twonly/src/localization/generated/app_localizations.dart';
import 'package:twonly/src/providers/connection.provider.dart'; import 'package:twonly/src/providers/connection.provider.dart';
import 'package:twonly/src/providers/purchases.provider.dart';
import 'package:twonly/src/providers/settings.provider.dart'; import 'package:twonly/src/providers/settings.provider.dart';
import 'package:twonly/src/services/subscription.service.dart'; import 'package:twonly/src/services/subscription.service.dart';
import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/log.dart';
@ -39,8 +41,8 @@ class _AppState extends State<App> with WidgetsBindingObserver {
await setUserPlan(); await setUserPlan();
}; };
globalCallbackUpdatePlan = (SubscriptionPlan plan) async { globalCallbackUpdatePlan = (SubscriptionPlan plan) {
await context.read<CustomChangeProvider>().updatePlan(plan); context.read<PurchasesProvider>().updatePlan(plan);
}; };
unawaited(initAsync()); unawaited(initAsync());
@ -50,7 +52,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
final user = await getUser(); final user = await getUser();
if (user != null && mounted) { if (user != null && mounted) {
if (mounted) { if (mounted) {
await context.read<CustomChangeProvider>().updatePlan( context.read<PurchasesProvider>().updatePlan(
planFromString(user.subscriptionPlan), planFromString(user.subscriptionPlan),
); );
} }
@ -59,7 +61,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
Future<void> initAsync() async { Future<void> initAsync() async {
await setUserPlan(); await setUserPlan();
await apiService.connect(force: true); await apiService.connect();
await apiService.listenToNetworkChanges(); await apiService.listenToNetworkChanges();
} }
@ -70,7 +72,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
if (wasPaused) { if (wasPaused) {
globalIsAppInBackground = false; globalIsAppInBackground = false;
twonlyDB.markUpdated(); twonlyDB.markUpdated();
unawaited(apiService.connect(force: true)); unawaited(apiService.connect());
} }
} else if (state == AppLifecycleState.paused) { } else if (state == AppLifecycleState.paused) {
wasPaused = true; wasPaused = true;
@ -92,6 +94,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
listenable: context.watch<SettingsChangeProvider>(), listenable: context.watch<SettingsChangeProvider>(),
builder: (BuildContext context, Widget? child) { builder: (BuildContext context, Widget? child) {
return MaterialApp( return MaterialApp(
scaffoldMessengerKey: globalRootScaffoldMessengerKey,
restorationScopeId: 'app', restorationScopeId: 'app',
localizationsDelegates: const [ localizationsDelegates: const [
AppLocalizations.delegate, AppLocalizations.delegate,
@ -155,11 +158,14 @@ class _AppMainWidgetState extends State<AppMainWidget> {
bool _showDatabaseMigration = false; bool _showDatabaseMigration = false;
bool _showOnboarding = true; bool _showOnboarding = true;
bool _isLoaded = false; bool _isLoaded = false;
bool _skipBackup = false;
int _initialPage = 0;
(Future<int>?, bool) _proofOfWork = (null, false); (Future<int>?, bool) _proofOfWork = (null, false);
@override @override
void initState() { void initState() {
_initialPage = widget.initialPage;
initAsync(); initAsync();
super.initState(); super.initState();
} }
@ -171,6 +177,9 @@ class _AppMainWidgetState extends State<AppMainWidget> {
if (gUser.appVersion < 62) { if (gUser.appVersion < 62) {
_showDatabaseMigration = true; _showDatabaseMigration = true;
} }
if (!gUser.startWithCameraOpen) {
_initialPage = 0;
}
} }
if (!_isUserCreated && !_showDatabaseMigration) { if (!_isUserCreated && !_showDatabaseMigration) {
@ -203,15 +212,16 @@ class _AppMainWidgetState extends State<AppMainWidget> {
if (_showDatabaseMigration) { if (_showDatabaseMigration) {
child = const DatabaseMigrationView(); child = const DatabaseMigrationView();
} else if (_isUserCreated) { } else if (_isUserCreated) {
if (gUser.twonlySafeBackup == null) { if (gUser.twonlySafeBackup == null && !_skipBackup && kReleaseMode) {
child = TwonlyIdentityBackupView( child = TwonlyIdentityBackupView(
callBack: () { callBack: () {
_skipBackup = true;
setState(() {}); setState(() {});
}, },
); );
} else { } else {
child = HomeView( child = HomeView(
initialPage: widget.initialPage, initialPage: _initialPage,
); );
} }
} else if (_showOnboarding) { } else if (_showOnboarding) {

View file

@ -1,6 +1,5 @@
import 'dart:ui';
import 'package:camera/camera.dart'; import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/database/twonly.db.dart';
import 'package:twonly/src/model/json/userdata.dart'; import 'package:twonly/src/model/json/userdata.dart';
import 'package:twonly/src/services/api.service.dart'; import 'package:twonly/src/services/api.service.dart';
@ -34,3 +33,9 @@ Map<String, VoidCallback> globalUserDataChangedCallBack = {};
bool globalIsAppInBackground = true; bool globalIsAppInBackground = true;
bool globalAllowErrorTrackingViaSentry = false; bool globalAllowErrorTrackingViaSentry = false;
late String globalApplicationCacheDirectory;
late String globalApplicationSupportDirectory;
final GlobalKey<ScaffoldMessengerState> globalRootScaffoldMessengerKey =
GlobalKey<ScaffoldMessengerState>();

View file

@ -1,12 +1,7 @@
// ignore_for_file: unused_import
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'package:camera/camera.dart'; import 'package:camera/camera.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/sentry_flutter.dart';
@ -15,6 +10,7 @@ import 'package:twonly/globals.dart';
import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/database/twonly.db.dart';
import 'package:twonly/src/providers/connection.provider.dart'; import 'package:twonly/src/providers/connection.provider.dart';
import 'package:twonly/src/providers/image_editor.provider.dart'; import 'package:twonly/src/providers/image_editor.provider.dart';
import 'package:twonly/src/providers/purchases.provider.dart';
import 'package:twonly/src/providers/settings.provider.dart'; import 'package:twonly/src/providers/settings.provider.dart';
import 'package:twonly/src/services/api.service.dart'; import 'package:twonly/src/services/api.service.dart';
import 'package:twonly/src/services/api/mediafiles/media_background.service.dart'; import 'package:twonly/src/services/api/mediafiles/media_background.service.dart';
@ -23,25 +19,39 @@ import 'package:twonly/src/services/fcm.service.dart';
import 'package:twonly/src/services/mediafiles/mediafile.service.dart'; import 'package:twonly/src/services/mediafiles/mediafile.service.dart';
import 'package:twonly/src/services/notifications/setup.notifications.dart'; import 'package:twonly/src/services/notifications/setup.notifications.dart';
import 'package:twonly/src/services/twonly_safe/create_backup.twonly_safe.dart'; import 'package:twonly/src/services/twonly_safe/create_backup.twonly_safe.dart';
import 'package:twonly/src/utils/avatars.dart';
import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/log.dart';
import 'package:twonly/src/utils/storage.dart'; import 'package:twonly/src/utils/storage.dart';
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized(); SentryWidgetsFlutterBinding.ensureInitialized();
try {
await initFCMService();
} catch (e) {
Log.error('$e');
}
initLogger(); await initFCMService();
final user = await getUser(); final user = await getUser();
if (user != null) { if (user != null) {
gUser = user; gUser = user;
if (user.allowErrorTrackingViaSentry) {
globalAllowErrorTrackingViaSentry = true;
await SentryFlutter.init(
(options) => options
..dsn =
'https://6b24a012c85144c9b522440a1d17d01c@glitchtip.twonly.eu/4'
..tracesSampleRate = 0.1
..enableAutoSessionTracking = false,
);
}
unawaited(performTwonlySafeBackup()); unawaited(performTwonlySafeBackup());
} }
globalApplicationCacheDirectory = (await getApplicationCacheDirectory()).path;
globalApplicationSupportDirectory =
(await getApplicationSupportDirectory()).path;
initLogger();
final settingsController = SettingsChangeProvider(); final settingsController = SettingsChangeProvider();
await settingsController.loadSettings(); await settingsController.loadSettings();
@ -51,53 +61,25 @@ void main() async {
gCameras = await availableCameras(); gCameras = await availableCameras();
// try {
// File(join((await getApplicationSupportDirectory()).path, 'twonly.sqlite'))
// .deleteSync();
// } catch (e) {}
// await updateUserdata((u) {
// u.appVersion = 0;
// return u;
// });
apiService = ApiService(); apiService = ApiService();
twonlyDB = TwonlyDB(); twonlyDB = TwonlyDB();
await twonlyDB.messagesDao.purgeMessageTable();
unawaited(MediaFileService.purgeTempFolder());
await initFileDownloader(); await initFileDownloader();
unawaited(finishStartedPreprocessing()); unawaited(finishStartedPreprocessing());
unawaited(MediaFileService.purgeTempFolder());
unawaited(createPushAvatars()); unawaited(createPushAvatars());
await twonlyDB.messagesDao.purgeMessageTable();
final providers = [
ChangeNotifierProvider(create: (_) => settingsController),
ChangeNotifierProvider(create: (_) => CustomChangeProvider()),
ChangeNotifierProvider(create: (_) => ImageEditorProvider()),
];
if (user != null) {
if (user.allowErrorTrackingViaSentry) {
globalAllowErrorTrackingViaSentry = true;
return SentryFlutter.init(
(options) => options
..dsn =
'https://6b24a012c85144c9b522440a1d17d01c@glitchtip.twonly.eu/4'
..tracesSampleRate = 0.01
..enableAutoSessionTracking = false,
appRunner: () => runApp(
MultiProvider(
providers: providers,
child: const App(),
),
),
);
}
}
runApp( runApp(
MultiProvider( MultiProvider(
providers: providers, providers: [
ChangeNotifierProvider(create: (_) => settingsController),
ChangeNotifierProvider(create: (_) => CustomChangeProvider()),
ChangeNotifierProvider(create: (_) => ImageEditorProvider()),
ChangeNotifierProvider(create: (_) => PurchasesProvider()),
],
child: const App(), child: const App(),
), ),
); );

View file

@ -0,0 +1,6 @@
class SubscriptionKeys {
static const String proMonthly = 'pro_monthly';
static const String proYearly = 'pro_yearly';
// static const String familyMonthly = 'family_monthly';
static const String familyYearly = 'family_yearly';
}

View file

@ -42,8 +42,15 @@ class ContactsDao extends DatabaseAccessor<TwonlyDB> with _$ContactsDaoMixin {
.getSingleOrNull(); .getSingleOrNull();
} }
Future<List<Contact>> getContactsByUsername(String username) async { Future<List<Contact>> getContactsByUsername(
return (select(contacts)..where((t) => t.username.equals(username))).get(); String username, {
String username2 = '_______',
}) async {
return (select(contacts)
..where(
(t) => t.username.equals(username) | t.username.equals(username2),
))
.get();
} }
Future<void> deleteContactByUserId(int userId) { Future<void> deleteContactByUserId(int userId) {
@ -58,7 +65,8 @@ class ContactsDao extends DatabaseAccessor<TwonlyDB> with _$ContactsDaoMixin {
.write(updatedValues); .write(updatedValues);
if (updatedValues.blocked.present || if (updatedValues.blocked.present ||
updatedValues.displayName.present || updatedValues.displayName.present ||
updatedValues.nickName.present) { updatedValues.nickName.present ||
updatedValues.username.present) {
final contact = await getContactByUserId(userId).getSingleOrNull(); final contact = await getContactByUserId(userId).getSingleOrNull();
if (contact != null) { if (contact != null) {
await updatePushUser(contact); await updatePushUser(contact);
@ -91,7 +99,7 @@ class ContactsDao extends DatabaseAccessor<TwonlyDB> with _$ContactsDaoMixin {
.watchSingleOrNull(); .watchSingleOrNull();
} }
Future<List<Contact>> getAllNotBlockedContacts() { Future<List<Contact>> getAllContacts() {
return select(contacts).get(); return select(contacts).get();
} }
@ -118,7 +126,12 @@ class ContactsDao extends DatabaseAccessor<TwonlyDB> with _$ContactsDaoMixin {
Stream<List<Contact>> watchAllAcceptedContacts() { Stream<List<Contact>> watchAllAcceptedContacts() {
return (select(contacts) return (select(contacts)
..where((t) => t.blocked.equals(false) & t.accepted.equals(true))) ..where(
(t) =>
t.blocked.equals(false) &
t.accepted.equals(true) &
t.accountDeleted.equals(false),
))
.watch(); .watch();
} }

View file

@ -3,6 +3,7 @@ import 'package:hashlib/random.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/database/tables/groups.table.dart'; import 'package:twonly/src/database/tables/groups.table.dart';
import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/database/twonly.db.dart';
import 'package:twonly/src/services/flame.service.dart';
import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/log.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
@ -247,16 +248,22 @@ class GroupsDao extends DatabaseAccessor<TwonlyDB> with _$GroupsDaoMixin {
.get(); .get();
} }
Future<List<GroupMember>> getAllGroupMemberWithoutPublicKey() { Future<List<GroupMember>> getAllGroupMemberWithoutPublicKey() async {
final query = try {
((select(groups)..where((t) => t.isDirectChat.equals(false))).join([ final query = ((select(groupMembers)
..where((t) => t.groupPublicKey.isNull()))
.join([
leftOuterJoin( leftOuterJoin(
groupMembers, groups,
groupMembers.groupId.equalsExp(groups.groupId), groups.groupId.equalsExp(groupMembers.groupId),
), ),
]) ])
..where(groupMembers.groupPublicKey.isNull())); ..where(groups.isDirectChat.isNull()));
return query.map((row) => row.readTable(groupMembers)).get(); return query.map((row) => row.readTable(groupMembers)).get();
} catch (e) {
Log.error(e);
return [];
}
} }
Future<Group?> getDirectChat(int userId) async { Future<Group?> getDirectChat(int userId) async {
@ -272,89 +279,6 @@ class GroupsDao extends DatabaseAccessor<TwonlyDB> with _$GroupsDaoMixin {
return query.map((row) => row.readTable(groups)).getSingleOrNull(); return query.map((row) => row.readTable(groups)).getSingleOrNull();
} }
Future<void> incFlameCounter(
String groupId,
bool received,
DateTime timestamp,
) async {
final group = await (select(groups)
..where((t) => t.groupId.equals(groupId)))
.getSingle();
final totalMediaCounter = group.totalMediaCounter + (received ? 0 : 1);
var flameCounter = group.flameCounter;
var maxFlameCounter = group.maxFlameCounter;
var maxFlameCounterFrom = group.maxFlameCounterFrom;
if (group.lastMessageReceived != null && group.lastMessageSend != null) {
final now = DateTime.now();
final startOfToday = DateTime(now.year, now.month, now.day);
final twoDaysAgo = startOfToday.subtract(const Duration(days: 2));
if (group.lastMessageSend!.isBefore(twoDaysAgo) ||
group.lastMessageReceived!.isBefore(twoDaysAgo)) {
flameCounter = 0;
}
}
var lastMessageSend = const Value<DateTime?>.absent();
var lastMessageReceived = const Value<DateTime?>.absent();
var lastFlameCounterChange = const Value<DateTime?>.absent();
if (group.lastFlameCounterChange != null) {
final now = DateTime.now();
final startOfToday = DateTime(now.year, now.month, now.day);
if (group.lastFlameCounterChange!.isBefore(startOfToday)) {
// last flame update was yesterday. check if it can be updated.
var updateFlame = false;
if (received) {
if (group.lastMessageSend != null &&
group.lastMessageSend!.isAfter(startOfToday)) {
// today a message was already send -> update flame
updateFlame = true;
}
} else if (group.lastMessageReceived != null &&
group.lastMessageReceived!.isAfter(startOfToday)) {
// today a message was already received -> update flame
updateFlame = true;
}
if (updateFlame) {
flameCounter += 1;
lastFlameCounterChange = Value(timestamp);
// Overwrite max flame counter either the current is bigger or the th max flame counter is older then 4 days
if (flameCounter >= maxFlameCounter ||
maxFlameCounterFrom == null ||
maxFlameCounterFrom
.isBefore(DateTime.now().subtract(const Duration(days: 5)))) {
maxFlameCounter = flameCounter;
maxFlameCounterFrom = DateTime.now();
}
}
}
} else {
// There where no message until no...
lastFlameCounterChange = Value(timestamp);
}
if (received) {
lastMessageReceived = Value(timestamp);
} else {
lastMessageSend = Value(timestamp);
}
await (update(groups)..where((t) => t.groupId.equals(groupId))).write(
GroupsCompanion(
totalMediaCounter: Value(totalMediaCounter),
lastFlameCounterChange: lastFlameCounterChange,
lastMessageReceived: lastMessageReceived,
lastMessageSend: lastMessageSend,
flameCounter: Value(flameCounter),
maxFlameCounter: Value(maxFlameCounter),
maxFlameCounterFrom: Value(maxFlameCounterFrom),
),
);
}
Stream<int> watchSumTotalMediaCounter() { Stream<int> watchSumTotalMediaCounter() {
final query = selectOnly(groups) final query = selectOnly(groups)
..addColumns([groups.totalMediaCounter.sum()]); ..addColumns([groups.totalMediaCounter.sum()]);
@ -377,19 +301,3 @@ class GroupsDao extends DatabaseAccessor<TwonlyDB> with _$GroupsDaoMixin {
.write(GroupsCompanion(lastMessageExchange: Value(newLastMessage))); .write(GroupsCompanion(lastMessageExchange: Value(newLastMessage)));
} }
} }
int getFlameCounterFromGroup(Group? group) {
if (group == null) return 0;
if (group.lastMessageSend == null || group.lastMessageReceived == null) {
return 0;
}
final now = DateTime.now();
final startOfToday = DateTime(now.year, now.month, now.day);
final twoDaysAgo = startOfToday.subtract(const Duration(days: 2));
if (group.lastMessageSend!.isAfter(twoDaysAgo) &&
group.lastMessageReceived!.isAfter(twoDaysAgo)) {
return group.flameCounter + 1;
} else {
return 0;
}
}

View file

@ -100,6 +100,14 @@ class MediaFilesDao extends DatabaseAccessor<TwonlyDB>
.get(); .get();
} }
Future<List<MediaFile>> getAllNonHashedStoredMediaFiles() async {
return (select(mediaFiles)
..where(
(t) => t.stored.equals(true) & t.storedFileHash.isNull(),
))
.get();
}
Future<List<MediaFile>> getAllMediaFilesPendingUpload() async { Future<List<MediaFile>> getAllMediaFilesPendingUpload() async {
return (select(mediaFiles) return (select(mediaFiles)
..where( ..where(
@ -111,7 +119,10 @@ class MediaFilesDao extends DatabaseAccessor<TwonlyDB>
} }
Stream<List<MediaFile>> watchAllStoredMediaFiles() { Stream<List<MediaFile>> watchAllStoredMediaFiles() {
return (select(mediaFiles)..where((t) => t.stored.equals(true))).watch(); final query = (select(mediaFiles)..where((t) => t.stored.equals(true)))
.join([])
..groupBy([mediaFiles.storedFileHash]);
return query.map((row) => row.readTable(mediaFiles)).watch();
} }
Stream<List<MediaFile>> watchNewestMediaFiles() { Stream<List<MediaFile>> watchNewestMediaFiles() {

View file

@ -1,3 +1,4 @@
import 'package:clock/clock.dart';
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:hashlib/random.dart'; import 'package:hashlib/random.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
@ -110,25 +111,23 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
final allGroups = await select(groups).get(); final allGroups = await select(groups).get();
for (final group in allGroups) { for (final group in allGroups) {
final deletionTime = DateTime.now().subtract( final deletionTime = clock.now().subtract(
Duration( Duration(
milliseconds: group.deleteMessagesAfterMilliseconds, milliseconds: group.deleteMessagesAfterMilliseconds,
), ),
); );
final affected = await (delete(messages) await (delete(messages)
..where( ..where(
(m) => (m) =>
m.groupId.equals(group.groupId) & m.groupId.equals(group.groupId) &
// m.messageId.equals(lastMessage.messageId).not() &
(m.mediaStored.equals(true) & (m.mediaStored.equals(true) &
m.isDeletedFromSender.equals(true) | m.isDeletedFromSender.equals(true) |
m.mediaStored.equals(false)) & m.mediaStored.equals(false)) &
(m.openedByAll.isSmallerThanValue(deletionTime) | (m.openedAt.isSmallerThanValue(deletionTime) |
(m.isDeletedFromSender.equals(true) & (m.isDeletedFromSender.equals(true) &
m.createdAt.isSmallerThanValue(deletionTime))), m.createdAt.isSmallerThanValue(deletionTime))),
)) ))
.go(); .go();
Log.info('Deleted $affected messages.');
} }
} }
@ -152,7 +151,7 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
// t.messageOtherId.isNull() & // t.messageOtherId.isNull() &
// t.errorWhileSending.equals(false) & // t.errorWhileSending.equals(false) &
// t.sendAt.isBiggerThanValue( // t.sendAt.isBiggerThanValue(
// DateTime.now().subtract(const Duration(minutes: 10)), // clock.now().subtract(const Duration(minutes: 10)),
// ), // ),
// )) // ))
// .get(); // .get();
@ -180,7 +179,7 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
// } // }
Future<void> openedAllTextMessages(String groupId) { Future<void> openedAllTextMessages(String groupId) {
final updates = MessagesCompanion(openedAt: Value(DateTime.now())); final updates = MessagesCompanion(openedAt: Value(clock.now()));
return (update(messages) return (update(messages)
..where( ..where(
(t) => (t) =>
@ -274,12 +273,12 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
// Directly show as message opened as soon as one person has opened it // Directly show as message opened as soon as one person has opened it
final openedByAll = final openedByAll =
await haveAllMembers(messageId, MessageActionType.openedAt) await haveAllMembers(messageId, MessageActionType.openedAt)
? DateTime.now() ? clock.now()
: null; : null;
await twonlyDB.messagesDao.updateMessageId( await twonlyDB.messagesDao.updateMessageId(
messageId, messageId,
MessagesCompanion( MessagesCompanion(
openedAt: Value(DateTime.now()), openedAt: Value(clock.now()),
openedByAll: Value(openedByAll), openedByAll: Value(openedByAll),
), ),
); );
@ -300,7 +299,7 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
); );
await twonlyDB.messagesDao.updateMessageId( await twonlyDB.messagesDao.updateMessageId(
messageId, messageId,
MessagesCompanion(ackByServer: Value(DateTime.now())), MessagesCompanion(ackByServer: Value(clock.now())),
); );
} }
@ -380,7 +379,7 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
await twonlyDB.groupsDao.updateGroup( await twonlyDB.groupsDao.updateGroup(
message.groupId.value, message.groupId.value,
GroupsCompanion( GroupsCompanion(
lastMessageExchange: Value(DateTime.now()), lastMessageExchange: Value(clock.now()),
archived: const Value(false), archived: const Value(false),
deletedContent: const Value(false), deletedContent: const Value(false),
), ),
@ -391,7 +390,7 @@ class MessagesDao extends DatabaseAccessor<TwonlyDB> with _$MessagesDaoMixin {
message.groupId.value, message.groupId.value,
message.senderId.value!, message.senderId.value!,
GroupMembersCompanion( GroupMembersCompanion(
lastMessage: Value(DateTime.now()), lastMessage: Value(clock.now()),
), ),
); );
} }

View file

@ -1,3 +1,4 @@
import 'package:clock/clock.dart';
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:hashlib/random.dart'; import 'package:hashlib/random.dart';
import 'package:twonly/src/database/tables/messages.table.dart'; import 'package:twonly/src/database/tables/messages.table.dart';
@ -62,7 +63,7 @@ class ReceiptsDao extends DatabaseAccessor<TwonlyDB> with _$ReceiptsDaoMixin {
return await (select(receipts)..where((t) => t.rowId.equals(id))) return await (select(receipts)..where((t) => t.rowId.equals(id)))
.getSingle(); .getSingle();
} catch (e) { } catch (e) {
Log.error(e); // ignore error, receipts is already in the database...
return null; return null;
} }
} }
@ -80,10 +81,18 @@ class ReceiptsDao extends DatabaseAccessor<TwonlyDB> with _$ReceiptsDaoMixin {
} }
} }
Future<List<Receipt>> getReceiptsNotAckByServer() async { Future<List<Receipt>> getReceiptsForRetransmission() async {
final markedRetriesTime = clock.now().subtract(
const Duration(
// give the server time to transmit all messages to the client
seconds: 20,
),
);
return (select(receipts) return (select(receipts)
..where( ..where(
(t) => t.ackByServerAt.isNull(), (t) =>
t.ackByServerAt.isNull() |
t.markForRetry.isSmallerThanValue(markedRetriesTime),
)) ))
.get(); .get();
} }
@ -100,6 +109,14 @@ class ReceiptsDao extends DatabaseAccessor<TwonlyDB> with _$ReceiptsDaoMixin {
.write(updates); .write(updates);
} }
Future<void> markMessagesForRetry(int contactId) async {
await (update(receipts)..where((c) => c.contactId.equals(contactId))).write(
ReceiptsCompanion(
markForRetry: Value(clock.now()),
),
);
}
Future<bool> isDuplicated(String receiptId) async { Future<bool> isDuplicated(String receiptId) async {
return await (select(receivedReceipts) return await (select(receivedReceipts)
..where((t) => t.receiptId.equals(receiptId))) ..where((t) => t.receiptId.equals(receiptId)))

View file

@ -1,3 +1,4 @@
import 'package:clock/clock.dart';
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/database/tables/signal_contact_prekey.table.dart'; import 'package:twonly/src/database/tables/signal_contact_prekey.table.dart';
@ -107,7 +108,7 @@ class SignalDao extends DatabaseAccessor<TwonlyDB> with _$SignalDaoMixin {
await (delete(signalContactPreKeys) await (delete(signalContactPreKeys)
..where( ..where(
(t) => (t.createdAt.isSmallerThanValue( (t) => (t.createdAt.isSmallerThanValue(
DateTime.now().subtract( clock.now().subtract(
const Duration(days: 100), const Duration(days: 100),
), ),
)), )),
@ -117,7 +118,7 @@ class SignalDao extends DatabaseAccessor<TwonlyDB> with _$SignalDaoMixin {
await (delete(twonlyDB.signalPreKeyStores) await (delete(twonlyDB.signalPreKeyStores)
..where( ..where(
(t) => (t.createdAt.isSmallerThanValue( (t) => (t.createdAt.isSmallerThanValue(
DateTime.now().subtract( clock.now().subtract(
const Duration(days: 365), const Duration(days: 365),
), ),
)), )),

Some files were not shown because too many files have changed in this diff Show more