mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-16 05:58:40 +00:00
Compare commits
No commits in common. "main" and "v0.0.66" have entirely different histories.
290 changed files with 9175 additions and 53023 deletions
11
.gitmodules
vendored
11
.gitmodules
vendored
|
|
@ -1,8 +1,3 @@
|
|||
|
||||
[submodule "dependencies"]
|
||||
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
|
||||
[submodule "dependencies/flutter_zxing"]
|
||||
path = dependencies/flutter_zxing
|
||||
url = https://github.com/khoren93/flutter_zxing.git
|
||||
|
|
|
|||
11
.vscode/launch.json
vendored
Normal file
11
.vscode/launch.json
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Flutter",
|
||||
"type": "dart",
|
||||
"request": "launch",
|
||||
"program": "lib/main.dart",
|
||||
"flutterMode": "profile"
|
||||
}
|
||||
]
|
||||
}
|
||||
53
CHANGELOG.md
53
CHANGELOG.md
|
|
@ -1,57 +1,5 @@
|
|||
# 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
|
||||
|
||||
- Support for groups with multiple administrators
|
||||
|
|
@ -68,6 +16,7 @@
|
|||
- Improved reliability of client-to-client messaging
|
||||
- Multiple bug fixes
|
||||
|
||||
|
||||
## 0.0.61
|
||||
|
||||
- Improving image editor when changing colors
|
||||
|
|
|
|||
30
README.md
30
README.md
|
|
@ -4,35 +4,12 @@
|
|||
|
||||
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
|
||||
|
||||
- Offer a Snapchat™ like experience
|
||||
- End-to-End encryption using the [Signal Protocol](https://de.wikipedia.org/wiki/Signal-Protokoll)
|
||||
- Open Source and can be downloaded directly from GitHub
|
||||
- twonly is 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
|
||||
- Privacy friendly - Everything is stored on the device
|
||||
- The backend is hosted exclusively in Europe
|
||||
|
|
@ -44,7 +21,6 @@ This repository contains the complete source code of the [twonly](https://twonly
|
|||
- Implementing [Sealed Sender](https://signal.org/blog/sealed-sender/) to minimize metadata
|
||||
|
||||
## Security Issues
|
||||
|
||||
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
|
||||
guarantee a bounty currently :/
|
||||
|
|
@ -78,7 +54,7 @@ run-as eu.twonly.testing ls /data/user/0/eu.twonly.testing/
|
|||
|
||||
## Signing Keys
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -16,8 +16,6 @@ analyzer:
|
|||
- "lib/src/model/protobuf/api/websocket/**"
|
||||
- "lib/generated/**"
|
||||
- "dependencies/**"
|
||||
- "pubspec.yaml"
|
||||
- "*.arb"
|
||||
- "test/drift/**"
|
||||
- "**.g.dart"
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ android {
|
|||
// compileSdk = flutter.compileSdkVersion
|
||||
compileSdk 36
|
||||
//ndkVersion = flutter.ndkVersion
|
||||
ndkVersion = "28.2.13676358"
|
||||
ndkVersion = "27.0.12077973"
|
||||
|
||||
compileOptions {
|
||||
coreLibraryDesugaringEnabled true
|
||||
|
|
|
|||
|
|
@ -1,15 +1,9 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- The INTERNET permission is required for development. Specifically,
|
||||
the Flutter tool needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<application android:usesCleartextTraffic="true" >
|
||||
<!-- // 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>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application
|
||||
android:label="twonly"
|
||||
android:name="${applicationName}"
|
||||
|
|
@ -26,23 +26,6 @@
|
|||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</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>
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
|
|
@ -50,17 +33,19 @@
|
|||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
|
||||
<!-- // 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>
|
||||
|
||||
<!-- <service
|
||||
android:name="com.pravera.flutter_foreground_task.service.ForegroundService"
|
||||
android:foregroundServiceType="dataSync|remoteMessaging"
|
||||
android:exported="false" /> -->
|
||||
|
||||
<meta-data
|
||||
android:name="eu.twonly.service.TWONLY_LOGO"
|
||||
android:resource="@drawable/ic_launcher_foreground" />
|
||||
</application>
|
||||
|
||||
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
|
|
@ -68,7 +53,6 @@
|
|||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="com.android.vending.BILLING" />
|
||||
|
||||
<!-- Required to query activities that can process text, see:
|
||||
https://developer.android.com/training/package-visibility and
|
||||
|
|
|
|||
|
|
@ -1,27 +1,12 @@
|
|||
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 android.view.KeyEvent
|
||||
import dev.darttools.flutter_android_volume_keydown.FlutterAndroidVolumeKeydownPlugin.eventSink
|
||||
import android.view.KeyEvent.KEYCODE_VOLUME_DOWN
|
||||
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() {
|
||||
|
||||
private val MEDIA_STORE_CHANNEL = "eu.twonly/mediaStore"
|
||||
private lateinit var channel: MethodChannel
|
||||
|
||||
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
|
||||
if (keyCode == KEYCODE_VOLUME_DOWN && eventSink != null) {
|
||||
eventSink!!.success(true)
|
||||
|
|
@ -33,84 +18,4 @@ class MainActivity : FlutterFragmentActivity() {
|
|||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
package eu.twonly
|
||||
|
||||
class MyMediaStorageProxy {
|
||||
|
||||
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.9 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.7 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 6.5 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 9.2 KiB |
|
|
@ -6,9 +6,4 @@
|
|||
android:drawable="@drawable/ic_launcher_foreground"
|
||||
android:inset="16%" />
|
||||
</foreground>
|
||||
<monochrome>
|
||||
<inset
|
||||
android:drawable="@drawable/ic_launcher_monochrome"
|
||||
android:inset="16%" />
|
||||
</monochrome>
|
||||
</adaptive-icon>
|
||||
|
|
|
|||
|
|
@ -8,5 +8,4 @@
|
|||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
<application android:usesCleartextTraffic="true" >
|
||||
</application>
|
||||
<meta-data android:name="firebase_performance_collection_deactivated" android:value="true" />
|
||||
</manifest>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1 +0,0 @@
|
|||
5cde0a78d118f9e043e7443ceca0f306
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.6 KiB |
Binary file not shown.
|
|
@ -12,4 +12,3 @@ targets:
|
|||
databases:
|
||||
twonly_db: lib/src/database/twonly.db.dart
|
||||
twonly_database: lib/src/database/twonly_database_old.dart
|
||||
schema_dir: lib/src/database/schemas
|
||||
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 7930d9727019344238297d810661bc3e8f724c37
|
||||
1
dependencies/flutter_zxing
vendored
Submodule
1
dependencies/flutter_zxing
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
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
|
||||
|
||||
var pushNotificationText: [PushKind: String] = [:]
|
||||
var title = "[Unknown]"
|
||||
var title = "Someone"
|
||||
|
||||
// Define the messages based on the system language
|
||||
if systemLanguage.contains("de") { // German
|
||||
title = "[Unbekannt]"
|
||||
title = "Jemand"
|
||||
pushNotificationText = [
|
||||
.text: "hat eine Nachricht{inGroup} gesendet.",
|
||||
.twonly: "hat ein twonly{inGroup} gesendet.",
|
||||
|
|
@ -238,7 +238,7 @@ func getPushNotificationText(pushNotification: PushNotification) -> (String, Str
|
|||
.text: "sent a message{inGroup}.",
|
||||
.twonly: "sent a twonly{inGroup}.",
|
||||
.video: "sent a video{inGroup}.",
|
||||
.image: "sent an image{inGroup}.",
|
||||
.image: "sent a image{inGroup}.",
|
||||
.audio: "sent a voice message{inGroup}.",
|
||||
.contactRequest: "wants to connect with you.",
|
||||
.acceptRequest: "is now connected with you.",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Uncomment this line to define a global platform for your project
|
||||
platform :ios, '15.5'
|
||||
platform :ios, '15.0'
|
||||
use_frameworks!
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
|
|
@ -43,13 +43,6 @@ target 'Runner' do
|
|||
target 'RunnerTests' do
|
||||
inherit! :search_paths
|
||||
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
|
||||
|
||||
post_install do |installer|
|
||||
|
|
|
|||
260
ios/Podfile.lock
260
ios/Podfile.lock
|
|
@ -1,6 +1,4 @@
|
|||
PODS:
|
||||
- app_links (7.0.0):
|
||||
- Flutter
|
||||
- audio_waveforms (0.0.1):
|
||||
- Flutter
|
||||
- background_downloader (0.0.1):
|
||||
|
|
@ -13,37 +11,6 @@ PODS:
|
|||
- Flutter
|
||||
- device_info_plus (0.0.1):
|
||||
- Flutter
|
||||
- DKImagePickerController/Core (4.3.9):
|
||||
- DKImagePickerController/ImageDataManager
|
||||
- DKImagePickerController/Resource
|
||||
- DKImagePickerController/ImageDataManager (4.3.9)
|
||||
- DKImagePickerController/PhotoGallery (4.3.9):
|
||||
- DKImagePickerController/Core
|
||||
- DKPhotoGallery
|
||||
- DKImagePickerController/Resource (4.3.9)
|
||||
- DKPhotoGallery (0.0.19):
|
||||
- DKPhotoGallery/Core (= 0.0.19)
|
||||
- DKPhotoGallery/Model (= 0.0.19)
|
||||
- DKPhotoGallery/Preview (= 0.0.19)
|
||||
- DKPhotoGallery/Resource (= 0.0.19)
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Core (0.0.19):
|
||||
- DKPhotoGallery/Model
|
||||
- DKPhotoGallery/Preview
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Model (0.0.19):
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Preview (0.0.19):
|
||||
- DKPhotoGallery/Model
|
||||
- DKPhotoGallery/Resource
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Resource (0.0.19):
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- emoji_picker_flutter (0.0.1):
|
||||
- Flutter
|
||||
- ffmpeg_kit_flutter_new (1.0.0):
|
||||
|
|
@ -51,58 +18,55 @@ PODS:
|
|||
- Flutter
|
||||
- ffmpeg_kit_flutter_new/full-gpl (1.0.0):
|
||||
- Flutter
|
||||
- file_picker (0.0.1):
|
||||
- DKImagePickerController/PhotoGallery
|
||||
- Flutter
|
||||
- Firebase (12.6.0):
|
||||
- Firebase/Core (= 12.6.0)
|
||||
- Firebase/Core (12.6.0):
|
||||
- Firebase (12.4.0):
|
||||
- Firebase/Core (= 12.4.0)
|
||||
- Firebase/Core (12.4.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseAnalytics (~> 12.6.0)
|
||||
- Firebase/CoreOnly (12.6.0):
|
||||
- FirebaseCore (~> 12.6.0)
|
||||
- Firebase/Messaging (12.6.0):
|
||||
- FirebaseAnalytics (~> 12.4.0)
|
||||
- Firebase/CoreOnly (12.4.0):
|
||||
- FirebaseCore (~> 12.4.0)
|
||||
- Firebase/Messaging (12.4.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseMessaging (~> 12.6.0)
|
||||
- firebase_core (4.3.0):
|
||||
- Firebase/CoreOnly (= 12.6.0)
|
||||
- FirebaseMessaging (~> 12.4.0)
|
||||
- firebase_core (4.2.1):
|
||||
- Firebase/CoreOnly (= 12.4.0)
|
||||
- Flutter
|
||||
- firebase_messaging (16.1.0):
|
||||
- Firebase/Messaging (= 12.6.0)
|
||||
- firebase_messaging (16.0.4):
|
||||
- Firebase/Messaging (= 12.4.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- FirebaseAnalytics (12.6.0):
|
||||
- FirebaseAnalytics/Default (= 12.6.0)
|
||||
- FirebaseCore (~> 12.6.0)
|
||||
- FirebaseInstallations (~> 12.6.0)
|
||||
- FirebaseAnalytics (12.4.0):
|
||||
- FirebaseAnalytics/Default (= 12.4.0)
|
||||
- FirebaseCore (~> 12.4.0)
|
||||
- FirebaseInstallations (~> 12.4.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||
- GoogleUtilities/Network (~> 8.1)
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||
- nanopb (~> 3.30910.0)
|
||||
- FirebaseAnalytics/Default (12.6.0):
|
||||
- FirebaseCore (~> 12.6.0)
|
||||
- FirebaseInstallations (~> 12.6.0)
|
||||
- GoogleAppMeasurement/Default (= 12.6.0)
|
||||
- FirebaseAnalytics/Default (12.4.0):
|
||||
- FirebaseCore (~> 12.4.0)
|
||||
- FirebaseInstallations (~> 12.4.0)
|
||||
- GoogleAppMeasurement/Default (= 12.4.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||
- GoogleUtilities/Network (~> 8.1)
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||
- nanopb (~> 3.30910.0)
|
||||
- FirebaseCore (12.6.0):
|
||||
- FirebaseCoreInternal (~> 12.6.0)
|
||||
- FirebaseCore (12.4.0):
|
||||
- FirebaseCoreInternal (~> 12.4.0)
|
||||
- GoogleUtilities/Environment (~> 8.1)
|
||||
- GoogleUtilities/Logger (~> 8.1)
|
||||
- FirebaseCoreInternal (12.6.0):
|
||||
- FirebaseCoreInternal (12.4.0):
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||
- FirebaseInstallations (12.6.0):
|
||||
- FirebaseCore (~> 12.6.0)
|
||||
- FirebaseInstallations (12.4.0):
|
||||
- FirebaseCore (~> 12.4.0)
|
||||
- GoogleUtilities/Environment (~> 8.1)
|
||||
- GoogleUtilities/UserDefaults (~> 8.1)
|
||||
- PromisesObjC (~> 2.4)
|
||||
- FirebaseMessaging (12.6.0):
|
||||
- FirebaseCore (~> 12.6.0)
|
||||
- FirebaseInstallations (~> 12.6.0)
|
||||
- FirebaseMessaging (12.4.0):
|
||||
- FirebaseCore (~> 12.4.0)
|
||||
- FirebaseInstallations (~> 12.4.0)
|
||||
- GoogleDataTransport (~> 10.1)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||
- GoogleUtilities/Environment (~> 8.1)
|
||||
|
|
@ -122,42 +86,35 @@ PODS:
|
|||
- flutter_secure_storage_darwin (10.0.0):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- flutter_sharing_intent (1.0.1):
|
||||
- Flutter
|
||||
- flutter_volume_controller (0.0.1):
|
||||
- Flutter
|
||||
- flutter_zxing (0.0.1):
|
||||
- Flutter
|
||||
- gal (1.0.0):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- 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):
|
||||
- GoogleAdsOnDeviceConversion (3.1.0):
|
||||
- GoogleUtilities/Environment (~> 8.1)
|
||||
- GoogleUtilities/Logger (~> 8.1)
|
||||
- GoogleUtilities/Network (~> 8.1)
|
||||
- nanopb (~> 3.30910.0)
|
||||
- GoogleAppMeasurement/Core (12.6.0):
|
||||
- GoogleAppMeasurement/Core (12.4.0):
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||
- GoogleUtilities/Network (~> 8.1)
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||
- nanopb (~> 3.30910.0)
|
||||
- GoogleAppMeasurement/Default (12.6.0):
|
||||
- GoogleAdsOnDeviceConversion (~> 3.2.0)
|
||||
- GoogleAppMeasurement/Core (= 12.6.0)
|
||||
- GoogleAppMeasurement/IdentitySupport (= 12.6.0)
|
||||
- GoogleAppMeasurement/Default (12.4.0):
|
||||
- GoogleAdsOnDeviceConversion (~> 3.1.0)
|
||||
- GoogleAppMeasurement/Core (= 12.4.0)
|
||||
- GoogleAppMeasurement/IdentitySupport (= 12.4.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||
- GoogleUtilities/Network (~> 8.1)
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||
- nanopb (~> 3.30910.0)
|
||||
- GoogleAppMeasurement/IdentitySupport (12.6.0):
|
||||
- GoogleAppMeasurement/Core (= 12.6.0)
|
||||
- GoogleAppMeasurement/IdentitySupport (12.4.0):
|
||||
- GoogleAppMeasurement/Core (= 12.4.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||
- GoogleUtilities/MethodSwizzler (~> 8.1)
|
||||
- GoogleUtilities/Network (~> 8.1)
|
||||
|
|
@ -166,16 +123,6 @@ PODS:
|
|||
- GoogleDataTransport (10.1.0):
|
||||
- nanopb (~> 3.30910.0)
|
||||
- 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/AppDelegateSwizzler (= 8.1.0)
|
||||
- GoogleUtilities/Environment (= 8.1.0)
|
||||
|
|
@ -216,12 +163,8 @@ PODS:
|
|||
- GoogleUtilities/UserDefaults (8.1.0):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Privacy
|
||||
- GTMSessionFetcher/Core (3.5.0)
|
||||
- image_picker_ios (0.0.1):
|
||||
- Flutter
|
||||
- in_app_purchase_storekit (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- libwebp (1.5.0):
|
||||
- libwebp/demux (= 1.5.0)
|
||||
- libwebp/mux (= 1.5.0)
|
||||
|
|
@ -240,33 +183,14 @@ PODS:
|
|||
- Mantle (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/decode (= 3.30910.0)
|
||||
- nanopb/encode (= 3.30910.0)
|
||||
- nanopb/decode (3.30910.0)
|
||||
- nanopb/encode (3.30910.0)
|
||||
- no_screenshot (0.3.2-beta.3):
|
||||
- "no_screenshot (0.0.1+4)":
|
||||
- Flutter
|
||||
- ScreenProtectorKit (~> 1.3.1)
|
||||
- objective_c (0.0.1):
|
||||
- Flutter
|
||||
- package_info_plus (0.4.5):
|
||||
- Flutter
|
||||
- path_provider_foundation (0.0.1):
|
||||
|
|
@ -278,17 +202,12 @@ PODS:
|
|||
- restart_app (0.0.1):
|
||||
- Flutter
|
||||
- ScreenProtectorKit (1.3.1)
|
||||
- SDWebImage (5.21.5):
|
||||
- SDWebImage/Core (= 5.21.5)
|
||||
- SDWebImage/Core (5.21.5)
|
||||
- SDWebImageWebPCoder (0.15.0):
|
||||
- SDWebImage (5.21.3):
|
||||
- SDWebImage/Core (= 5.21.3)
|
||||
- SDWebImage/Core (5.21.3)
|
||||
- SDWebImageWebPCoder (0.14.6):
|
||||
- libwebp (~> 1.0)
|
||||
- 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):
|
||||
- Flutter
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
|
|
@ -322,8 +241,7 @@ PODS:
|
|||
- sqlite3/perf-threadsafe
|
||||
- sqlite3/rtree
|
||||
- sqlite3/session
|
||||
- SwiftProtobuf (1.33.3)
|
||||
- SwiftyGif (5.4.5)
|
||||
- SwiftProtobuf (1.33.1)
|
||||
- url_launcher_ios (0.0.1):
|
||||
- Flutter
|
||||
- video_player_avfoundation (0.0.1):
|
||||
|
|
@ -331,7 +249,6 @@ PODS:
|
|||
- FlutterMacOS
|
||||
|
||||
DEPENDENCIES:
|
||||
- app_links (from `.symlinks/plugins/app_links/ios`)
|
||||
- audio_waveforms (from `.symlinks/plugins/audio_waveforms/ios`)
|
||||
- background_downloader (from `.symlinks/plugins/background_downloader/ios`)
|
||||
- camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`)
|
||||
|
|
@ -340,7 +257,6 @@ DEPENDENCIES:
|
|||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||
- emoji_picker_flutter (from `.symlinks/plugins/emoji_picker_flutter/ios`)
|
||||
- ffmpeg_kit_flutter_new (from `.symlinks/plugins/ffmpeg_kit_flutter_new/ios`)
|
||||
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||
- Firebase
|
||||
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
|
||||
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
||||
|
|
@ -352,22 +268,17 @@ DEPENDENCIES:
|
|||
- 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_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_zxing (from `.symlinks/plugins/flutter_zxing/ios`)
|
||||
- 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
|
||||
- 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`)
|
||||
- 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`)
|
||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/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`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
|
||||
|
|
@ -378,8 +289,6 @@ DEPENDENCIES:
|
|||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- DKImagePickerController
|
||||
- DKPhotoGallery
|
||||
- Firebase
|
||||
- FirebaseAnalytics
|
||||
- FirebaseCore
|
||||
|
|
@ -389,29 +298,18 @@ SPEC REPOS:
|
|||
- GoogleAdsOnDeviceConversion
|
||||
- GoogleAppMeasurement
|
||||
- GoogleDataTransport
|
||||
- GoogleMLKit
|
||||
- GoogleToolboxForMac
|
||||
- GoogleUtilities
|
||||
- GTMSessionFetcher
|
||||
- libwebp
|
||||
- Mantle
|
||||
- MLImage
|
||||
- MLKitBarcodeScanning
|
||||
- MLKitCommon
|
||||
- MLKitVision
|
||||
- nanopb
|
||||
- PromisesObjC
|
||||
- ScreenProtectorKit
|
||||
- SDWebImage
|
||||
- SDWebImageWebPCoder
|
||||
- Sentry
|
||||
- sqlite3
|
||||
- SwiftProtobuf
|
||||
- SwiftyGif
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
app_links:
|
||||
:path: ".symlinks/plugins/app_links/ios"
|
||||
audio_waveforms:
|
||||
:path: ".symlinks/plugins/audio_waveforms/ios"
|
||||
background_downloader:
|
||||
|
|
@ -428,8 +326,6 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/emoji_picker_flutter/ios"
|
||||
ffmpeg_kit_flutter_new:
|
||||
:path: ".symlinks/plugins/ffmpeg_kit_flutter_new/ios"
|
||||
file_picker:
|
||||
:path: ".symlinks/plugins/file_picker/ios"
|
||||
firebase_core:
|
||||
:path: ".symlinks/plugins/firebase_core/ios"
|
||||
firebase_messaging:
|
||||
|
|
@ -444,26 +340,18 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/flutter_local_notifications/ios"
|
||||
flutter_secure_storage_darwin:
|
||||
:path: ".symlinks/plugins/flutter_secure_storage_darwin/darwin"
|
||||
flutter_sharing_intent:
|
||||
:path: ".symlinks/plugins/flutter_sharing_intent/ios"
|
||||
flutter_volume_controller:
|
||||
:path: ".symlinks/plugins/flutter_volume_controller/ios"
|
||||
flutter_zxing:
|
||||
:path: ".symlinks/plugins/flutter_zxing/ios"
|
||||
gal:
|
||||
: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:
|
||||
:path: ".symlinks/plugins/image_picker_ios/ios"
|
||||
in_app_purchase_storekit:
|
||||
:path: ".symlinks/plugins/in_app_purchase_storekit/darwin"
|
||||
local_auth_darwin:
|
||||
:path: ".symlinks/plugins/local_auth_darwin/darwin"
|
||||
no_screenshot:
|
||||
:path: ".symlinks/plugins/no_screenshot/ios"
|
||||
objective_c:
|
||||
:path: ".symlinks/plugins/objective_c/ios"
|
||||
package_info_plus:
|
||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||
path_provider_foundation:
|
||||
|
|
@ -472,8 +360,6 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||
restart_app:
|
||||
:path: ".symlinks/plugins/restart_app/ios"
|
||||
sentry_flutter:
|
||||
:path: ".symlinks/plugins/sentry_flutter/ios"
|
||||
share_plus:
|
||||
:path: ".symlinks/plugins/share_plus/ios"
|
||||
shared_preferences_foundation:
|
||||
|
|
@ -488,75 +374,57 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/video_player_avfoundation/darwin"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
app_links: a754cbec3c255bd4bbb4d236ecc06f28cd9a7ce8
|
||||
audio_waveforms: a6dde7fe7c0ea05f06ffbdb0f7c1b2b2ba6cedcf
|
||||
background_downloader: 50e91d979067b82081aba359d7d916b3ba5fadad
|
||||
camera_avfoundation: 5675ca25298b6f81fa0a325188e7df62cc217741
|
||||
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
||||
cryptography_flutter_plus: 44f4e9e4079395fcbb3e7809c0ac2c6ae2d9576f
|
||||
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
|
||||
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
|
||||
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
|
||||
emoji_picker_flutter: ece213fc274bdddefb77d502d33080dc54e616cc
|
||||
ffmpeg_kit_flutter_new: 12426a19f10ac81186c67c6ebc4717f8f4364b7f
|
||||
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
|
||||
Firebase: a451a7b61536298fd5cbfe3a746fd40443a50679
|
||||
firebase_core: ba00a168e719694f38960502ceb560285603d073
|
||||
firebase_messaging: bf0e29321927edc02a563c984dbfa5b063864b15
|
||||
FirebaseAnalytics: d0a97a0db6425e5a5d966340b87f92ca7b13a557
|
||||
FirebaseCore: 0e38ad5d62d980a47a64b8e9301ffa311457be04
|
||||
FirebaseCoreInternal: 69bf1306a05b8ac43004f6cc1f804bb7b05b229e
|
||||
FirebaseInstallations: 631b38da2e11a83daa4bfb482f79d286a5dfa7ad
|
||||
FirebaseMessaging: a61bc42dcab3f7a346d94bbb54dab2c9435b18b2
|
||||
Firebase: f07b15ae5a6ec0f93713e30b923d9970d144af3e
|
||||
firebase_core: f1aafb21c14f497e5498f7ffc4dc63cbb52b2594
|
||||
firebase_messaging: c17a29984eafce4b2997fe078bb0a9e0b06f5dde
|
||||
FirebaseAnalytics: 0fc2b20091f0ddd21bf73397cf8f0eb5346dc24f
|
||||
FirebaseCore: bb595f3114953664e3c1dc032f008a244147cfd3
|
||||
FirebaseCoreInternal: d7f5a043c2cd01a08103ab586587c1468047bca6
|
||||
FirebaseInstallations: ae9f4902cb5bf1d0c5eaa31ec1f4e5495a0714e2
|
||||
FirebaseMessaging: d33971b7bb252745ea6cd31ab190d1a1df4b8ed5
|
||||
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
|
||||
flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1
|
||||
flutter_keyboard_visibility_temp_fork: 95b2d534bacf6ac62e7fcbe5c2a9e2c2a17ce06f
|
||||
flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb
|
||||
flutter_secure_storage_darwin: acdb3f316ed05a3e68f856e0353b133eec373a23
|
||||
flutter_sharing_intent: 0c1e53949f09fa8df8ac2268505687bde8ff264c
|
||||
flutter_secure_storage_darwin: ce237a8775b39723566dc72571190a3769d70468
|
||||
flutter_volume_controller: c2be490cb0487e8b88d0d9fc2b7e1c139a4ebccb
|
||||
flutter_zxing: e8bcc43bd3056c70c271b732ed94e7a16fd62f93
|
||||
gal: baecd024ebfd13c441269ca7404792a7152fde89
|
||||
google_mlkit_barcode_scanning: 8f5987f244a43fe1167689c548342a5174108159
|
||||
google_mlkit_commons: 2abe6a70e1824e431d16a51085cb475b672c8aab
|
||||
GoogleAdsOnDeviceConversion: d68c69dd9581a0f5da02617b6f377e5be483970f
|
||||
GoogleAppMeasurement: 3bf40aff49a601af5da1c3345702fcb4991d35ee
|
||||
GoogleAdsOnDeviceConversion: e03a386840803ea7eef3fd22a061930142c039c1
|
||||
GoogleAppMeasurement: 1e718274b7e015cefd846ac1fcf7820c70dc017d
|
||||
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
||||
GoogleMLKit: eff9e23ec1d90ea4157a1ee2e32a4f610c5b3318
|
||||
GoogleToolboxForMac: d1a2cbf009c453f4d6ded37c105e2f67a32206d8
|
||||
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
||||
GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6
|
||||
image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326
|
||||
in_app_purchase_storekit: 22cca7d08eebca9babdf4d07d0baccb73325d3c8
|
||||
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
|
||||
local_auth_darwin: c3ee6cce0a8d56be34c8ccb66ba31f7f180aaebb
|
||||
Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d
|
||||
MLImage: 0ad1c5f50edd027672d8b26b0fee78a8b4a0fc56
|
||||
MLKitBarcodeScanning: 0a3064da0a7f49ac24ceb3cb46a5bc67496facd2
|
||||
MLKitCommon: 07c2c33ae5640e5380beaaa6e4b9c249a205542d
|
||||
MLKitVision: 45e79d68845a2de77e2dd4d7f07947f0ed157b0e
|
||||
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
|
||||
no_screenshot: 89e778ede9f1e39cc3fb9404d782a42712f2a0b2
|
||||
objective_c: 89e720c30d716b036faf9c9684022048eee1eee2
|
||||
no_screenshot: 6d183496405a3ab709a67a54e5cd0f639e94729e
|
||||
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
||||
path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
|
||||
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
|
||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||
restart_app: 9cda5378aacc5000e3f66ee76a9201534e7d3ecf
|
||||
ScreenProtectorKit: 83a6281b02c7a5902ee6eac4f5045f674e902ae4
|
||||
SDWebImage: e9c98383c7572d713c1a0d7dd2783b10599b9838
|
||||
SDWebImageWebPCoder: 0e06e365080397465cc73a7a9b472d8a3bd0f377
|
||||
Sentry: b53951377b78e21a734f5dc8318e333dbfc682d7
|
||||
sentry_flutter: 4c33648b7e83310aa1fdb1b10c5491027d9643f0
|
||||
SDWebImage: 16309af6d214ba3f77a7c6f6fdda888cb313a50a
|
||||
SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380
|
||||
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
||||
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
||||
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
||||
sqlite3: 73513155ec6979715d3904ef53a8d68892d4032b
|
||||
sqlite3_flutter_libs: 83f8e9f5b6554077f1d93119fe20ebaa5f3a9ef1
|
||||
SwiftProtobuf: e1b437c8e31a4c5577b643249a0bb62ed4f02153
|
||||
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||
SwiftProtobuf: 533a18409c3ca3a6156b2b1e46afd0f69e751aba
|
||||
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
|
||||
video_player_avfoundation: dd410b52df6d2466a42d28550e33e4146928280a
|
||||
|
||||
PODFILE CHECKSUM: ae041999f13ba7b2285ff9ad9bc688ed647bbcb7
|
||||
PODFILE CHECKSUM: 47470fbd5b59affa461eaf943ac57acce81e0ee8
|
||||
|
||||
COCOAPODS: 1.16.2
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
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 */; };
|
||||
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 */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
|
|
@ -19,8 +18,6 @@
|
|||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
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, ); }; };
|
||||
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 */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
|
|
@ -39,13 +36,6 @@
|
|||
remoteGlobalIDString = D21FCEA32D9F2B750088701D;
|
||||
remoteInfo = NotificationService;
|
||||
};
|
||||
D25D4D782EFF41DB0029F805 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = D25D4D6F2EFF41DB0029F805;
|
||||
remoteInfo = ShareExtension;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
|
|
@ -65,7 +55,6 @@
|
|||
dstPath = "";
|
||||
dstSubfolderSpec = 13;
|
||||
files = (
|
||||
D25D4D7A2EFF41DB0029F805 /* ShareExtension.appex in Embed Foundation Extensions */,
|
||||
D21FCEAB2D9F2B750088701D /* NotificationService.appex in Embed Foundation Extensions */,
|
||||
);
|
||||
name = "Embed Foundation Extensions";
|
||||
|
|
@ -77,12 +66,10 @@
|
|||
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>"; };
|
||||
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>"; };
|
||||
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; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
|
|
@ -99,15 +86,10 @@
|
|||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
|
|
@ -121,13 +103,6 @@
|
|||
);
|
||||
target = D21FCEA32D9F2B750088701D /* NotificationService */;
|
||||
};
|
||||
D25D4D7E2EFF41DB0029F805 /* Exceptions for "ShareExtension" folder in "ShareExtension" target */ = {
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
Info.plist,
|
||||
);
|
||||
target = D25D4D6F2EFF41DB0029F805 /* ShareExtension */;
|
||||
};
|
||||
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||
|
|
@ -139,14 +114,6 @@
|
|||
path = NotificationService;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D25D4D712EFF41DB0029F805 /* ShareExtension */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
D25D4D7E2EFF41DB0029F805 /* Exceptions for "ShareExtension" folder in "ShareExtension" target */,
|
||||
);
|
||||
path = ShareExtension;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXFileSystemSynchronizedRootGroup section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
|
@ -163,7 +130,6 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
CA4FDF5DD8F229C30DE512AF /* Pods_Runner.framework in Frameworks */,
|
||||
D25D4D1E2EF626E30029F805 /* StoreKit.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
@ -175,14 +141,6 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D25D4D6D2EFF41DB0029F805 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
30EBDD0F93DC44E774F3B785 /* Pods_ShareExtension.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
|
|
@ -211,7 +169,6 @@
|
|||
9740EEB11CF90186004384FC /* Flutter */,
|
||||
97C146F01CF9000F007C117D /* Runner */,
|
||||
D21FCEA52D9F2B750088701D /* NotificationService */,
|
||||
D25D4D712EFF41DB0029F805 /* ShareExtension */,
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||
16FBC6F5B58E1C6646F5D447 /* GoogleService-Info.plist */,
|
||||
|
|
@ -226,7 +183,6 @@
|
|||
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
|
||||
D21FCEA42D9F2B750088701D /* NotificationService.appex */,
|
||||
D25D4D702EFF41DB0029F805 /* ShareExtension.appex */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -234,7 +190,6 @@
|
|||
97C146F01CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D25D4D802EFF437F0029F805 /* RunnerDebug.entitlements */,
|
||||
D2265DD42D920142000D99BB /* Runner.entitlements */,
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||
|
|
@ -251,11 +206,9 @@
|
|||
E5079CCEE4804DB65AA3F23F /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D25D4D1D2EF626E30029F805 /* StoreKit.framework */,
|
||||
A198C9B5D90584C4F96206B2 /* Pods_NotificationService.framework */,
|
||||
EE2CCFEE4ABECF33852F7735 /* Pods_Runner.framework */,
|
||||
DC1EE71614E1B4F84D6FDC2D /* Pods_RunnerTests.framework */,
|
||||
E190E82D9973B318A389650B /* Pods_ShareExtension.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -272,9 +225,6 @@
|
|||
4D78471482626812FE2468E9 /* Pods-NotificationService.debug.xcconfig */,
|
||||
35366FD433E0EFC6EF19A452 /* Pods-NotificationService.release.xcconfig */,
|
||||
F02F7A1D63544AA9F23A1085 /* Pods-NotificationService.profile.xcconfig */,
|
||||
15CEF849B61A620CFB2DC5F1 /* Pods-ShareExtension.debug.xcconfig */,
|
||||
A22BD564F16069E5FCB60767 /* Pods-ShareExtension.release.xcconfig */,
|
||||
39FB86A38393489D58A01B0B /* Pods-ShareExtension.profile.xcconfig */,
|
||||
);
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -320,7 +270,6 @@
|
|||
);
|
||||
dependencies = (
|
||||
D21FCEAA2D9F2B750088701D /* PBXTargetDependency */,
|
||||
D25D4D792EFF41DB0029F805 /* PBXTargetDependency */,
|
||||
);
|
||||
name = Runner;
|
||||
productName = Runner;
|
||||
|
|
@ -348,27 +297,6 @@
|
|||
productReference = D21FCEA42D9F2B750088701D /* NotificationService.appex */;
|
||||
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 */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
|
|
@ -376,7 +304,7 @@
|
|||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastSwiftUpdateCheck = 2610;
|
||||
LastSwiftUpdateCheck = 1620;
|
||||
LastUpgradeCheck = 1510;
|
||||
ORGANIZATIONNAME = "";
|
||||
TargetAttributes = {
|
||||
|
|
@ -391,9 +319,6 @@
|
|||
D21FCEA32D9F2B750088701D = {
|
||||
CreatedOnToolsVersion = 16.2;
|
||||
};
|
||||
D25D4D6F2EFF41DB0029F805 = {
|
||||
CreatedOnToolsVersion = 26.1.1;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
||||
|
|
@ -412,7 +337,6 @@
|
|||
97C146ED1CF9000F007C117D /* Runner */,
|
||||
331C8080294A63A400263BE5 /* RunnerTests */,
|
||||
D21FCEA32D9F2B750088701D /* NotificationService */,
|
||||
D25D4D6F2EFF41DB0029F805 /* ShareExtension */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
|
@ -444,13 +368,6 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D25D4D6E2EFF41DB0029F805 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
|
|
@ -531,28 +448,6 @@
|
|||
shellPath = /bin/sh;
|
||||
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 */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
|
|
@ -634,13 +529,6 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D25D4D6C2EFF41DB0029F805 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
|
|
@ -654,11 +542,6 @@
|
|||
target = D21FCEA32D9F2B750088701D /* NotificationService */;
|
||||
targetProxy = D21FCEA92D9F2B750088701D /* PBXContainerItemProxy */;
|
||||
};
|
||||
D25D4D792EFF41DB0029F805 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = D25D4D6F2EFF41DB0029F805 /* ShareExtension */;
|
||||
targetProxy = D25D4D782EFF41DB0029F805 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
|
|
@ -744,7 +627,6 @@
|
|||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
CUSTOM_GROUP_ID = group.eu.twonly.shareIntent;
|
||||
DEVELOPMENT_TEAM = CN332ZUGRP;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
|
|
@ -941,9 +823,8 @@
|
|||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/RunnerDebug.entitlements;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
CUSTOM_GROUP_ID = group.eu.twonly.shareIntent;
|
||||
DEVELOPMENT_TEAM = CN332ZUGRP;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
|
|
@ -978,7 +859,6 @@
|
|||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
CUSTOM_GROUP_ID = group.eu.twonly.shareIntent;
|
||||
DEVELOPMENT_TEAM = CN332ZUGRP;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
|
|
@ -1120,133 +1000,6 @@
|
|||
};
|
||||
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 */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
|
|
@ -1290,16 +1043,6 @@
|
|||
defaultConfigurationIsVisible = 0;
|
||||
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 */
|
||||
};
|
||||
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@
|
|||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
buildConfiguration = "Release"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||
|
|
|
|||
|
|
@ -1,49 +1,37 @@
|
|||
import CryptoKit
|
||||
import Flutter
|
||||
import Foundation
|
||||
import UIKit
|
||||
import UserNotifications
|
||||
import flutter_sharing_intent
|
||||
import CryptoKit
|
||||
import Foundation
|
||||
|
||||
|
||||
@main
|
||||
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
|
||||
if #available(iOS 10.0, *) {
|
||||
//UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
override func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
|
||||
|
||||
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, 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")
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -2,27 +2,6 @@
|
|||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<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>
|
||||
<true/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
|
|
@ -49,8 +28,6 @@
|
|||
<false/>
|
||||
<key>FirebaseAutomaticScreenReportingEnabled</key>
|
||||
<false/>
|
||||
<key>FlutterDeepLinkingEnabled</key>
|
||||
<false/>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
|
|
@ -87,21 +64,5 @@
|
|||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</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>
|
||||
</plist>
|
||||
|
|
|
|||
|
|
@ -4,10 +4,6 @@
|
|||
<dict>
|
||||
<key>aps-environment</key>
|
||||
<string>development</string>
|
||||
<key>com.apple.developer.associated-domains</key>
|
||||
<array>
|
||||
<string>applinks:me.twonly.eu</string>
|
||||
</array>
|
||||
<key>keychain-access-groups</key>
|
||||
<array>
|
||||
<string>$(AppIdentifierPrefix)eu.twonly.shared</string>
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
<?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>
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
<?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>
|
||||
|
|
@ -1,553 +0,0 @@
|
|||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
<?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>
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
<?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>
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
class ShareViewController: FSIShareViewController {
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
arb-dir: lib/src/localization/translations
|
||||
template-arb-file: en.arb
|
||||
arb-dir: lib/src/localization
|
||||
template-arb-file: app_en.arb
|
||||
output-localization-file: app_localizations.dart
|
||||
untranslated-messages-file: build/l10n.log
|
||||
output-dir: lib/src/localization/generated
|
||||
|
|
|
|||
24
lib/app.dart
24
lib/app.dart
|
|
@ -1,12 +1,10 @@
|
|||
import 'dart:async';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
import 'package:twonly/src/localization/generated/app_localizations.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/services/subscription.service.dart';
|
||||
import 'package:twonly/src/utils/log.dart';
|
||||
|
|
@ -41,8 +39,8 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
|||
await setUserPlan();
|
||||
};
|
||||
|
||||
globalCallbackUpdatePlan = (SubscriptionPlan plan) {
|
||||
context.read<PurchasesProvider>().updatePlan(plan);
|
||||
globalCallbackUpdatePlan = (SubscriptionPlan plan) async {
|
||||
await context.read<CustomChangeProvider>().updatePlan(plan);
|
||||
};
|
||||
|
||||
unawaited(initAsync());
|
||||
|
|
@ -52,7 +50,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
|||
final user = await getUser();
|
||||
if (user != null && mounted) {
|
||||
if (mounted) {
|
||||
context.read<PurchasesProvider>().updatePlan(
|
||||
await context.read<CustomChangeProvider>().updatePlan(
|
||||
planFromString(user.subscriptionPlan),
|
||||
);
|
||||
}
|
||||
|
|
@ -61,7 +59,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
|||
|
||||
Future<void> initAsync() async {
|
||||
await setUserPlan();
|
||||
await apiService.connect();
|
||||
await apiService.connect(force: true);
|
||||
await apiService.listenToNetworkChanges();
|
||||
}
|
||||
|
||||
|
|
@ -72,7 +70,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
|||
if (wasPaused) {
|
||||
globalIsAppInBackground = false;
|
||||
twonlyDB.markUpdated();
|
||||
unawaited(apiService.connect());
|
||||
unawaited(apiService.connect(force: true));
|
||||
}
|
||||
} else if (state == AppLifecycleState.paused) {
|
||||
wasPaused = true;
|
||||
|
|
@ -94,7 +92,6 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
|||
listenable: context.watch<SettingsChangeProvider>(),
|
||||
builder: (BuildContext context, Widget? child) {
|
||||
return MaterialApp(
|
||||
scaffoldMessengerKey: globalRootScaffoldMessengerKey,
|
||||
restorationScopeId: 'app',
|
||||
localizationsDelegates: const [
|
||||
AppLocalizations.delegate,
|
||||
|
|
@ -158,14 +155,11 @@ class _AppMainWidgetState extends State<AppMainWidget> {
|
|||
bool _showDatabaseMigration = false;
|
||||
bool _showOnboarding = true;
|
||||
bool _isLoaded = false;
|
||||
bool _skipBackup = false;
|
||||
int _initialPage = 0;
|
||||
|
||||
(Future<int>?, bool) _proofOfWork = (null, false);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_initialPage = widget.initialPage;
|
||||
initAsync();
|
||||
super.initState();
|
||||
}
|
||||
|
|
@ -177,9 +171,6 @@ class _AppMainWidgetState extends State<AppMainWidget> {
|
|||
if (gUser.appVersion < 62) {
|
||||
_showDatabaseMigration = true;
|
||||
}
|
||||
if (!gUser.startWithCameraOpen) {
|
||||
_initialPage = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_isUserCreated && !_showDatabaseMigration) {
|
||||
|
|
@ -212,16 +203,15 @@ class _AppMainWidgetState extends State<AppMainWidget> {
|
|||
if (_showDatabaseMigration) {
|
||||
child = const DatabaseMigrationView();
|
||||
} else if (_isUserCreated) {
|
||||
if (gUser.twonlySafeBackup == null && !_skipBackup && kReleaseMode) {
|
||||
if (gUser.twonlySafeBackup == null) {
|
||||
child = TwonlyIdentityBackupView(
|
||||
callBack: () {
|
||||
_skipBackup = true;
|
||||
setState(() {});
|
||||
},
|
||||
);
|
||||
} else {
|
||||
child = HomeView(
|
||||
initialPage: _initialPage,
|
||||
initialPage: widget.initialPage,
|
||||
);
|
||||
}
|
||||
} else if (_showOnboarding) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:ui';
|
||||
|
||||
import 'package:camera/camera.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:twonly/src/database/twonly.db.dart';
|
||||
import 'package:twonly/src/model/json/userdata.dart';
|
||||
import 'package:twonly/src/services/api.service.dart';
|
||||
|
|
@ -32,10 +33,3 @@ void Function(SubscriptionPlan plan) globalCallbackUpdatePlan =
|
|||
Map<String, VoidCallback> globalUserDataChangedCallBack = {};
|
||||
|
||||
bool globalIsAppInBackground = true;
|
||||
bool globalAllowErrorTrackingViaSentry = false;
|
||||
|
||||
late String globalApplicationCacheDirectory;
|
||||
late String globalApplicationSupportDirectory;
|
||||
|
||||
final GlobalKey<ScaffoldMessengerState> globalRootScaffoldMessengerKey =
|
||||
GlobalKey<ScaffoldMessengerState>();
|
||||
|
|
|
|||
|
|
@ -1,16 +1,19 @@
|
|||
// ignore_for_file: unused_import
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:camera/camera.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:path/path.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||
import 'package:twonly/app.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
import 'package:twonly/src/database/twonly.db.dart';
|
||||
import 'package:twonly/src/providers/connection.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/services/api.service.dart';
|
||||
import 'package:twonly/src/services/api/mediafiles/media_background.service.dart';
|
||||
|
|
@ -19,39 +22,25 @@ import 'package:twonly/src/services/fcm.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/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/storage.dart';
|
||||
|
||||
void main() async {
|
||||
SentryWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
try {
|
||||
await initFCMService();
|
||||
} catch (e) {
|
||||
Log.error('$e');
|
||||
}
|
||||
|
||||
initLogger();
|
||||
|
||||
final user = await getUser();
|
||||
if (user != null) {
|
||||
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());
|
||||
}
|
||||
|
||||
globalApplicationCacheDirectory = (await getApplicationCacheDirectory()).path;
|
||||
globalApplicationSupportDirectory =
|
||||
(await getApplicationSupportDirectory()).path;
|
||||
|
||||
initLogger();
|
||||
|
||||
final settingsController = SettingsChangeProvider();
|
||||
|
||||
await settingsController.loadSettings();
|
||||
|
|
@ -61,16 +50,24 @@ void main() async {
|
|||
|
||||
gCameras = await availableCameras();
|
||||
|
||||
// try {
|
||||
// File(join((await getApplicationSupportDirectory()).path, 'twonly.sqlite'))
|
||||
// .deleteSync();
|
||||
// } catch (e) {}
|
||||
// await updateUserdata((u) {
|
||||
// u.appVersion = 0;
|
||||
// return u;
|
||||
// });
|
||||
|
||||
apiService = ApiService();
|
||||
twonlyDB = TwonlyDB();
|
||||
|
||||
await twonlyDB.messagesDao.purgeMessageTable();
|
||||
unawaited(MediaFileService.purgeTempFolder());
|
||||
|
||||
await initFileDownloader();
|
||||
unawaited(finishStartedPreprocessing());
|
||||
|
||||
unawaited(MediaFileService.purgeTempFolder());
|
||||
unawaited(createPushAvatars());
|
||||
await twonlyDB.messagesDao.purgeMessageTable();
|
||||
|
||||
runApp(
|
||||
MultiProvider(
|
||||
|
|
@ -78,7 +75,6 @@ void main() async {
|
|||
ChangeNotifierProvider(create: (_) => settingsController),
|
||||
ChangeNotifierProvider(create: (_) => CustomChangeProvider()),
|
||||
ChangeNotifierProvider(create: (_) => ImageEditorProvider()),
|
||||
ChangeNotifierProvider(create: (_) => PurchasesProvider()),
|
||||
],
|
||||
child: const App(),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
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,15 +42,8 @@ class ContactsDao extends DatabaseAccessor<TwonlyDB> with _$ContactsDaoMixin {
|
|||
.getSingleOrNull();
|
||||
}
|
||||
|
||||
Future<List<Contact>> getContactsByUsername(
|
||||
String username, {
|
||||
String username2 = '_______',
|
||||
}) async {
|
||||
return (select(contacts)
|
||||
..where(
|
||||
(t) => t.username.equals(username) | t.username.equals(username2),
|
||||
))
|
||||
.get();
|
||||
Future<List<Contact>> getContactsByUsername(String username) async {
|
||||
return (select(contacts)..where((t) => t.username.equals(username))).get();
|
||||
}
|
||||
|
||||
Future<void> deleteContactByUserId(int userId) {
|
||||
|
|
@ -65,8 +58,7 @@ class ContactsDao extends DatabaseAccessor<TwonlyDB> with _$ContactsDaoMixin {
|
|||
.write(updatedValues);
|
||||
if (updatedValues.blocked.present ||
|
||||
updatedValues.displayName.present ||
|
||||
updatedValues.nickName.present ||
|
||||
updatedValues.username.present) {
|
||||
updatedValues.nickName.present) {
|
||||
final contact = await getContactByUserId(userId).getSingleOrNull();
|
||||
if (contact != null) {
|
||||
await updatePushUser(contact);
|
||||
|
|
@ -99,7 +91,7 @@ class ContactsDao extends DatabaseAccessor<TwonlyDB> with _$ContactsDaoMixin {
|
|||
.watchSingleOrNull();
|
||||
}
|
||||
|
||||
Future<List<Contact>> getAllContacts() {
|
||||
Future<List<Contact>> getAllNotBlockedContacts() {
|
||||
return select(contacts).get();
|
||||
}
|
||||
|
||||
|
|
@ -126,12 +118,7 @@ class ContactsDao extends DatabaseAccessor<TwonlyDB> with _$ContactsDaoMixin {
|
|||
|
||||
Stream<List<Contact>> watchAllAcceptedContacts() {
|
||||
return (select(contacts)
|
||||
..where(
|
||||
(t) =>
|
||||
t.blocked.equals(false) &
|
||||
t.accepted.equals(true) &
|
||||
t.accountDeleted.equals(false),
|
||||
))
|
||||
..where((t) => t.blocked.equals(false) & t.accepted.equals(true)))
|
||||
.watch();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import 'package:hashlib/random.dart';
|
|||
import 'package:twonly/globals.dart';
|
||||
import 'package:twonly/src/database/tables/groups.table.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/misc.dart';
|
||||
|
||||
|
|
@ -248,22 +247,16 @@ class GroupsDao extends DatabaseAccessor<TwonlyDB> with _$GroupsDaoMixin {
|
|||
.get();
|
||||
}
|
||||
|
||||
Future<List<GroupMember>> getAllGroupMemberWithoutPublicKey() async {
|
||||
try {
|
||||
final query = ((select(groupMembers)
|
||||
..where((t) => t.groupPublicKey.isNull()))
|
||||
.join([
|
||||
Future<List<GroupMember>> getAllGroupMemberWithoutPublicKey() {
|
||||
final query =
|
||||
((select(groups)..where((t) => t.isDirectChat.equals(false))).join([
|
||||
leftOuterJoin(
|
||||
groups,
|
||||
groups.groupId.equalsExp(groupMembers.groupId),
|
||||
groupMembers,
|
||||
groupMembers.groupId.equalsExp(groups.groupId),
|
||||
),
|
||||
])
|
||||
..where(groups.isDirectChat.isNull()));
|
||||
..where(groupMembers.groupPublicKey.isNull()));
|
||||
return query.map((row) => row.readTable(groupMembers)).get();
|
||||
} catch (e) {
|
||||
Log.error(e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
Future<Group?> getDirectChat(int userId) async {
|
||||
|
|
@ -279,6 +272,89 @@ class GroupsDao extends DatabaseAccessor<TwonlyDB> with _$GroupsDaoMixin {
|
|||
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() {
|
||||
final query = selectOnly(groups)
|
||||
..addColumns([groups.totalMediaCounter.sum()]);
|
||||
|
|
@ -301,3 +377,19 @@ class GroupsDao extends DatabaseAccessor<TwonlyDB> with _$GroupsDaoMixin {
|
|||
.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,14 +100,6 @@ class MediaFilesDao extends DatabaseAccessor<TwonlyDB>
|
|||
.get();
|
||||
}
|
||||
|
||||
Future<List<MediaFile>> getAllNonHashedStoredMediaFiles() async {
|
||||
return (select(mediaFiles)
|
||||
..where(
|
||||
(t) => t.stored.equals(true) & t.storedFileHash.isNull(),
|
||||
))
|
||||
.get();
|
||||
}
|
||||
|
||||
Future<List<MediaFile>> getAllMediaFilesPendingUpload() async {
|
||||
return (select(mediaFiles)
|
||||
..where(
|
||||
|
|
@ -119,10 +111,7 @@ class MediaFilesDao extends DatabaseAccessor<TwonlyDB>
|
|||
}
|
||||
|
||||
Stream<List<MediaFile>> watchAllStoredMediaFiles() {
|
||||
final query = (select(mediaFiles)..where((t) => t.stored.equals(true)))
|
||||
.join([])
|
||||
..groupBy([mediaFiles.storedFileHash]);
|
||||
return query.map((row) => row.readTable(mediaFiles)).watch();
|
||||
return (select(mediaFiles)..where((t) => t.stored.equals(true))).watch();
|
||||
}
|
||||
|
||||
Stream<List<MediaFile>> watchNewestMediaFiles() {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue