feat: enhance clipboard image handling and share functionality in Android app
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
package com.paarrot.app
|
||||
|
||||
import android.net.Uri
|
||||
import android.view.View
|
||||
import androidx.core.view.ContentInfoCompat
|
||||
import androidx.core.view.OnReceiveContentListener
|
||||
|
||||
/**
|
||||
* Receives rich content from the IME (Gboard GIF), clipboard paste, and drag-drop,
|
||||
* then forwards file URIs through [ShareIntentStore] so JS can attach them in-room.
|
||||
*/
|
||||
class ImageKeyboardContentReceiver : OnReceiveContentListener {
|
||||
|
||||
override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat? {
|
||||
val split = payload.partition { item -> item.uri != null }
|
||||
val uriContent = split.first
|
||||
val remaining = split.second
|
||||
|
||||
if (uriContent != null) {
|
||||
val uris = mutableListOf<Uri>()
|
||||
val clip = uriContent.clip
|
||||
for (i in 0 until clip.itemCount) {
|
||||
clip.getItemAt(i).uri?.let { uris.add(it) }
|
||||
}
|
||||
if (uris.isNotEmpty()) {
|
||||
ShareIntentStore.handleContentUris(view.context, uris)
|
||||
}
|
||||
}
|
||||
|
||||
return remaining
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.paarrot.app
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputConnection
|
||||
import androidx.core.view.inputmethod.EditorInfoCompat
|
||||
import androidx.core.view.inputmethod.InputConnectionCompat
|
||||
import com.getcapacitor.CapacitorWebView
|
||||
|
||||
/**
|
||||
* Capacitor WebView that advertises image/video MIME types to the IME
|
||||
* (Gboard GIF/sticker keyboard) and routes commit-content through
|
||||
* [androidx.core.view.ViewCompat.setOnReceiveContentListener].
|
||||
*/
|
||||
class ImageKeyboardWebView(
|
||||
context: Context,
|
||||
attrs: AttributeSet?,
|
||||
) : CapacitorWebView(context, attrs) {
|
||||
|
||||
override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection? {
|
||||
val inputConnection = super.onCreateInputConnection(outAttrs) ?: return null
|
||||
EditorInfoCompat.setContentMimeTypes(outAttrs, MIME_TYPES)
|
||||
return InputConnectionCompat.createWrapper(this, inputConnection, outAttrs)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val MIME_TYPES: Array<String> = arrayOf(
|
||||
"image/*",
|
||||
"image/png",
|
||||
"image/gif",
|
||||
"image/jpeg",
|
||||
"image/webp",
|
||||
"video/*",
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.paarrot.app;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.webkit.WebView;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import com.getcapacitor.BridgeActivity;
|
||||
|
||||
public class MainActivity extends BridgeActivity {
|
||||
@@ -10,5 +12,18 @@ public class MainActivity extends BridgeActivity {
|
||||
registerPlugin(ShareHandlerPlugin.class);
|
||||
registerPlugin(PluginStoragePlugin.class);
|
||||
super.onCreate(savedInstanceState);
|
||||
setupImageKeyboardSupport();
|
||||
}
|
||||
}
|
||||
|
||||
/** Advertise image MIME types and receive Gboard / paste / drag-drop media. */
|
||||
private void setupImageKeyboardSupport() {
|
||||
if (bridge == null) return;
|
||||
WebView webView = bridge.getWebView();
|
||||
if (webView == null) return;
|
||||
ViewCompat.setOnReceiveContentListener(
|
||||
webView,
|
||||
ImageKeyboardWebView.MIME_TYPES,
|
||||
new ImageKeyboardContentReceiver()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,6 @@ object ShareIntentStore {
|
||||
|
||||
if (action != Intent.ACTION_SEND && action != Intent.ACTION_SEND_MULTIPLE) return
|
||||
|
||||
val receivedAt = System.currentTimeMillis()
|
||||
val text = intent.getStringExtra(Intent.EXTRA_TEXT)
|
||||
val subject = intent.getStringExtra(Intent.EXTRA_SUBJECT)
|
||||
|
||||
@@ -86,8 +85,29 @@ object ShareIntentStore {
|
||||
uri?.let { uris.add(it) }
|
||||
}
|
||||
|
||||
deliverShare(context, uris, text, subject)
|
||||
}
|
||||
|
||||
/**
|
||||
* Deliver content URIs from the IME (Gboard GIF), clipboard paste, or drag-drop
|
||||
* into the same share pipeline used by ACTION_SEND.
|
||||
*/
|
||||
fun handleContentUris(context: Context, uris: List<Uri>) {
|
||||
if (uris.isEmpty()) return
|
||||
deliverShare(context, uris, text = null, subject = null)
|
||||
}
|
||||
|
||||
private fun deliverShare(
|
||||
context: Context,
|
||||
uris: List<Uri>,
|
||||
text: String?,
|
||||
subject: String?,
|
||||
) {
|
||||
val receivedAt = System.currentTimeMillis()
|
||||
val copiedFiles = uris.mapNotNull { copySharedUri(context, it, receivedAt) }
|
||||
|
||||
if (copiedFiles.isEmpty() && text.isNullOrBlank() && subject.isNullOrBlank()) return
|
||||
|
||||
val payload = SharePayload(
|
||||
text = text,
|
||||
subject = subject,
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="com.getcapacitor.BridgeActivity">
|
||||
|
||||
<com.paarrot.app.ImageKeyboardWebView
|
||||
android:id="@+id/webview"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
Reference in New Issue
Block a user