Using new unified API for content insertion
This commit is contained in:
parent
f7ba6fc87c
commit
57af8806f7
5 changed files with 101 additions and 38 deletions
|
@ -22,6 +22,7 @@ Group changes to describe their impact on the project, as follows:
|
|||
### Changed
|
||||
- UI has been reworked around SlidingPane component to better handle tablets & foldable devices
|
||||
- Animations have been replaced to use com.google.android.material.transition ones
|
||||
- Using new [Unified Content API](https://developer.android.com/about/versions/12/features/unified-content-api) to share files from keyboard (or other sources)
|
||||
- Bumped dependencies, gradle updated from 4.2.2 to 7.0.2
|
||||
- Target Android SDK version set to 31 (Android 12)
|
||||
- SDK updated to 5.1.0 release
|
||||
|
|
|
@ -38,7 +38,9 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import java.io.File
|
||||
import java.lang.IllegalArgumentException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||
import org.linphone.LinphoneApplication.Companion.corePreferences
|
||||
import org.linphone.R
|
||||
|
@ -449,6 +451,24 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
|
|||
}
|
||||
}
|
||||
|
||||
sharedViewModel.richContentUri.observe(
|
||||
viewLifecycleOwner,
|
||||
{
|
||||
it.consume { uri ->
|
||||
Log.i("[Chat] Found rich content URI: $uri")
|
||||
lifecycleScope.launch {
|
||||
withContext(Dispatchers.Main) {
|
||||
val path = FileUtils.getFilePath(requireContext(), uri)
|
||||
Log.i("[Chat] Rich content URI: $uri matching path is: $path")
|
||||
if (path != null) {
|
||||
chatSendingViewModel.addAttachment(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
sharedViewModel.messageToForwardEvent.observe(
|
||||
viewLifecycleOwner,
|
||||
{
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2021 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-android
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.linphone.activities.main.chat.receivers
|
||||
|
||||
import android.content.ClipData
|
||||
import android.net.Uri
|
||||
import android.view.View
|
||||
import androidx.core.util.component1
|
||||
import androidx.core.util.component2
|
||||
import androidx.core.view.ContentInfoCompat
|
||||
import androidx.core.view.OnReceiveContentListener
|
||||
import org.linphone.core.tools.Log
|
||||
|
||||
class RichContentReceiver(private val contentReceived: (uri: Uri) -> Unit) : OnReceiveContentListener {
|
||||
companion object {
|
||||
val MIME_TYPES = arrayOf("image/png", "image/gif", "image/jpeg")
|
||||
}
|
||||
|
||||
override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat? {
|
||||
val (uriContent, remaining) = payload.partition { item -> item.uri != null }
|
||||
if (uriContent != null) {
|
||||
val clip: ClipData = uriContent.clip
|
||||
for (i in 0 until clip.itemCount) {
|
||||
val uri: Uri = clip.getItemAt(i).uri
|
||||
Log.i("[Content Receiver] Found URI: $uri")
|
||||
contentReceived(uri)
|
||||
}
|
||||
}
|
||||
// Return anything that your app didn't handle. This preserves the default platform
|
||||
// behavior for text and anything else that you aren't implementing custom handling for.
|
||||
return remaining
|
||||
}
|
||||
}
|
|
@ -19,61 +19,49 @@
|
|||
*/
|
||||
package org.linphone.activities.main.chat.views
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.util.AttributeSet
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputConnection
|
||||
import androidx.appcompat.widget.AppCompatEditText
|
||||
import androidx.core.view.inputmethod.EditorInfoCompat
|
||||
import androidx.core.view.inputmethod.InputConnectionCompat
|
||||
import androidx.core.view.inputmethod.InputContentInfoCompat
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.ViewModelStoreOwner
|
||||
import org.linphone.activities.main.chat.receivers.RichContentReceiver
|
||||
import org.linphone.activities.main.viewmodels.SharedMainViewModel
|
||||
import org.linphone.core.tools.Log
|
||||
import org.linphone.utils.Event
|
||||
|
||||
/**
|
||||
* Allows for image input inside an EditText, usefull for keyboards with gif support for example.
|
||||
*/
|
||||
class RichEditText : AppCompatEditText {
|
||||
private var mListener: RichInputListener? = null
|
||||
private var mSupportedMimeTypes: Array<String>? = null
|
||||
|
||||
interface RichInputListener {
|
||||
fun onCommitContent(
|
||||
inputContentInfo: InputContentInfoCompat,
|
||||
flags: Int,
|
||||
opts: Bundle?,
|
||||
contentMimeTypes: Array<String>?
|
||||
): Boolean
|
||||
constructor(context: Context) : super(context) {
|
||||
initReceiveContentListener()
|
||||
}
|
||||
|
||||
constructor(context: Context) : super(context)
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||
initReceiveContentListener()
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
|
||||
context,
|
||||
attrs,
|
||||
defStyleAttr
|
||||
)
|
||||
|
||||
fun setListener(listener: RichInputListener) {
|
||||
mListener = listener
|
||||
mSupportedMimeTypes = arrayOf("image/png", "image/gif", "image/jpeg")
|
||||
) {
|
||||
initReceiveContentListener()
|
||||
}
|
||||
|
||||
override fun onCreateInputConnection(editorInfo: EditorInfo): InputConnection? {
|
||||
val ic = super.onCreateInputConnection(editorInfo)
|
||||
EditorInfoCompat.setContentMimeTypes(editorInfo, mSupportedMimeTypes)
|
||||
|
||||
val callback =
|
||||
InputConnectionCompat.OnCommitContentListener { inputContentInfo, flags, opts ->
|
||||
val listener = mListener
|
||||
listener?.onCommitContent(
|
||||
inputContentInfo, flags, opts, mSupportedMimeTypes
|
||||
) ?: false
|
||||
private fun initReceiveContentListener() {
|
||||
ViewCompat.setOnReceiveContentListener(
|
||||
this, RichContentReceiver.MIME_TYPES,
|
||||
RichContentReceiver { uri ->
|
||||
Log.i("[Rich Edit Text] Received URI: $uri")
|
||||
val activity = context as Activity
|
||||
val sharedViewModel = activity.run {
|
||||
ViewModelProvider(activity as ViewModelStoreOwner).get(SharedMainViewModel::class.java)
|
||||
}
|
||||
sharedViewModel.richContentUri.value = Event(uri)
|
||||
}
|
||||
|
||||
return if (ic != null) {
|
||||
InputConnectionCompat.createWrapper(ic, editorInfo, callback)
|
||||
} else null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
package org.linphone.activities.main.viewmodels
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import org.linphone.activities.main.history.data.GroupedCallLogData
|
||||
|
@ -66,6 +67,9 @@ class SharedMainViewModel : ViewModel() {
|
|||
|
||||
var chatRoomSubject: String = ""
|
||||
|
||||
// When using keyboard to share gif or other, see RichContentReceiver & RichEditText classes
|
||||
val richContentUri = MutableLiveData<Event<Uri>>()
|
||||
|
||||
/* Contacts */
|
||||
|
||||
val contactFragmentOpenedEvent: MutableLiveData<Event<Boolean>> by lazy {
|
||||
|
|
Loading…
Reference in a new issue