Compare commits
No commits in common. "c22b35b4ac11768b186298544425faef4c78b9a8" and "fd91ccc46f82108d588bc6c27a209fa71483ebc1" have entirely different histories.
c22b35b4ac
...
fd91ccc46f
@ -7,7 +7,6 @@ linter:
|
|||||||
avoid_positional_boolean_parameters: false
|
avoid_positional_boolean_parameters: false
|
||||||
avoid_bool_literals_in_conditional_expressions: false
|
avoid_bool_literals_in_conditional_expressions: false
|
||||||
file_names: false
|
file_names: false
|
||||||
one_member_abstracts: false
|
|
||||||
|
|
||||||
analyzer:
|
analyzer:
|
||||||
exclude:
|
exclude:
|
||||||
|
@ -2,9 +2,6 @@ package org.moxxy.moxxy_native
|
|||||||
|
|
||||||
const val TAG = "moxxy_native"
|
const val TAG = "moxxy_native"
|
||||||
|
|
||||||
// The size of buffers to use for various operations
|
|
||||||
const val BUFFER_SIZE = 4096
|
|
||||||
|
|
||||||
// The data key for text entered in the notification's reply field
|
// The data key for text entered in the notification's reply field
|
||||||
const val REPLY_TEXT_KEY = "key_reply_text"
|
const val REPLY_TEXT_KEY = "key_reply_text"
|
||||||
|
|
||||||
|
@ -13,12 +13,6 @@ import io.flutter.embedding.engine.plugins.FlutterPlugin
|
|||||||
import io.flutter.embedding.engine.plugins.activity.ActivityAware
|
import io.flutter.embedding.engine.plugins.activity.ActivityAware
|
||||||
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
|
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
|
||||||
import io.flutter.plugin.common.EventChannel
|
import io.flutter.plugin.common.EventChannel
|
||||||
import org.moxxy.moxxy_native.contacts.ContactsImplementation
|
|
||||||
import org.moxxy.moxxy_native.contacts.MoxxyContactsApi
|
|
||||||
import org.moxxy.moxxy_native.cryptography.CryptographyImplementation
|
|
||||||
import org.moxxy.moxxy_native.cryptography.MoxxyCryptographyApi
|
|
||||||
import org.moxxy.moxxy_native.media.MediaImplementation
|
|
||||||
import org.moxxy.moxxy_native.media.MoxxyMediaApi
|
|
||||||
import org.moxxy.moxxy_native.notifications.MessagingNotification
|
import org.moxxy.moxxy_native.notifications.MessagingNotification
|
||||||
import org.moxxy.moxxy_native.notifications.MoxxyNotificationsApi
|
import org.moxxy.moxxy_native.notifications.MoxxyNotificationsApi
|
||||||
import org.moxxy.moxxy_native.notifications.NotificationChannel
|
import org.moxxy.moxxy_native.notifications.NotificationChannel
|
||||||
@ -33,8 +27,6 @@ import org.moxxy.moxxy_native.notifications.showNotificationImpl
|
|||||||
import org.moxxy.moxxy_native.picker.FilePickerType
|
import org.moxxy.moxxy_native.picker.FilePickerType
|
||||||
import org.moxxy.moxxy_native.picker.MoxxyPickerApi
|
import org.moxxy.moxxy_native.picker.MoxxyPickerApi
|
||||||
import org.moxxy.moxxy_native.picker.PickerResultListener
|
import org.moxxy.moxxy_native.picker.PickerResultListener
|
||||||
import org.moxxy.moxxy_native.platform.MoxxyPlatformApi
|
|
||||||
import org.moxxy.moxxy_native.platform.PlatformImplementation
|
|
||||||
|
|
||||||
object MoxxyEventChannels {
|
object MoxxyEventChannels {
|
||||||
var notificationChannel: EventChannel? = null
|
var notificationChannel: EventChannel? = null
|
||||||
@ -63,26 +55,13 @@ object NotificationCache {
|
|||||||
class MoxxyNativePlugin : FlutterPlugin, ActivityAware, MoxxyPickerApi, MoxxyNotificationsApi {
|
class MoxxyNativePlugin : FlutterPlugin, ActivityAware, MoxxyPickerApi, MoxxyNotificationsApi {
|
||||||
private var context: Context? = null
|
private var context: Context? = null
|
||||||
private var activity: Activity? = null
|
private var activity: Activity? = null
|
||||||
|
private lateinit var activityClass: Class<Any>
|
||||||
private lateinit var pickerListener: PickerResultListener
|
private lateinit var pickerListener: PickerResultListener
|
||||||
private val cryptographyImplementation = CryptographyImplementation()
|
|
||||||
private lateinit var contactsImplementation: ContactsImplementation
|
|
||||||
private lateinit var platformImplementation: PlatformImplementation
|
|
||||||
private val mediaImplementation = MediaImplementation()
|
|
||||||
|
|
||||||
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
|
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
|
||||||
context = flutterPluginBinding.applicationContext
|
context = flutterPluginBinding.applicationContext
|
||||||
contactsImplementation = ContactsImplementation(context!!)
|
|
||||||
platformImplementation = PlatformImplementation(context!!)
|
|
||||||
|
|
||||||
// Register the pigeon handlers
|
|
||||||
MoxxyPickerApi.setUp(flutterPluginBinding.binaryMessenger, this)
|
MoxxyPickerApi.setUp(flutterPluginBinding.binaryMessenger, this)
|
||||||
MoxxyNotificationsApi.setUp(flutterPluginBinding.binaryMessenger, this)
|
MoxxyNotificationsApi.setUp(flutterPluginBinding.binaryMessenger, this)
|
||||||
MoxxyCryptographyApi.setUp(flutterPluginBinding.binaryMessenger, cryptographyImplementation)
|
|
||||||
MoxxyContactsApi.setUp(flutterPluginBinding.binaryMessenger, contactsImplementation)
|
|
||||||
MoxxyPlatformApi.setUp(flutterPluginBinding.binaryMessenger, platformImplementation)
|
|
||||||
MoxxyMediaApi.setUp(flutterPluginBinding.binaryMessenger, mediaImplementation)
|
|
||||||
|
|
||||||
// Register the picker handler
|
|
||||||
pickerListener = PickerResultListener(context!!)
|
pickerListener = PickerResultListener(context!!)
|
||||||
Log.d(TAG, "Attached to engine")
|
Log.d(TAG, "Attached to engine")
|
||||||
}
|
}
|
||||||
@ -93,6 +72,7 @@ class MoxxyNativePlugin : FlutterPlugin, ActivityAware, MoxxyPickerApi, MoxxyNot
|
|||||||
|
|
||||||
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
|
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
|
||||||
activity = binding.activity
|
activity = binding.activity
|
||||||
|
activityClass = activity!!.javaClass
|
||||||
binding.addActivityResultListener(pickerListener)
|
binding.addActivityResultListener(pickerListener)
|
||||||
Log.d(TAG, "Attached to activity")
|
Log.d(TAG, "Attached to activity")
|
||||||
}
|
}
|
||||||
|
@ -1,95 +0,0 @@
|
|||||||
// Autogenerated from Pigeon (v11.0.1), do not edit directly.
|
|
||||||
// See also: https://pub.dev/packages/pigeon
|
|
||||||
|
|
||||||
package org.moxxy.moxxy_native.contacts
|
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import io.flutter.plugin.common.BasicMessageChannel
|
|
||||||
import io.flutter.plugin.common.BinaryMessenger
|
|
||||||
import io.flutter.plugin.common.MessageCodec
|
|
||||||
import io.flutter.plugin.common.StandardMessageCodec
|
|
||||||
|
|
||||||
private fun wrapResult(result: Any?): List<Any?> {
|
|
||||||
return listOf(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun wrapError(exception: Throwable): List<Any?> {
|
|
||||||
if (exception is FlutterError) {
|
|
||||||
return listOf(
|
|
||||||
exception.code,
|
|
||||||
exception.message,
|
|
||||||
exception.details,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return listOf(
|
|
||||||
exception.javaClass.simpleName,
|
|
||||||
exception.toString(),
|
|
||||||
"Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Error class for passing custom error details to Flutter via a thrown PlatformException.
|
|
||||||
* @property code The error code.
|
|
||||||
* @property message The error message.
|
|
||||||
* @property details The error details. Must be a datatype supported by the api codec.
|
|
||||||
*/
|
|
||||||
class FlutterError(
|
|
||||||
val code: String,
|
|
||||||
override val message: String? = null,
|
|
||||||
val details: Any? = null,
|
|
||||||
) : Throwable()
|
|
||||||
|
|
||||||
/** The type of icon to use when no avatar path is provided. */
|
|
||||||
enum class FallbackIconType(val raw: Int) {
|
|
||||||
NONE(0),
|
|
||||||
PERSON(1),
|
|
||||||
NOTES(2),
|
|
||||||
;
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun ofRaw(raw: Int): FallbackIconType? {
|
|
||||||
return values().firstOrNull { it.raw == raw }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
|
|
||||||
interface MoxxyContactsApi {
|
|
||||||
fun recordSentMessage(name: String, jid: String, avatarPath: String?, fallbackIcon: FallbackIconType)
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
/** The codec used by MoxxyContactsApi. */
|
|
||||||
val codec: MessageCodec<Any?> by lazy {
|
|
||||||
StandardMessageCodec()
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Sets up an instance of `MoxxyContactsApi` to handle messages through the `binaryMessenger`. */
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
fun setUp(binaryMessenger: BinaryMessenger, api: MoxxyContactsApi?) {
|
|
||||||
run {
|
|
||||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.moxxy_native.MoxxyContactsApi.recordSentMessage", codec)
|
|
||||||
if (api != null) {
|
|
||||||
channel.setMessageHandler { message, reply ->
|
|
||||||
val args = message as List<Any?>
|
|
||||||
val nameArg = args[0] as String
|
|
||||||
val jidArg = args[1] as String
|
|
||||||
val avatarPathArg = args[2] as String?
|
|
||||||
val fallbackIconArg = FallbackIconType.ofRaw(args[3] as Int)!!
|
|
||||||
var wrapped: List<Any?>
|
|
||||||
try {
|
|
||||||
api.recordSentMessage(nameArg, jidArg, avatarPathArg, fallbackIconArg)
|
|
||||||
wrapped = listOf<Any?>(null)
|
|
||||||
} catch (exception: Throwable) {
|
|
||||||
wrapped = wrapError(exception)
|
|
||||||
}
|
|
||||||
reply.reply(wrapped)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
channel.setMessageHandler(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
package org.moxxy.moxxy_native.contacts
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.graphics.BitmapFactory
|
|
||||||
import androidx.core.app.Person
|
|
||||||
import androidx.core.content.pm.ShortcutInfoCompat
|
|
||||||
import androidx.core.content.pm.ShortcutManagerCompat
|
|
||||||
import androidx.core.graphics.drawable.IconCompat
|
|
||||||
import org.moxxy.moxxy_native.R
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Implementation of Moxxy's contact APIs.
|
|
||||||
* */
|
|
||||||
class ContactsImplementation(private val context: Context) : MoxxyContactsApi {
|
|
||||||
override fun recordSentMessage(
|
|
||||||
name: String,
|
|
||||||
jid: String,
|
|
||||||
avatarPath: String?,
|
|
||||||
fallbackIcon: FallbackIconType,
|
|
||||||
) {
|
|
||||||
val pkgName = context.packageName
|
|
||||||
val intent = Intent(context, Class.forName("$pkgName.MainActivity")).apply {
|
|
||||||
action = Intent.ACTION_SEND
|
|
||||||
|
|
||||||
// Compatibility with share_handler
|
|
||||||
putExtra("conversationIdentifier", jid)
|
|
||||||
}
|
|
||||||
|
|
||||||
val shortcutTarget = "$pkgName.dynamic_share_target"
|
|
||||||
val shortcutBuilder = ShortcutInfoCompat.Builder(context, jid).apply {
|
|
||||||
setShortLabel(name)
|
|
||||||
setIsConversation()
|
|
||||||
setCategories(setOf(shortcutTarget))
|
|
||||||
setIntent(intent)
|
|
||||||
setLongLived(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
val personBuilder = Person.Builder().apply {
|
|
||||||
setKey(jid)
|
|
||||||
setName(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Either set an avatar image OR a fallback icon
|
|
||||||
if (avatarPath != null) {
|
|
||||||
val icon = IconCompat.createWithAdaptiveBitmap(
|
|
||||||
BitmapFactory.decodeFile(avatarPath),
|
|
||||||
)
|
|
||||||
shortcutBuilder.setIcon(icon)
|
|
||||||
personBuilder.setIcon(icon)
|
|
||||||
} else {
|
|
||||||
val resourceId = when (fallbackIcon) {
|
|
||||||
FallbackIconType.NONE, FallbackIconType.PERSON -> R.mipmap.person
|
|
||||||
FallbackIconType.NOTES -> R.mipmap.notes
|
|
||||||
}
|
|
||||||
val icon = IconCompat.createWithResource(context, resourceId)
|
|
||||||
shortcutBuilder.setIcon(icon)
|
|
||||||
personBuilder.setIcon(icon)
|
|
||||||
}
|
|
||||||
|
|
||||||
shortcutBuilder.setPerson(personBuilder.build())
|
|
||||||
ShortcutManagerCompat.addDynamicShortcuts(
|
|
||||||
context,
|
|
||||||
listOf(shortcutBuilder.build()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,192 +0,0 @@
|
|||||||
// Autogenerated from Pigeon (v11.0.1), do not edit directly.
|
|
||||||
// See also: https://pub.dev/packages/pigeon
|
|
||||||
|
|
||||||
package org.moxxy.moxxy_native.cryptography
|
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import io.flutter.plugin.common.BasicMessageChannel
|
|
||||||
import io.flutter.plugin.common.BinaryMessenger
|
|
||||||
import io.flutter.plugin.common.MessageCodec
|
|
||||||
import io.flutter.plugin.common.StandardMessageCodec
|
|
||||||
import java.io.ByteArrayOutputStream
|
|
||||||
import java.nio.ByteBuffer
|
|
||||||
|
|
||||||
private fun wrapResult(result: Any?): List<Any?> {
|
|
||||||
return listOf(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun wrapError(exception: Throwable): List<Any?> {
|
|
||||||
if (exception is FlutterError) {
|
|
||||||
return listOf(
|
|
||||||
exception.code,
|
|
||||||
exception.message,
|
|
||||||
exception.details,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return listOf(
|
|
||||||
exception.javaClass.simpleName,
|
|
||||||
exception.toString(),
|
|
||||||
"Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Error class for passing custom error details to Flutter via a thrown PlatformException.
|
|
||||||
* @property code The error code.
|
|
||||||
* @property message The error message.
|
|
||||||
* @property details The error details. Must be a datatype supported by the api codec.
|
|
||||||
*/
|
|
||||||
class FlutterError(
|
|
||||||
val code: String,
|
|
||||||
override val message: String? = null,
|
|
||||||
val details: Any? = null,
|
|
||||||
) : Throwable()
|
|
||||||
|
|
||||||
enum class CipherAlgorithm(val raw: Int) {
|
|
||||||
AES128GCMNOPADDING(0),
|
|
||||||
AES256GCMNOPADDING(1),
|
|
||||||
AES256CBCPKCS7(2),
|
|
||||||
;
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun ofRaw(raw: Int): CipherAlgorithm? {
|
|
||||||
return values().firstOrNull { it.raw == raw }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Generated class from Pigeon that represents data sent in messages. */
|
|
||||||
data class CryptographyResult(
|
|
||||||
val plaintextHash: ByteArray,
|
|
||||||
val ciphertextHash: ByteArray,
|
|
||||||
|
|
||||||
) {
|
|
||||||
companion object {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
fun fromList(list: List<Any?>): CryptographyResult {
|
|
||||||
val plaintextHash = list[0] as ByteArray
|
|
||||||
val ciphertextHash = list[1] as ByteArray
|
|
||||||
return CryptographyResult(plaintextHash, ciphertextHash)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fun toList(): List<Any?> {
|
|
||||||
return listOf<Any?>(
|
|
||||||
plaintextHash,
|
|
||||||
ciphertextHash,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
private object MoxxyCryptographyApiCodec : StandardMessageCodec() {
|
|
||||||
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
|
|
||||||
return when (type) {
|
|
||||||
128.toByte() -> {
|
|
||||||
return (readValue(buffer) as? List<Any?>)?.let {
|
|
||||||
CryptographyResult.fromList(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> super.readValueOfType(type, buffer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
override fun writeValue(stream: ByteArrayOutputStream, value: Any?) {
|
|
||||||
when (value) {
|
|
||||||
is CryptographyResult -> {
|
|
||||||
stream.write(128)
|
|
||||||
writeValue(stream, value.toList())
|
|
||||||
}
|
|
||||||
else -> super.writeValue(stream, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
|
|
||||||
interface MoxxyCryptographyApi {
|
|
||||||
fun encryptFile(sourcePath: String, destPath: String, key: ByteArray, iv: ByteArray, algorithm: CipherAlgorithm, hashSpec: String, callback: (Result<CryptographyResult?>) -> Unit)
|
|
||||||
fun decryptFile(sourcePath: String, destPath: String, key: ByteArray, iv: ByteArray, algorithm: CipherAlgorithm, hashSpec: String, callback: (Result<CryptographyResult?>) -> Unit)
|
|
||||||
fun hashFile(sourcePath: String, hashSpec: String, callback: (Result<ByteArray?>) -> Unit)
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
/** The codec used by MoxxyCryptographyApi. */
|
|
||||||
val codec: MessageCodec<Any?> by lazy {
|
|
||||||
MoxxyCryptographyApiCodec
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Sets up an instance of `MoxxyCryptographyApi` to handle messages through the `binaryMessenger`. */
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
fun setUp(binaryMessenger: BinaryMessenger, api: MoxxyCryptographyApi?) {
|
|
||||||
run {
|
|
||||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.moxxy_native.MoxxyCryptographyApi.encryptFile", codec)
|
|
||||||
if (api != null) {
|
|
||||||
channel.setMessageHandler { message, reply ->
|
|
||||||
val args = message as List<Any?>
|
|
||||||
val sourcePathArg = args[0] as String
|
|
||||||
val destPathArg = args[1] as String
|
|
||||||
val keyArg = args[2] as ByteArray
|
|
||||||
val ivArg = args[3] as ByteArray
|
|
||||||
val algorithmArg = CipherAlgorithm.ofRaw(args[4] as Int)!!
|
|
||||||
val hashSpecArg = args[5] as String
|
|
||||||
api.encryptFile(sourcePathArg, destPathArg, keyArg, ivArg, algorithmArg, hashSpecArg) { result: Result<CryptographyResult?> ->
|
|
||||||
val error = result.exceptionOrNull()
|
|
||||||
if (error != null) {
|
|
||||||
reply.reply(wrapError(error))
|
|
||||||
} else {
|
|
||||||
val data = result.getOrNull()
|
|
||||||
reply.reply(wrapResult(data))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
channel.setMessageHandler(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
run {
|
|
||||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.moxxy_native.MoxxyCryptographyApi.decryptFile", codec)
|
|
||||||
if (api != null) {
|
|
||||||
channel.setMessageHandler { message, reply ->
|
|
||||||
val args = message as List<Any?>
|
|
||||||
val sourcePathArg = args[0] as String
|
|
||||||
val destPathArg = args[1] as String
|
|
||||||
val keyArg = args[2] as ByteArray
|
|
||||||
val ivArg = args[3] as ByteArray
|
|
||||||
val algorithmArg = CipherAlgorithm.ofRaw(args[4] as Int)!!
|
|
||||||
val hashSpecArg = args[5] as String
|
|
||||||
api.decryptFile(sourcePathArg, destPathArg, keyArg, ivArg, algorithmArg, hashSpecArg) { result: Result<CryptographyResult?> ->
|
|
||||||
val error = result.exceptionOrNull()
|
|
||||||
if (error != null) {
|
|
||||||
reply.reply(wrapError(error))
|
|
||||||
} else {
|
|
||||||
val data = result.getOrNull()
|
|
||||||
reply.reply(wrapResult(data))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
channel.setMessageHandler(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
run {
|
|
||||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.moxxy_native.MoxxyCryptographyApi.hashFile", codec)
|
|
||||||
if (api != null) {
|
|
||||||
channel.setMessageHandler { message, reply ->
|
|
||||||
val args = message as List<Any?>
|
|
||||||
val sourcePathArg = args[0] as String
|
|
||||||
val hashSpecArg = args[1] as String
|
|
||||||
api.hashFile(sourcePathArg, hashSpecArg) { result: Result<ByteArray?> ->
|
|
||||||
val error = result.exceptionOrNull()
|
|
||||||
if (error != null) {
|
|
||||||
reply.reply(wrapError(error))
|
|
||||||
} else {
|
|
||||||
val data = result.getOrNull()
|
|
||||||
reply.reply(wrapResult(data))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
channel.setMessageHandler(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,169 +0,0 @@
|
|||||||
package org.moxxy.moxxy_native.cryptography
|
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import org.moxxy.moxxy_native.BUFFER_SIZE
|
|
||||||
import org.moxxy.moxxy_native.TAG
|
|
||||||
import java.io.FileInputStream
|
|
||||||
import java.security.MessageDigest
|
|
||||||
import javax.crypto.Cipher
|
|
||||||
import javax.crypto.CipherOutputStream
|
|
||||||
import javax.crypto.spec.IvParameterSpec
|
|
||||||
import javax.crypto.spec.SecretKeySpec
|
|
||||||
import kotlin.concurrent.thread
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Convert the algorithm spec @algorithm to the format that Java/Android understands
|
|
||||||
* */
|
|
||||||
private fun getCipherSpecFromInteger(algorithm: CipherAlgorithm): String {
|
|
||||||
return when (algorithm) {
|
|
||||||
CipherAlgorithm.AES128GCMNOPADDING -> "AES_128/GCM/NoPadding"
|
|
||||||
CipherAlgorithm.AES256GCMNOPADDING -> "AES_256/GCM/NoPadding"
|
|
||||||
CipherAlgorithm.AES256CBCPKCS7 -> "AES_256/CBC/PKCS7PADDING"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Implementation of Moxxy's cryptography API
|
|
||||||
* */
|
|
||||||
class CryptographyImplementation : MoxxyCryptographyApi {
|
|
||||||
override fun encryptFile(
|
|
||||||
sourcePath: String,
|
|
||||||
destPath: String,
|
|
||||||
key: ByteArray,
|
|
||||||
iv: ByteArray,
|
|
||||||
algorithm: CipherAlgorithm,
|
|
||||||
hashSpec: String,
|
|
||||||
callback: (Result<CryptographyResult?>) -> Unit,
|
|
||||||
) {
|
|
||||||
thread(start = true) {
|
|
||||||
val cipherSpec = getCipherSpecFromInteger(algorithm)
|
|
||||||
val buffer = ByteArray(BUFFER_SIZE)
|
|
||||||
val secretKey = SecretKeySpec(key, cipherSpec)
|
|
||||||
val inputStream = FileInputStream(sourcePath)
|
|
||||||
try {
|
|
||||||
val digest = MessageDigest.getInstance(hashSpec)
|
|
||||||
val cipher = Cipher.getInstance(cipherSpec).apply {
|
|
||||||
init(Cipher.ENCRYPT_MODE, secretKey, IvParameterSpec(iv))
|
|
||||||
}
|
|
||||||
val fileOutputStream = HashedFileOutputStream(destPath, hashSpec)
|
|
||||||
val cipherOutputStream = CipherOutputStream(fileOutputStream, cipher)
|
|
||||||
var length: Int
|
|
||||||
while (true) {
|
|
||||||
length = inputStream.read(buffer)
|
|
||||||
if (length <= 0) break
|
|
||||||
|
|
||||||
digest.update(buffer, 0, length)
|
|
||||||
cipherOutputStream.write(buffer, 0, length)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up
|
|
||||||
cipherOutputStream.apply {
|
|
||||||
flush()
|
|
||||||
close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Success
|
|
||||||
callback(
|
|
||||||
Result.success(
|
|
||||||
CryptographyResult(
|
|
||||||
plaintextHash = digest.digest(),
|
|
||||||
ciphertextHash = fileOutputStream.digest(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
} catch (ex: Exception) {
|
|
||||||
Log.e(TAG, "Failed to encrypt file $sourcePath: ${ex.message}")
|
|
||||||
callback(Result.success(null))
|
|
||||||
} finally {
|
|
||||||
// Clean up
|
|
||||||
inputStream.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun decryptFile(
|
|
||||||
sourcePath: String,
|
|
||||||
destPath: String,
|
|
||||||
key: ByteArray,
|
|
||||||
iv: ByteArray,
|
|
||||||
algorithm: CipherAlgorithm,
|
|
||||||
hashSpec: String,
|
|
||||||
callback: (Result<CryptographyResult?>) -> Unit,
|
|
||||||
) {
|
|
||||||
thread(start = true) {
|
|
||||||
val cipherSpec = getCipherSpecFromInteger(algorithm)
|
|
||||||
val buffer = ByteArray(BUFFER_SIZE)
|
|
||||||
val secretKey = SecretKeySpec(key, cipherSpec)
|
|
||||||
val inputStream = FileInputStream(sourcePath)
|
|
||||||
try {
|
|
||||||
val digest = MessageDigest.getInstance(hashSpec)
|
|
||||||
val cipher = Cipher.getInstance(cipherSpec).apply {
|
|
||||||
init(Cipher.DECRYPT_MODE, secretKey, IvParameterSpec(iv))
|
|
||||||
}
|
|
||||||
val fileOutputStream = HashedFileOutputStream(destPath, hashSpec)
|
|
||||||
val cipherOutputStream = CipherOutputStream(fileOutputStream, cipher)
|
|
||||||
var length: Int
|
|
||||||
while (true) {
|
|
||||||
length = inputStream.read(buffer)
|
|
||||||
if (length <= 0) break
|
|
||||||
|
|
||||||
digest.update(buffer, 0, length)
|
|
||||||
cipherOutputStream.write(buffer, 0, length)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up
|
|
||||||
cipherOutputStream.apply {
|
|
||||||
flush()
|
|
||||||
close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Success
|
|
||||||
callback(
|
|
||||||
Result.success(
|
|
||||||
CryptographyResult(
|
|
||||||
plaintextHash = digest.digest(),
|
|
||||||
ciphertextHash = fileOutputStream.digest(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
} catch (ex: Exception) {
|
|
||||||
Log.e(TAG, "Failed to decrypt file $sourcePath: ${ex.message}")
|
|
||||||
callback(Result.success(null))
|
|
||||||
} finally {
|
|
||||||
// Clean up
|
|
||||||
inputStream.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashFile(
|
|
||||||
sourcePath: String,
|
|
||||||
hashSpec: String,
|
|
||||||
callback: (Result<ByteArray?>) -> Unit,
|
|
||||||
) {
|
|
||||||
thread(start = true) {
|
|
||||||
val buffer = ByteArray(BUFFER_SIZE)
|
|
||||||
val inputStream = FileInputStream(sourcePath)
|
|
||||||
try {
|
|
||||||
val digest = MessageDigest.getInstance(hashSpec)
|
|
||||||
var length: Int
|
|
||||||
while (true) {
|
|
||||||
length = inputStream.read(buffer)
|
|
||||||
if (length <= 0) break
|
|
||||||
|
|
||||||
// Only update the digest if we read more than 0 bytes
|
|
||||||
digest.update(buffer, 0, length)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return success
|
|
||||||
callback(Result.success(digest.digest()))
|
|
||||||
} catch (ex: Exception) {
|
|
||||||
Log.e(TAG, "Failed to has file $sourcePath with $hashSpec: ${ex.message}")
|
|
||||||
callback(Result.success(null))
|
|
||||||
} finally {
|
|
||||||
// Clean up
|
|
||||||
inputStream.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
package org.moxxy.moxxy_native.cryptography
|
|
||||||
|
|
||||||
import java.io.FileOutputStream
|
|
||||||
import java.security.MessageDigest
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A FileOutputStream that continuously hashes whatever it writes to the file.
|
|
||||||
*/
|
|
||||||
class HashedFileOutputStream(name: String, hashAlgorithm: String) : FileOutputStream(name) {
|
|
||||||
private val digest: MessageDigest
|
|
||||||
|
|
||||||
init {
|
|
||||||
this.digest = MessageDigest.getInstance(hashAlgorithm)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun write(buffer: ByteArray, offset: Int, length: Int) {
|
|
||||||
super.write(buffer, offset, length)
|
|
||||||
|
|
||||||
digest.update(buffer, offset, length)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun digest(): ByteArray {
|
|
||||||
return digest.digest()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
// Autogenerated from Pigeon (v11.0.1), do not edit directly.
|
|
||||||
// See also: https://pub.dev/packages/pigeon
|
|
||||||
|
|
||||||
package org.moxxy.moxxy_native.media
|
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import io.flutter.plugin.common.BasicMessageChannel
|
|
||||||
import io.flutter.plugin.common.BinaryMessenger
|
|
||||||
import io.flutter.plugin.common.MessageCodec
|
|
||||||
import io.flutter.plugin.common.StandardMessageCodec
|
|
||||||
|
|
||||||
private fun wrapResult(result: Any?): List<Any?> {
|
|
||||||
return listOf(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun wrapError(exception: Throwable): List<Any?> {
|
|
||||||
if (exception is FlutterError) {
|
|
||||||
return listOf(
|
|
||||||
exception.code,
|
|
||||||
exception.message,
|
|
||||||
exception.details,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return listOf(
|
|
||||||
exception.javaClass.simpleName,
|
|
||||||
exception.toString(),
|
|
||||||
"Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Error class for passing custom error details to Flutter via a thrown PlatformException.
|
|
||||||
* @property code The error code.
|
|
||||||
* @property message The error message.
|
|
||||||
* @property details The error details. Must be a datatype supported by the api codec.
|
|
||||||
*/
|
|
||||||
class FlutterError(
|
|
||||||
val code: String,
|
|
||||||
override val message: String? = null,
|
|
||||||
val details: Any? = null,
|
|
||||||
) : Throwable()
|
|
||||||
|
|
||||||
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
|
|
||||||
interface MoxxyMediaApi {
|
|
||||||
fun generateVideoThumbnail(src: String, dest: String, maxWidth: Long): Boolean
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
/** The codec used by MoxxyMediaApi. */
|
|
||||||
val codec: MessageCodec<Any?> by lazy {
|
|
||||||
StandardMessageCodec()
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Sets up an instance of `MoxxyMediaApi` to handle messages through the `binaryMessenger`. */
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
fun setUp(binaryMessenger: BinaryMessenger, api: MoxxyMediaApi?) {
|
|
||||||
run {
|
|
||||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.moxxy_native.MoxxyMediaApi.generateVideoThumbnail", codec)
|
|
||||||
if (api != null) {
|
|
||||||
channel.setMessageHandler { message, reply ->
|
|
||||||
val args = message as List<Any?>
|
|
||||||
val srcArg = args[0] as String
|
|
||||||
val destArg = args[1] as String
|
|
||||||
val maxWidthArg = args[2].let { if (it is Int) it.toLong() else it as Long }
|
|
||||||
var wrapped: List<Any?>
|
|
||||||
try {
|
|
||||||
wrapped = listOf<Any?>(api.generateVideoThumbnail(srcArg, destArg, maxWidthArg))
|
|
||||||
} catch (exception: Throwable) {
|
|
||||||
wrapped = wrapError(exception)
|
|
||||||
}
|
|
||||||
reply.reply(wrapped)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
channel.setMessageHandler(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
package org.moxxy.moxxy_native.media
|
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.media.MediaMetadataRetriever
|
|
||||||
import android.util.Log
|
|
||||||
import org.moxxy.moxxy_native.TAG
|
|
||||||
import java.io.FileOutputStream
|
|
||||||
|
|
||||||
class MediaImplementation : MoxxyMediaApi {
|
|
||||||
override fun generateVideoThumbnail(src: String, dest: String, maxWidth: Long): Boolean {
|
|
||||||
try {
|
|
||||||
// Get a frame as a thumbnail
|
|
||||||
val mmr = MediaMetadataRetriever().apply {
|
|
||||||
setDataSource(src)
|
|
||||||
}
|
|
||||||
val unscaledThumbnail = mmr.getFrameAtTime(0) ?: return false
|
|
||||||
|
|
||||||
// Scale down the thumbnail while keeping the aspect ratio
|
|
||||||
val scalingFactor = maxWidth.toDouble() / unscaledThumbnail.width
|
|
||||||
Log.d(TAG, "Scaling to $maxWidth from ${unscaledThumbnail.width} with scalingFactor $scalingFactor")
|
|
||||||
val thumbnail = Bitmap.createScaledBitmap(
|
|
||||||
unscaledThumbnail,
|
|
||||||
(unscaledThumbnail.width * scalingFactor).toInt(),
|
|
||||||
(unscaledThumbnail.height * scalingFactor).toInt(),
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
|
|
||||||
// Write it to the destination file
|
|
||||||
val fileOutputStream = FileOutputStream(dest)
|
|
||||||
thumbnail.compress(Bitmap.CompressFormat.JPEG, 75, fileOutputStream)
|
|
||||||
|
|
||||||
// Clean up
|
|
||||||
fileOutputStream.apply {
|
|
||||||
flush()
|
|
||||||
close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Success
|
|
||||||
return true
|
|
||||||
} catch (ex: Exception) {
|
|
||||||
Log.e(TAG, "Failed to create thumbnail for $src: ${ex.message}")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,127 +0,0 @@
|
|||||||
// Autogenerated from Pigeon (v11.0.1), do not edit directly.
|
|
||||||
// See also: https://pub.dev/packages/pigeon
|
|
||||||
|
|
||||||
package org.moxxy.moxxy_native.platform
|
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import io.flutter.plugin.common.BasicMessageChannel
|
|
||||||
import io.flutter.plugin.common.BinaryMessenger
|
|
||||||
import io.flutter.plugin.common.MessageCodec
|
|
||||||
import io.flutter.plugin.common.StandardMessageCodec
|
|
||||||
|
|
||||||
private fun wrapResult(result: Any?): List<Any?> {
|
|
||||||
return listOf(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun wrapError(exception: Throwable): List<Any?> {
|
|
||||||
if (exception is FlutterError) {
|
|
||||||
return listOf(
|
|
||||||
exception.code,
|
|
||||||
exception.message,
|
|
||||||
exception.details,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return listOf(
|
|
||||||
exception.javaClass.simpleName,
|
|
||||||
exception.toString(),
|
|
||||||
"Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Error class for passing custom error details to Flutter via a thrown PlatformException.
|
|
||||||
* @property code The error code.
|
|
||||||
* @property message The error message.
|
|
||||||
* @property details The error details. Must be a datatype supported by the api codec.
|
|
||||||
*/
|
|
||||||
class FlutterError(
|
|
||||||
val code: String,
|
|
||||||
override val message: String? = null,
|
|
||||||
val details: Any? = null,
|
|
||||||
) : Throwable()
|
|
||||||
|
|
||||||
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
|
|
||||||
interface MoxxyPlatformApi {
|
|
||||||
fun getPersistentDataPath(): String
|
|
||||||
fun getCacheDataPath(): String
|
|
||||||
fun openBatteryOptimisationSettings()
|
|
||||||
fun isIgnoringBatteryOptimizations(): Boolean
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
/** The codec used by MoxxyPlatformApi. */
|
|
||||||
val codec: MessageCodec<Any?> by lazy {
|
|
||||||
StandardMessageCodec()
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Sets up an instance of `MoxxyPlatformApi` to handle messages through the `binaryMessenger`. */
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
fun setUp(binaryMessenger: BinaryMessenger, api: MoxxyPlatformApi?) {
|
|
||||||
run {
|
|
||||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.moxxy_native.MoxxyPlatformApi.getPersistentDataPath", codec)
|
|
||||||
if (api != null) {
|
|
||||||
channel.setMessageHandler { _, reply ->
|
|
||||||
var wrapped: List<Any?>
|
|
||||||
try {
|
|
||||||
wrapped = listOf<Any?>(api.getPersistentDataPath())
|
|
||||||
} catch (exception: Throwable) {
|
|
||||||
wrapped = wrapError(exception)
|
|
||||||
}
|
|
||||||
reply.reply(wrapped)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
channel.setMessageHandler(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
run {
|
|
||||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.moxxy_native.MoxxyPlatformApi.getCacheDataPath", codec)
|
|
||||||
if (api != null) {
|
|
||||||
channel.setMessageHandler { _, reply ->
|
|
||||||
var wrapped: List<Any?>
|
|
||||||
try {
|
|
||||||
wrapped = listOf<Any?>(api.getCacheDataPath())
|
|
||||||
} catch (exception: Throwable) {
|
|
||||||
wrapped = wrapError(exception)
|
|
||||||
}
|
|
||||||
reply.reply(wrapped)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
channel.setMessageHandler(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
run {
|
|
||||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.moxxy_native.MoxxyPlatformApi.openBatteryOptimisationSettings", codec)
|
|
||||||
if (api != null) {
|
|
||||||
channel.setMessageHandler { _, reply ->
|
|
||||||
var wrapped: List<Any?>
|
|
||||||
try {
|
|
||||||
api.openBatteryOptimisationSettings()
|
|
||||||
wrapped = listOf<Any?>(null)
|
|
||||||
} catch (exception: Throwable) {
|
|
||||||
wrapped = wrapError(exception)
|
|
||||||
}
|
|
||||||
reply.reply(wrapped)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
channel.setMessageHandler(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
run {
|
|
||||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.moxxy_native.MoxxyPlatformApi.isIgnoringBatteryOptimizations", codec)
|
|
||||||
if (api != null) {
|
|
||||||
channel.setMessageHandler { _, reply ->
|
|
||||||
var wrapped: List<Any?>
|
|
||||||
try {
|
|
||||||
wrapped = listOf<Any?>(api.isIgnoringBatteryOptimizations())
|
|
||||||
} catch (exception: Throwable) {
|
|
||||||
wrapped = wrapError(exception)
|
|
||||||
}
|
|
||||||
reply.reply(wrapped)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
channel.setMessageHandler(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
package org.moxxy.moxxy_native.platform
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.net.Uri
|
|
||||||
import android.os.PowerManager
|
|
||||||
import android.provider.Settings
|
|
||||||
|
|
||||||
class PlatformImplementation(private val context: Context) : MoxxyPlatformApi {
|
|
||||||
override fun getPersistentDataPath(): String {
|
|
||||||
return context.filesDir.path
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getCacheDataPath(): String {
|
|
||||||
return context.cacheDir.path
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openBatteryOptimisationSettings() {
|
|
||||||
val packageUri = Uri.parse("package:${context.packageName}")
|
|
||||||
val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, packageUri).apply {
|
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
|
||||||
}
|
|
||||||
context.startActivity(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isIgnoringBatteryOptimizations(): Boolean {
|
|
||||||
val pm = context.getSystemService(PowerManager::class.java)
|
|
||||||
return pm.isIgnoringBatteryOptimizations(context.packageName)
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 911 B |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 701 B |
Before Width: | Height: | Size: 828 B |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 3.5 KiB |
@ -1,5 +1,3 @@
|
|||||||
import 'dart:io';
|
|
||||||
import 'dart:typed_data';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:moxxy_native/moxxy_native.dart';
|
import 'package:moxxy_native/moxxy_native.dart';
|
||||||
|
|
||||||
@ -7,16 +5,9 @@ void main() {
|
|||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatefulWidget {
|
class MyApp extends StatelessWidget {
|
||||||
const MyApp({super.key});
|
const MyApp({super.key});
|
||||||
|
|
||||||
@override
|
|
||||||
MyAppState createState() => MyAppState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyAppState extends State<MyApp> {
|
|
||||||
String? imagePath;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
@ -53,49 +44,6 @@ class MyAppState extends State<MyApp> {
|
|||||||
},
|
},
|
||||||
child: const Text('Generic multi-picker'),
|
child: const Text('Generic multi-picker'),
|
||||||
),
|
),
|
||||||
TextButton(
|
|
||||||
onPressed: () async {
|
|
||||||
final result = await MoxxyPickerApi()
|
|
||||||
.pickFiles(FilePickerType.image, false);
|
|
||||||
if (result.isEmpty) return;
|
|
||||||
|
|
||||||
final encDest = '${result.first!}.enc';
|
|
||||||
final decDest = '${result.first!}.dec';
|
|
||||||
final encResult = await MoxxyCryptographyApi().encryptFile(
|
|
||||||
result.first!,
|
|
||||||
encDest,
|
|
||||||
Uint8List.fromList(List.filled(32, 1)),
|
|
||||||
Uint8List.fromList(List.filled(16, 2)),
|
|
||||||
CipherAlgorithm.aes256CbcPkcs7,
|
|
||||||
'SHA-256',
|
|
||||||
);
|
|
||||||
if (encResult == null) {
|
|
||||||
// ignore: avoid_print
|
|
||||||
print('Failed to encrypt file');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final decResult = await MoxxyCryptographyApi().decryptFile(
|
|
||||||
encDest,
|
|
||||||
decDest,
|
|
||||||
Uint8List.fromList(List.filled(32, 1)),
|
|
||||||
Uint8List.fromList(List.filled(16, 2)),
|
|
||||||
CipherAlgorithm.aes256CbcPkcs7,
|
|
||||||
'SHA-256',
|
|
||||||
);
|
|
||||||
if (decResult == null) {
|
|
||||||
// ignore: avoid_print
|
|
||||||
print('Failed to decrypt file');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
imagePath = decDest;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: const Text('Test cryptography'),
|
|
||||||
),
|
|
||||||
if (imagePath != null) Image.file(File(imagePath!)),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1 +0,0 @@
|
|||||||
|
|
@ -130,6 +130,54 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.2"
|
version: "1.8.2"
|
||||||
|
permission_handler:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: permission_handler
|
||||||
|
sha256: bc56bfe9d3f44c3c612d8d393bd9b174eb796d706759f9b495ac254e4294baa5
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.4.5"
|
||||||
|
permission_handler_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_android
|
||||||
|
sha256: "59c6322171c29df93a22d150ad95f3aa19ed86542eaec409ab2691b8f35f9a47"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.3.6"
|
||||||
|
permission_handler_apple:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_apple
|
||||||
|
sha256: "99e220bce3f8877c78e4ace901082fb29fa1b4ebde529ad0932d8d664b34f3f5"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "9.1.4"
|
||||||
|
permission_handler_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_platform_interface
|
||||||
|
sha256: f2343e9fa9c22ae4fd92d4732755bfe452214e7189afcc097380950cf567b4b2
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.11.5"
|
||||||
|
permission_handler_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_windows
|
||||||
|
sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.3"
|
||||||
|
plugin_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: plugin_platform_interface
|
||||||
|
sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.6"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -193,4 +241,4 @@ packages:
|
|||||||
version: "2.1.4"
|
version: "2.1.4"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.19.6 <3.0.0"
|
dart: ">=2.19.6 <3.0.0"
|
||||||
flutter: ">=2.5.0"
|
flutter: ">=2.8.0"
|
||||||
|
@ -1,6 +1,2 @@
|
|||||||
export 'pigeon/contacts.g.dart';
|
|
||||||
export 'pigeon/cryptography.g.dart';
|
|
||||||
export 'pigeon/media.g.dart';
|
|
||||||
export 'pigeon/notifications.g.dart';
|
export 'pigeon/notifications.g.dart';
|
||||||
export 'pigeon/picker.g.dart';
|
export 'pigeon/picker.g.dart';
|
||||||
export 'pigeon/platform.g.dart';
|
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
// Autogenerated from Pigeon (v11.0.1), do not edit directly.
|
|
||||||
// See also: https://pub.dev/packages/pigeon
|
|
||||||
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
|
|
||||||
|
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
|
|
||||||
/// The type of icon to use when no avatar path is provided.
|
|
||||||
enum FallbackIconType {
|
|
||||||
none,
|
|
||||||
person,
|
|
||||||
notes,
|
|
||||||
}
|
|
||||||
|
|
||||||
class MoxxyContactsApi {
|
|
||||||
/// Constructor for [MoxxyContactsApi]. The [binaryMessenger] named argument is
|
|
||||||
/// available for dependency injection. If it is left null, the default
|
|
||||||
/// BinaryMessenger will be used which routes to the host platform.
|
|
||||||
MoxxyContactsApi({BinaryMessenger? binaryMessenger})
|
|
||||||
: _binaryMessenger = binaryMessenger;
|
|
||||||
final BinaryMessenger? _binaryMessenger;
|
|
||||||
|
|
||||||
static const MessageCodec<Object?> codec = StandardMessageCodec();
|
|
||||||
|
|
||||||
Future<void> recordSentMessage(String arg_name, String arg_jid,
|
|
||||||
String? arg_avatarPath, FallbackIconType arg_fallbackIcon) async {
|
|
||||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
|
||||||
'dev.flutter.pigeon.moxxy_native.MoxxyContactsApi.recordSentMessage',
|
|
||||||
codec,
|
|
||||||
binaryMessenger: _binaryMessenger);
|
|
||||||
final List<Object?>? replyList = await channel.send(<Object?>[
|
|
||||||
arg_name,
|
|
||||||
arg_jid,
|
|
||||||
arg_avatarPath,
|
|
||||||
arg_fallbackIcon.index
|
|
||||||
]) as List<Object?>?;
|
|
||||||
if (replyList == null) {
|
|
||||||
throw PlatformException(
|
|
||||||
code: 'channel-error',
|
|
||||||
message: 'Unable to establish connection on channel.',
|
|
||||||
);
|
|
||||||
} else if (replyList.length > 1) {
|
|
||||||
throw PlatformException(
|
|
||||||
code: replyList[0]! as String,
|
|
||||||
message: replyList[1] as String?,
|
|
||||||
details: replyList[2],
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,168 +0,0 @@
|
|||||||
// Autogenerated from Pigeon (v11.0.1), do not edit directly.
|
|
||||||
// See also: https://pub.dev/packages/pigeon
|
|
||||||
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
|
|
||||||
|
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
|
|
||||||
enum CipherAlgorithm {
|
|
||||||
aes128GcmNoPadding,
|
|
||||||
aes256GcmNoPadding,
|
|
||||||
aes256CbcPkcs7,
|
|
||||||
}
|
|
||||||
|
|
||||||
class CryptographyResult {
|
|
||||||
CryptographyResult({
|
|
||||||
required this.plaintextHash,
|
|
||||||
required this.ciphertextHash,
|
|
||||||
});
|
|
||||||
|
|
||||||
Uint8List plaintextHash;
|
|
||||||
|
|
||||||
Uint8List ciphertextHash;
|
|
||||||
|
|
||||||
Object encode() {
|
|
||||||
return <Object?>[
|
|
||||||
plaintextHash,
|
|
||||||
ciphertextHash,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
static CryptographyResult decode(Object result) {
|
|
||||||
result as List<Object?>;
|
|
||||||
return CryptographyResult(
|
|
||||||
plaintextHash: result[0]! as Uint8List,
|
|
||||||
ciphertextHash: result[1]! as Uint8List,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _MoxxyCryptographyApiCodec extends StandardMessageCodec {
|
|
||||||
const _MoxxyCryptographyApiCodec();
|
|
||||||
@override
|
|
||||||
void writeValue(WriteBuffer buffer, Object? value) {
|
|
||||||
if (value is CryptographyResult) {
|
|
||||||
buffer.putUint8(128);
|
|
||||||
writeValue(buffer, value.encode());
|
|
||||||
} else {
|
|
||||||
super.writeValue(buffer, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Object? readValueOfType(int type, ReadBuffer buffer) {
|
|
||||||
switch (type) {
|
|
||||||
case 128:
|
|
||||||
return CryptographyResult.decode(readValue(buffer)!);
|
|
||||||
default:
|
|
||||||
return super.readValueOfType(type, buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MoxxyCryptographyApi {
|
|
||||||
/// Constructor for [MoxxyCryptographyApi]. The [binaryMessenger] named argument is
|
|
||||||
/// available for dependency injection. If it is left null, the default
|
|
||||||
/// BinaryMessenger will be used which routes to the host platform.
|
|
||||||
MoxxyCryptographyApi({BinaryMessenger? binaryMessenger})
|
|
||||||
: _binaryMessenger = binaryMessenger;
|
|
||||||
final BinaryMessenger? _binaryMessenger;
|
|
||||||
|
|
||||||
static const MessageCodec<Object?> codec = _MoxxyCryptographyApiCodec();
|
|
||||||
|
|
||||||
Future<CryptographyResult?> encryptFile(
|
|
||||||
String arg_sourcePath,
|
|
||||||
String arg_destPath,
|
|
||||||
Uint8List arg_key,
|
|
||||||
Uint8List arg_iv,
|
|
||||||
CipherAlgorithm arg_algorithm,
|
|
||||||
String arg_hashSpec) async {
|
|
||||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
|
||||||
'dev.flutter.pigeon.moxxy_native.MoxxyCryptographyApi.encryptFile',
|
|
||||||
codec,
|
|
||||||
binaryMessenger: _binaryMessenger);
|
|
||||||
final List<Object?>? replyList = await channel.send(<Object?>[
|
|
||||||
arg_sourcePath,
|
|
||||||
arg_destPath,
|
|
||||||
arg_key,
|
|
||||||
arg_iv,
|
|
||||||
arg_algorithm.index,
|
|
||||||
arg_hashSpec
|
|
||||||
]) as List<Object?>?;
|
|
||||||
if (replyList == null) {
|
|
||||||
throw PlatformException(
|
|
||||||
code: 'channel-error',
|
|
||||||
message: 'Unable to establish connection on channel.',
|
|
||||||
);
|
|
||||||
} else if (replyList.length > 1) {
|
|
||||||
throw PlatformException(
|
|
||||||
code: replyList[0]! as String,
|
|
||||||
message: replyList[1] as String?,
|
|
||||||
details: replyList[2],
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (replyList[0] as CryptographyResult?);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<CryptographyResult?> decryptFile(
|
|
||||||
String arg_sourcePath,
|
|
||||||
String arg_destPath,
|
|
||||||
Uint8List arg_key,
|
|
||||||
Uint8List arg_iv,
|
|
||||||
CipherAlgorithm arg_algorithm,
|
|
||||||
String arg_hashSpec) async {
|
|
||||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
|
||||||
'dev.flutter.pigeon.moxxy_native.MoxxyCryptographyApi.decryptFile',
|
|
||||||
codec,
|
|
||||||
binaryMessenger: _binaryMessenger);
|
|
||||||
final List<Object?>? replyList = await channel.send(<Object?>[
|
|
||||||
arg_sourcePath,
|
|
||||||
arg_destPath,
|
|
||||||
arg_key,
|
|
||||||
arg_iv,
|
|
||||||
arg_algorithm.index,
|
|
||||||
arg_hashSpec
|
|
||||||
]) as List<Object?>?;
|
|
||||||
if (replyList == null) {
|
|
||||||
throw PlatformException(
|
|
||||||
code: 'channel-error',
|
|
||||||
message: 'Unable to establish connection on channel.',
|
|
||||||
);
|
|
||||||
} else if (replyList.length > 1) {
|
|
||||||
throw PlatformException(
|
|
||||||
code: replyList[0]! as String,
|
|
||||||
message: replyList[1] as String?,
|
|
||||||
details: replyList[2],
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (replyList[0] as CryptographyResult?);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<Uint8List?> hashFile(
|
|
||||||
String arg_sourcePath, String arg_hashSpec) async {
|
|
||||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
|
||||||
'dev.flutter.pigeon.moxxy_native.MoxxyCryptographyApi.hashFile', codec,
|
|
||||||
binaryMessenger: _binaryMessenger);
|
|
||||||
final List<Object?>? replyList = await channel
|
|
||||||
.send(<Object?>[arg_sourcePath, arg_hashSpec]) as List<Object?>?;
|
|
||||||
if (replyList == null) {
|
|
||||||
throw PlatformException(
|
|
||||||
code: 'channel-error',
|
|
||||||
message: 'Unable to establish connection on channel.',
|
|
||||||
);
|
|
||||||
} else if (replyList.length > 1) {
|
|
||||||
throw PlatformException(
|
|
||||||
code: replyList[0]! as String,
|
|
||||||
message: replyList[1] as String?,
|
|
||||||
details: replyList[2],
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (replyList[0] as Uint8List?);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
// Autogenerated from Pigeon (v11.0.1), do not edit directly.
|
|
||||||
// See also: https://pub.dev/packages/pigeon
|
|
||||||
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
|
|
||||||
|
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
|
|
||||||
class MoxxyMediaApi {
|
|
||||||
/// Constructor for [MoxxyMediaApi]. The [binaryMessenger] named argument is
|
|
||||||
/// available for dependency injection. If it is left null, the default
|
|
||||||
/// BinaryMessenger will be used which routes to the host platform.
|
|
||||||
MoxxyMediaApi({BinaryMessenger? binaryMessenger})
|
|
||||||
: _binaryMessenger = binaryMessenger;
|
|
||||||
final BinaryMessenger? _binaryMessenger;
|
|
||||||
|
|
||||||
static const MessageCodec<Object?> codec = StandardMessageCodec();
|
|
||||||
|
|
||||||
Future<bool> generateVideoThumbnail(
|
|
||||||
String arg_src, String arg_dest, int arg_maxWidth) async {
|
|
||||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
|
||||||
'dev.flutter.pigeon.moxxy_native.MoxxyMediaApi.generateVideoThumbnail',
|
|
||||||
codec,
|
|
||||||
binaryMessenger: _binaryMessenger);
|
|
||||||
final List<Object?>? replyList = await channel
|
|
||||||
.send(<Object?>[arg_src, arg_dest, arg_maxWidth]) as List<Object?>?;
|
|
||||||
if (replyList == null) {
|
|
||||||
throw PlatformException(
|
|
||||||
code: 'channel-error',
|
|
||||||
message: 'Unable to establish connection on channel.',
|
|
||||||
);
|
|
||||||
} else if (replyList.length > 1) {
|
|
||||||
throw PlatformException(
|
|
||||||
code: replyList[0]! as String,
|
|
||||||
message: replyList[1] as String?,
|
|
||||||
details: replyList[2],
|
|
||||||
);
|
|
||||||
} else if (replyList[0] == null) {
|
|
||||||
throw PlatformException(
|
|
||||||
code: 'null-error',
|
|
||||||
message: 'Host platform returned null value for non-null return value.',
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (replyList[0] as bool?)!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,123 +0,0 @@
|
|||||||
// Autogenerated from Pigeon (v11.0.1), do not edit directly.
|
|
||||||
// See also: https://pub.dev/packages/pigeon
|
|
||||||
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
|
|
||||||
|
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
|
|
||||||
class MoxxyPlatformApi {
|
|
||||||
/// Constructor for [MoxxyPlatformApi]. The [binaryMessenger] named argument is
|
|
||||||
/// available for dependency injection. If it is left null, the default
|
|
||||||
/// BinaryMessenger will be used which routes to the host platform.
|
|
||||||
MoxxyPlatformApi({BinaryMessenger? binaryMessenger})
|
|
||||||
: _binaryMessenger = binaryMessenger;
|
|
||||||
final BinaryMessenger? _binaryMessenger;
|
|
||||||
|
|
||||||
static const MessageCodec<Object?> codec = StandardMessageCodec();
|
|
||||||
|
|
||||||
Future<String> getPersistentDataPath() async {
|
|
||||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
|
||||||
'dev.flutter.pigeon.moxxy_native.MoxxyPlatformApi.getPersistentDataPath',
|
|
||||||
codec,
|
|
||||||
binaryMessenger: _binaryMessenger);
|
|
||||||
final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
|
|
||||||
if (replyList == null) {
|
|
||||||
throw PlatformException(
|
|
||||||
code: 'channel-error',
|
|
||||||
message: 'Unable to establish connection on channel.',
|
|
||||||
);
|
|
||||||
} else if (replyList.length > 1) {
|
|
||||||
throw PlatformException(
|
|
||||||
code: replyList[0]! as String,
|
|
||||||
message: replyList[1] as String?,
|
|
||||||
details: replyList[2],
|
|
||||||
);
|
|
||||||
} else if (replyList[0] == null) {
|
|
||||||
throw PlatformException(
|
|
||||||
code: 'null-error',
|
|
||||||
message: 'Host platform returned null value for non-null return value.',
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (replyList[0] as String?)!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<String> getCacheDataPath() async {
|
|
||||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
|
||||||
'dev.flutter.pigeon.moxxy_native.MoxxyPlatformApi.getCacheDataPath',
|
|
||||||
codec,
|
|
||||||
binaryMessenger: _binaryMessenger);
|
|
||||||
final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
|
|
||||||
if (replyList == null) {
|
|
||||||
throw PlatformException(
|
|
||||||
code: 'channel-error',
|
|
||||||
message: 'Unable to establish connection on channel.',
|
|
||||||
);
|
|
||||||
} else if (replyList.length > 1) {
|
|
||||||
throw PlatformException(
|
|
||||||
code: replyList[0]! as String,
|
|
||||||
message: replyList[1] as String?,
|
|
||||||
details: replyList[2],
|
|
||||||
);
|
|
||||||
} else if (replyList[0] == null) {
|
|
||||||
throw PlatformException(
|
|
||||||
code: 'null-error',
|
|
||||||
message: 'Host platform returned null value for non-null return value.',
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (replyList[0] as String?)!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> openBatteryOptimisationSettings() async {
|
|
||||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
|
||||||
'dev.flutter.pigeon.moxxy_native.MoxxyPlatformApi.openBatteryOptimisationSettings',
|
|
||||||
codec,
|
|
||||||
binaryMessenger: _binaryMessenger);
|
|
||||||
final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
|
|
||||||
if (replyList == null) {
|
|
||||||
throw PlatformException(
|
|
||||||
code: 'channel-error',
|
|
||||||
message: 'Unable to establish connection on channel.',
|
|
||||||
);
|
|
||||||
} else if (replyList.length > 1) {
|
|
||||||
throw PlatformException(
|
|
||||||
code: replyList[0]! as String,
|
|
||||||
message: replyList[1] as String?,
|
|
||||||
details: replyList[2],
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> isIgnoringBatteryOptimizations() async {
|
|
||||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
|
||||||
'dev.flutter.pigeon.moxxy_native.MoxxyPlatformApi.isIgnoringBatteryOptimizations',
|
|
||||||
codec,
|
|
||||||
binaryMessenger: _binaryMessenger);
|
|
||||||
final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
|
|
||||||
if (replyList == null) {
|
|
||||||
throw PlatformException(
|
|
||||||
code: 'channel-error',
|
|
||||||
message: 'Unable to establish connection on channel.',
|
|
||||||
);
|
|
||||||
} else if (replyList.length > 1) {
|
|
||||||
throw PlatformException(
|
|
||||||
code: replyList[0]! as String,
|
|
||||||
message: replyList[1] as String?,
|
|
||||||
details: replyList[2],
|
|
||||||
);
|
|
||||||
} else if (replyList[0] == null) {
|
|
||||||
throw PlatformException(
|
|
||||||
code: 'null-error',
|
|
||||||
message: 'Host platform returned null value for non-null return value.',
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (replyList[0] as bool?)!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
import 'package:pigeon/pigeon.dart';
|
|
||||||
|
|
||||||
@ConfigurePigeon(
|
|
||||||
PigeonOptions(
|
|
||||||
dartOut: 'lib/pigeon/contacts.g.dart',
|
|
||||||
kotlinOut:
|
|
||||||
'android/src/main/kotlin/org/moxxy/moxxy_native/contacts/ContactsApi.kt',
|
|
||||||
kotlinOptions: KotlinOptions(
|
|
||||||
package: 'org.moxxy.moxxy_native.contacts',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
/// The type of icon to use when no avatar path is provided.
|
|
||||||
enum FallbackIconType {
|
|
||||||
none,
|
|
||||||
person,
|
|
||||||
notes;
|
|
||||||
}
|
|
||||||
|
|
||||||
@HostApi()
|
|
||||||
abstract class MoxxyContactsApi {
|
|
||||||
void recordSentMessage(
|
|
||||||
String name,
|
|
||||||
String jid,
|
|
||||||
String? avatarPath,
|
|
||||||
FallbackIconType fallbackIcon,
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
import 'package:pigeon/pigeon.dart';
|
|
||||||
|
|
||||||
@ConfigurePigeon(
|
|
||||||
PigeonOptions(
|
|
||||||
dartOut: 'lib/pigeon/cryptography.g.dart',
|
|
||||||
kotlinOut:
|
|
||||||
'android/src/main/kotlin/org/moxxy/moxxy_native/cryptography/CryptographyApi.kt',
|
|
||||||
kotlinOptions: KotlinOptions(
|
|
||||||
package: 'org.moxxy.moxxy_native.cryptography',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
enum CipherAlgorithm {
|
|
||||||
aes128GcmNoPadding,
|
|
||||||
aes256GcmNoPadding,
|
|
||||||
aes256CbcPkcs7;
|
|
||||||
}
|
|
||||||
|
|
||||||
class CryptographyResult {
|
|
||||||
const CryptographyResult(this.plaintextHash, this.ciphertextHash);
|
|
||||||
final Uint8List plaintextHash;
|
|
||||||
final Uint8List ciphertextHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
@HostApi()
|
|
||||||
abstract class MoxxyCryptographyApi {
|
|
||||||
@async
|
|
||||||
CryptographyResult? encryptFile(
|
|
||||||
String sourcePath,
|
|
||||||
String destPath,
|
|
||||||
Uint8List key,
|
|
||||||
Uint8List iv,
|
|
||||||
CipherAlgorithm algorithm,
|
|
||||||
String hashSpec,
|
|
||||||
);
|
|
||||||
|
|
||||||
@async
|
|
||||||
CryptographyResult? decryptFile(
|
|
||||||
String sourcePath,
|
|
||||||
String destPath,
|
|
||||||
Uint8List key,
|
|
||||||
Uint8List iv,
|
|
||||||
CipherAlgorithm algorithm,
|
|
||||||
String hashSpec,
|
|
||||||
);
|
|
||||||
|
|
||||||
@async
|
|
||||||
Uint8List? hashFile(
|
|
||||||
String sourcePath,
|
|
||||||
String hashSpec,
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
import 'package:pigeon/pigeon.dart';
|
|
||||||
|
|
||||||
@ConfigurePigeon(
|
|
||||||
PigeonOptions(
|
|
||||||
dartOut: 'lib/pigeon/media.g.dart',
|
|
||||||
kotlinOut:
|
|
||||||
'android/src/main/kotlin/org/moxxy/moxxy_native/media/MediaApi.kt',
|
|
||||||
kotlinOptions: KotlinOptions(
|
|
||||||
package: 'org.moxxy.moxxy_native.media',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
@HostApi()
|
|
||||||
abstract class MoxxyMediaApi {
|
|
||||||
bool generateVideoThumbnail(String src, String dest, int maxWidth);
|
|
||||||
}
|
|
@ -3,8 +3,7 @@ import 'package:pigeon/pigeon.dart';
|
|||||||
@ConfigurePigeon(
|
@ConfigurePigeon(
|
||||||
PigeonOptions(
|
PigeonOptions(
|
||||||
dartOut: 'lib/pigeon/notifications.g.dart',
|
dartOut: 'lib/pigeon/notifications.g.dart',
|
||||||
kotlinOut:
|
kotlinOut: 'android/src/main/kotlin/org/moxxy/moxxy_native/notifications/NotificationsApi.kt',
|
||||||
'android/src/main/kotlin/org/moxxy/moxxy_native/notifications/NotificationsApi.kt',
|
|
||||||
kotlinOptions: KotlinOptions(
|
kotlinOptions: KotlinOptions(
|
||||||
package: 'org.moxxy.moxxy_native.notifications',
|
package: 'org.moxxy.moxxy_native.notifications',
|
||||||
),
|
),
|
||||||
@ -55,16 +54,9 @@ class NotificationMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MessagingNotification {
|
class MessagingNotification {
|
||||||
const MessagingNotification(
|
const MessagingNotification(this.title, this.id, this.jid, this.messages,
|
||||||
this.title,
|
this.channelId, this.isGroupchat, this.extra,
|
||||||
this.id,
|
{this.groupId});
|
||||||
this.jid,
|
|
||||||
this.messages,
|
|
||||||
this.channelId,
|
|
||||||
this.isGroupchat,
|
|
||||||
this.extra, {
|
|
||||||
this.groupId,
|
|
||||||
});
|
|
||||||
|
|
||||||
/// The title of the conversation.
|
/// The title of the conversation.
|
||||||
final String title;
|
final String title;
|
||||||
@ -99,13 +91,8 @@ enum NotificationIcon {
|
|||||||
|
|
||||||
class RegularNotification {
|
class RegularNotification {
|
||||||
const RegularNotification(
|
const RegularNotification(
|
||||||
this.title,
|
this.title, this.body, this.channelId, this.id, this.icon,
|
||||||
this.body,
|
{this.groupId});
|
||||||
this.channelId,
|
|
||||||
this.id,
|
|
||||||
this.icon, {
|
|
||||||
this.groupId,
|
|
||||||
});
|
|
||||||
|
|
||||||
/// The title of the notification.
|
/// The title of the notification.
|
||||||
final String title;
|
final String title;
|
||||||
@ -178,7 +165,6 @@ class NotificationGroup {
|
|||||||
final String description;
|
final String description;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore: constant_identifier_names
|
|
||||||
enum NotificationChannelImportance { MIN, HIGH, DEFAULT }
|
enum NotificationChannelImportance { MIN, HIGH, DEFAULT }
|
||||||
|
|
||||||
class NotificationChannel {
|
class NotificationChannel {
|
||||||
|
@ -3,13 +3,13 @@ import 'package:pigeon/pigeon.dart';
|
|||||||
@ConfigurePigeon(
|
@ConfigurePigeon(
|
||||||
PigeonOptions(
|
PigeonOptions(
|
||||||
dartOut: 'lib/pigeon/picker.g.dart',
|
dartOut: 'lib/pigeon/picker.g.dart',
|
||||||
kotlinOut:
|
kotlinOut: 'android/src/main/kotlin/org/moxxy/moxxy_native/picker/PickerApi.kt',
|
||||||
'android/src/main/kotlin/org/moxxy/moxxy_native/picker/PickerApi.kt',
|
|
||||||
kotlinOptions: KotlinOptions(
|
kotlinOptions: KotlinOptions(
|
||||||
package: 'org.moxxy.moxxy_native.picker',
|
package: 'org.moxxy.moxxy_native.picker',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
enum FilePickerType {
|
enum FilePickerType {
|
||||||
/// Pick only image(s)
|
/// Pick only image(s)
|
||||||
image,
|
image,
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
import 'package:pigeon/pigeon.dart';
|
|
||||||
|
|
||||||
@ConfigurePigeon(
|
|
||||||
PigeonOptions(
|
|
||||||
dartOut: 'lib/pigeon/platform.g.dart',
|
|
||||||
kotlinOut:
|
|
||||||
'android/src/main/kotlin/org/moxxy/moxxy_native/platform/PlatformApi.kt',
|
|
||||||
kotlinOptions: KotlinOptions(
|
|
||||||
package: 'org.moxxy.moxxy_native.platform',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
@HostApi()
|
|
||||||
abstract class MoxxyPlatformApi {
|
|
||||||
String getPersistentDataPath();
|
|
||||||
|
|
||||||
String getCacheDataPath();
|
|
||||||
|
|
||||||
void openBatteryOptimisationSettings();
|
|
||||||
|
|
||||||
bool isIgnoringBatteryOptimizations();
|
|
||||||
}
|
|