feat: Move over the contacts API

This commit is contained in:
PapaTutuWawa 2023-09-08 19:40:03 +02:00
parent 809ddfaf80
commit 6e6b50d0c2
16 changed files with 249 additions and 0 deletions

View File

@ -13,6 +13,8 @@ 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.CryptographyImplementation
import org.moxxy.moxxy_native.cryptography.MoxxyCryptographyApi import org.moxxy.moxxy_native.cryptography.MoxxyCryptographyApi
import org.moxxy.moxxy_native.notifications.MessagingNotification import org.moxxy.moxxy_native.notifications.MessagingNotification
@ -60,12 +62,19 @@ class MoxxyNativePlugin : FlutterPlugin, ActivityAware, MoxxyPickerApi, MoxxyNot
private lateinit var activityClass: Class<Any> private lateinit var activityClass: Class<Any>
private lateinit var pickerListener: PickerResultListener private lateinit var pickerListener: PickerResultListener
private val cryptographyImplementation = CryptographyImplementation() private val cryptographyImplementation = CryptographyImplementation()
private lateinit var contactsImplementation: ContactsImplementation
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
context = flutterPluginBinding.applicationContext context = flutterPluginBinding.applicationContext
contactsImplementation = ContactsImplementation(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) MoxxyCryptographyApi.setUp(flutterPluginBinding.binaryMessenger, cryptographyImplementation)
MoxxyContactsApi.setUp(flutterPluginBinding.binaryMessenger, contactsImplementation)
// Register the picker handler
pickerListener = PickerResultListener(context!!) pickerListener = PickerResultListener(context!!)
Log.d(TAG, "Attached to engine") Log.d(TAG, "Attached to engine")
} }

View File

@ -0,0 +1,94 @@
// 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
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()
/** 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)
}
}
}
}
}

View File

@ -0,0 +1,67 @@
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()),
)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 701 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 828 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -1,3 +1,4 @@
export 'pigeon/contacts.g.dart';
export 'pigeon/cryptography.g.dart'; export 'pigeon/cryptography.g.dart';
export 'pigeon/notifications.g.dart'; export 'pigeon/notifications.g.dart';
export 'pigeon/picker.g.dart'; export 'pigeon/picker.g.dart';

View File

@ -0,0 +1,49 @@
// 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;
}
}
}

29
pigeon/contacts.dart Normal file
View File

@ -0,0 +1,29 @@
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,
);
}