mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-16 05:58:40 +00:00
Compare commits
132 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
944fc1eb6c | ||
|
|
b1802111f5 | ||
|
|
52952babfc | ||
|
|
085702c0bb | ||
|
|
285859cee6 | ||
|
|
2249c63c2f | ||
|
|
772ec8aff1 | ||
|
|
e9fcfbefd9 | ||
|
|
5b2e91964f | ||
|
|
70fbf6abbb | ||
|
|
e9c5d49938 | ||
|
|
13f62934b7 | ||
|
|
36e309d58a | ||
|
|
d2b881e281 | ||
|
|
585f577f89 | ||
|
|
ad0ef841cc | ||
|
|
e97f0a910f | ||
|
|
6b353d8a66 | ||
|
|
24f45ce9bd | ||
|
|
1f8bdaa32d | ||
|
|
d067a3c931 | ||
|
|
b3c25dd160 | ||
|
|
3899c8e6e4 | ||
|
|
87187843fa | ||
|
|
ebf53a5ab4 | ||
|
|
6a104e9468 | ||
|
|
ea68dcaf1c | ||
|
|
4b5a4387d1 | ||
|
|
85d6bdfcc9 | ||
|
|
41dfd54e81 | ||
|
|
20a2d61751 | ||
|
|
57c73a86ac | ||
|
|
230809290a | ||
|
|
0984eaf347 | ||
|
|
b093a7acdb | ||
|
|
6dc9aa10bc | ||
|
|
11aa4c4202 | ||
|
|
987a55dc65 | ||
|
|
910f5f79fa | ||
|
|
27483bccd6 | ||
|
|
abd689f1fa | ||
|
|
027871290d | ||
|
|
82f4c9af9f | ||
|
|
7007e7b063 | ||
|
|
333f033993 | ||
|
|
e17e39ef41 | ||
|
|
b9bb074ba6 | ||
|
|
2713f092eb | ||
|
|
c91c53dd8b | ||
|
|
049507cd25 | ||
|
|
fa953b8928 | ||
|
|
074ead8b4f | ||
|
|
9fe55ab62d | ||
|
|
2db1775d1f | ||
|
|
189ed26dd7 | ||
|
|
39d406d156 | ||
|
|
6b2cc85e81 | ||
|
|
0ed264f152 | ||
|
|
5645baaae8 | ||
|
|
4f27bfba01 | ||
|
|
618d4a3fb3 | ||
|
|
54f049496d | ||
|
|
ab103a98ae | ||
|
|
1798ba321b | ||
|
|
7768362eb5 | ||
|
|
05c2e8d677 | ||
|
|
1a2aa5edb9 | ||
|
|
25114daee2 | ||
|
|
bc1c61c8f8 | ||
|
|
36e11c206c | ||
|
|
332c19e880 | ||
|
|
b3ec419411 | ||
|
|
3265b6259c | ||
|
|
76b617e63a | ||
|
|
9667ea21b6 | ||
|
|
3cb9f7bf4b | ||
|
|
004f00f308 | ||
|
|
a63343ccdd | ||
|
|
35a90ace0a | ||
|
|
38ab86f5e8 | ||
|
|
24edf896c5 | ||
|
|
6ab11c4e69 | ||
|
|
b8c063cc29 | ||
|
|
febf236147 | ||
|
|
b306165681 | ||
|
|
ef4b799861 | ||
|
|
83d57c638b | ||
|
|
03df9634aa | ||
|
|
6ed8a3eff5 | ||
|
|
7aeaa97a68 | ||
|
|
108a58ffe1 | ||
|
|
9cb2503cdb | ||
|
|
5758749bd1 | ||
|
|
d2b7e4cf9e | ||
|
|
2624df9b99 | ||
|
|
004c0e116c | ||
|
|
c6cc518de1 | ||
|
|
e7e413a9f1 | ||
|
|
1f54423a10 | ||
|
|
92fa2cdff5 | ||
|
|
819c8201d2 | ||
|
|
a99a52cdb0 | ||
|
|
7268e990bc | ||
|
|
89e12fe24f | ||
|
|
66fb320355 | ||
|
|
c3e92ac7d1 | ||
|
|
f50add6530 | ||
|
|
e00700d4e3 | ||
|
|
4623487556 | ||
|
|
72495b4c2a | ||
|
|
eb8b7d31de | ||
|
|
39c8d4990f | ||
|
|
8a4632c4c4 | ||
|
|
fa85dbd6e2 | ||
|
|
58b286526d | ||
|
|
fc2513ddba | ||
|
|
7977d171c7 | ||
|
|
1eaa1a5edd | ||
|
|
570d820ada | ||
|
|
1e14905682 | ||
|
|
f57c2fec79 | ||
|
|
5371114e21 | ||
|
|
2a9414ae4f | ||
|
|
0260d552bf | ||
|
|
4ff42c93b7 | ||
|
|
091e4bbfa8 | ||
|
|
6d86af155c | ||
|
|
bc2c998850 | ||
|
|
1cc19f7834 | ||
|
|
5946420fd0 | ||
|
|
85d755e46b | ||
|
|
b584974491 |
290 changed files with 53025 additions and 9177 deletions
11
.gitmodules
vendored
11
.gitmodules
vendored
|
|
@ -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
11
.vscode/launch.json
vendored
|
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": "Flutter",
|
|
||||||
"type": "dart",
|
|
||||||
"request": "launch",
|
|
||||||
"program": "lib/main.dart",
|
|
||||||
"flutterMode": "profile"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
53
CHANGELOG.md
53
CHANGELOG.md
|
|
@ -1,5 +1,57 @@
|
||||||
# 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
|
||||||
|
|
||||||
|
- Adds crash reports (optional). Please consider enabling this under Settings > Help > “Share errors and crashes with us.”
|
||||||
|
- Fixes bug when saving images to the gallery
|
||||||
|
- Multiple layout issues fixed
|
||||||
|
- Multiple bug fixes
|
||||||
|
|
||||||
## 0.0.62
|
## 0.0.62
|
||||||
|
|
||||||
- Support for groups with multiple administrators
|
- Support for groups with multiple administrators
|
||||||
|
|
@ -16,7 +68,6 @@
|
||||||
- Improved reliability of client-to-client messaging
|
- Improved reliability of client-to-client messaging
|
||||||
- Multiple bug fixes
|
- Multiple bug fixes
|
||||||
|
|
||||||
|
|
||||||
## 0.0.61
|
## 0.0.61
|
||||||
|
|
||||||
- Improving image editor when changing colors
|
- Improving image editor when changing colors
|
||||||
|
|
|
||||||
30
README.md
30
README.md
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 |
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
1
assets/animated_icons/alarm-clock.json
Normal file
1
assets/animated_icons/alarm-clock.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/ant.json
Normal file
1
assets/animated_icons/ant.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/automobile.json
Normal file
1
assets/animated_icons/automobile.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/beating-heart.json
Normal file
1
assets/animated_icons/beating-heart.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/bee.json
Normal file
1
assets/animated_icons/bee.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/burrito.json
Normal file
1
assets/animated_icons/burrito.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/cockroach.json
Normal file
1
assets/animated_icons/cockroach.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/crocodile.json
Normal file
1
assets/animated_icons/crocodile.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/crying-cat-face.json
Normal file
1
assets/animated_icons/crying-cat-face.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/fly.json
Normal file
1
assets/animated_icons/fly.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/guide-dog.json
Normal file
1
assets/animated_icons/guide-dog.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/heart-eyes-cat.json
Normal file
1
assets/animated_icons/heart-eyes-cat.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/heart-grow.json
Normal file
1
assets/animated_icons/heart-grow.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/joy-cat.json
Normal file
1
assets/animated_icons/joy-cat.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/kissing-cat.json
Normal file
1
assets/animated_icons/kissing-cat.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/kissing-smiling-eyes.json
Normal file
1
assets/animated_icons/kissing-smiling-eyes.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/lady-bug.json
Normal file
1
assets/animated_icons/lady-bug.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/leg-mechanical.json
Normal file
1
assets/animated_icons/leg-mechanical.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/leg.json
Normal file
1
assets/animated_icons/leg.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/lizard.json
Normal file
1
assets/animated_icons/lizard.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/lobster.json
Normal file
1
assets/animated_icons/lobster.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/monkey.json
Normal file
1
assets/animated_icons/monkey.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/neutral-face.json
Normal file
1
assets/animated_icons/neutral-face.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/palms-up.json
Normal file
1
assets/animated_icons/palms-up.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/peacock.json
Normal file
1
assets/animated_icons/peacock.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/pouting-cat.json
Normal file
1
assets/animated_icons/pouting-cat.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/rainbow.json
Normal file
1
assets/animated_icons/rainbow.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/revolving-hearts.json
Normal file
1
assets/animated_icons/revolving-hearts.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/scorpion.json
Normal file
1
assets/animated_icons/scorpion.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/scream-cat.json
Normal file
1
assets/animated_icons/scream-cat.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/seal.json
Normal file
1
assets/animated_icons/seal.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/shark.json
Normal file
1
assets/animated_icons/shark.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/smile-cat.json
Normal file
1
assets/animated_icons/smile-cat.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/smiley-cat.json
Normal file
1
assets/animated_icons/smiley-cat.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/smirk-cat.json
Normal file
1
assets/animated_icons/smirk-cat.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/taxi.json
Normal file
1
assets/animated_icons/taxi.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/tiger.json
Normal file
1
assets/animated_icons/tiger.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animated_icons/volcano.json
Normal file
1
assets/animated_icons/volcano.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/images/build/.last_build_id
Normal file
1
assets/images/build/.last_build_id
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
5cde0a78d118f9e043e7443ceca0f306
|
||||||
BIN
assets/images/default_avatar.png
Normal file
BIN
assets/images/default_avatar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
BIN
assets/images/default_avatar.svg.vec
Normal file
BIN
assets/images/default_avatar.svg.vec
Normal file
Binary file not shown.
|
|
@ -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
1
dependencies
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 7930d9727019344238297d810661bc3e8f724c37
|
||||||
1
dependencies/flutter_zxing
vendored
1
dependencies/flutter_zxing
vendored
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit ba65f2fb4a09f4e68f6de64aa1de41ba3dc4977e
|
|
||||||
|
|
@ -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.",
|
||||||
|
|
|
||||||
|
|
@ -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|
|
||||||
|
|
|
||||||
264
ios/Podfile.lock
264
ios/Podfile.lock
|
|
@ -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,14 +240,33 @@ 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):
|
||||||
|
- Flutter
|
||||||
- package_info_plus (0.4.5):
|
- package_info_plus (0.4.5):
|
||||||
- Flutter
|
- Flutter
|
||||||
- path_provider_foundation (0.0.1):
|
- path_provider_foundation (0.0.1):
|
||||||
|
|
@ -202,12 +278,17 @@ 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_flutter (9.8.0):
|
||||||
|
- Flutter
|
||||||
|
- FlutterMacOS
|
||||||
|
- Sentry/HybridSDK (= 8.56.2)
|
||||||
- share_plus (0.0.1):
|
- share_plus (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- shared_preferences_foundation (0.0.1):
|
- shared_preferences_foundation (0.0.1):
|
||||||
|
|
@ -241,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):
|
||||||
|
|
@ -249,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`)
|
||||||
|
|
@ -257,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`)
|
||||||
|
|
@ -268,17 +352,22 @@ 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`)
|
||||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||||
- restart_app (from `.symlinks/plugins/restart_app/ios`)
|
- restart_app (from `.symlinks/plugins/restart_app/ios`)
|
||||||
|
- sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`)
|
||||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||||
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
|
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
|
||||||
|
|
@ -289,6 +378,8 @@ DEPENDENCIES:
|
||||||
|
|
||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
trunk:
|
trunk:
|
||||||
|
- DKImagePickerController
|
||||||
|
- DKPhotoGallery
|
||||||
- Firebase
|
- Firebase
|
||||||
- FirebaseAnalytics
|
- FirebaseAnalytics
|
||||||
- FirebaseCore
|
- FirebaseCore
|
||||||
|
|
@ -298,18 +389,29 @@ 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
|
||||||
- SDWebImage
|
- SDWebImage
|
||||||
- SDWebImageWebPCoder
|
- SDWebImageWebPCoder
|
||||||
|
- 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:
|
||||||
|
|
@ -326,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:
|
||||||
|
|
@ -340,18 +444,26 @@ 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:
|
||||||
:path: ".symlinks/plugins/no_screenshot/ios"
|
:path: ".symlinks/plugins/no_screenshot/ios"
|
||||||
|
objective_c:
|
||||||
|
:path: ".symlinks/plugins/objective_c/ios"
|
||||||
package_info_plus:
|
package_info_plus:
|
||||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
|
|
@ -360,6 +472,8 @@ EXTERNAL SOURCES:
|
||||||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||||
restart_app:
|
restart_app:
|
||||||
:path: ".symlinks/plugins/restart_app/ios"
|
:path: ".symlinks/plugins/restart_app/ios"
|
||||||
|
sentry_flutter:
|
||||||
|
:path: ".symlinks/plugins/sentry_flutter/ios"
|
||||||
share_plus:
|
share_plus:
|
||||||
:path: ".symlinks/plugins/share_plus/ios"
|
:path: ".symlinks/plugins/share_plus/ios"
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
|
|
@ -374,57 +488,75 @@ 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
|
||||||
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
||||||
path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
|
path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
|
||||||
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
|
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
|
||||||
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_flutter: 4c33648b7e83310aa1fdb1b10c5491027d9643f0
|
||||||
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
||||||
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -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 */;
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
20
ios/Runner/RunnerDebug.entitlements
Normal file
20
ios/Runner/RunnerDebug.entitlements
Normal 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>
|
||||||
24
ios/ShareExtension/Base.lproj/MainInterface.storyboard
Normal file
24
ios/ShareExtension/Base.lproj/MainInterface.storyboard
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="j1y-V4-xli">
|
||||||
|
<dependencies>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
|
||||||
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--Share View Controller-->
|
||||||
|
<scene sceneID="ceB-am-kn3">
|
||||||
|
<objects>
|
||||||
|
<viewController id="j1y-V4-xli" customClass="ShareViewController" customModuleProvider="target" sceneMemberID="viewController">
|
||||||
|
<view key="view" opaque="NO" contentMode="scaleToFill" id="wbc-yd-nQP">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<viewLayoutGuide key="safeArea" id="1Xd-am-t49"/>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="CEy-Cv-SGf" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
</document>
|
||||||
553
ios/ShareExtension/FSIShareViewController.swift
Normal file
553
ios/ShareExtension/FSIShareViewController.swift
Normal 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 11–18
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
ios/ShareExtension/Info.plist
Normal file
35
ios/ShareExtension/Info.plist
Normal 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>
|
||||||
10
ios/ShareExtension/ShareExtensionDebug.entitlements
Normal file
10
ios/ShareExtension/ShareExtensionDebug.entitlements
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.security.application-groups</key>
|
||||||
|
<array>
|
||||||
|
<string>group.eu.twonly.shareIntent</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
3
ios/ShareExtension/ShareViewController.swift
Normal file
3
ios/ShareExtension/ShareViewController.swift
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
class ShareViewController: FSIShareViewController {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
24
lib/app.dart
24
lib/app.dart
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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';
|
||||||
|
|
@ -33,3 +32,10 @@ void Function(SubscriptionPlan plan) globalCallbackUpdatePlan =
|
||||||
Map<String, VoidCallback> globalUserDataChangedCallBack = {};
|
Map<String, VoidCallback> globalUserDataChangedCallBack = {};
|
||||||
|
|
||||||
bool globalIsAppInBackground = true;
|
bool globalIsAppInBackground = true;
|
||||||
|
bool globalAllowErrorTrackingViaSentry = false;
|
||||||
|
|
||||||
|
late String globalApplicationCacheDirectory;
|
||||||
|
late String globalApplicationSupportDirectory;
|
||||||
|
|
||||||
|
final GlobalKey<ScaffoldMessengerState> globalRootScaffoldMessengerKey =
|
||||||
|
GlobalKey<ScaffoldMessengerState>();
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,16 @@
|
||||||
// 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:twonly/app.dart';
|
import 'package:twonly/app.dart';
|
||||||
import 'package:twonly/globals.dart';
|
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';
|
||||||
|
|
@ -22,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();
|
||||||
|
|
@ -50,24 +61,16 @@ 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();
|
|
||||||
|
|
||||||
runApp(
|
runApp(
|
||||||
MultiProvider(
|
MultiProvider(
|
||||||
|
|
@ -75,6 +78,7 @@ void main() async {
|
||||||
ChangeNotifierProvider(create: (_) => settingsController),
|
ChangeNotifierProvider(create: (_) => settingsController),
|
||||||
ChangeNotifierProvider(create: (_) => CustomChangeProvider()),
|
ChangeNotifierProvider(create: (_) => CustomChangeProvider()),
|
||||||
ChangeNotifierProvider(create: (_) => ImageEditorProvider()),
|
ChangeNotifierProvider(create: (_) => ImageEditorProvider()),
|
||||||
|
ChangeNotifierProvider(create: (_) => PurchasesProvider()),
|
||||||
],
|
],
|
||||||
child: const App(),
|
child: const App(),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
6
lib/src/constants/subscription.keys.dart
Normal file
6
lib/src/constants/subscription.keys.dart
Normal 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';
|
||||||
|
}
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 + 1) >= maxFlameCounter ||
|
|
||||||
maxFlameCounterFrom == null ||
|
|
||||||
maxFlameCounterFrom
|
|
||||||
.isBefore(DateTime.now().subtract(const Duration(days: 5)))) {
|
|
||||||
maxFlameCounter = flameCounter + 1;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
|
|
@ -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()),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)))
|
||||||
|
|
|
||||||
|
|
@ -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';
|
||||||
|
|
@ -57,7 +58,6 @@ class SignalDao extends DatabaseAccessor<TwonlyDB> with _$SignalDaoMixin {
|
||||||
tbl.preKeyId.equals(preKey.preKeyId),
|
tbl.preKeyId.equals(preKey.preKeyId),
|
||||||
))
|
))
|
||||||
.go();
|
.go();
|
||||||
Log.info('[PREKEY] Using prekey ${preKey.preKeyId} for $contactId');
|
|
||||||
return preKey;
|
return preKey;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -68,7 +68,6 @@ class SignalDao extends DatabaseAccessor<TwonlyDB> with _$SignalDaoMixin {
|
||||||
List<SignalContactPreKeysCompanion> preKeys,
|
List<SignalContactPreKeysCompanion> preKeys,
|
||||||
) async {
|
) async {
|
||||||
for (final preKey in preKeys) {
|
for (final preKey in preKeys) {
|
||||||
Log.info('[PREKEY] Inserting others ${preKey.preKeyId}');
|
|
||||||
try {
|
try {
|
||||||
await into(signalContactPreKeys).insert(preKey);
|
await into(signalContactPreKeys).insert(preKey);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
@ -109,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),
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
|
|
@ -119,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
Loading…
Reference in a new issue