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
|
### Changed
|
||||||
- UI has been reworked around SlidingPane component to better handle tablets & foldable devices
|
- 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
|
- 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
|
- Bumped dependencies, gradle updated from 4.2.2 to 7.0.2
|
||||||
- Target Android SDK version set to 31 (Android 12)
|
- Target Android SDK version set to 31 (Android 12)
|
||||||
- SDK updated to 5.1.0 release
|
- SDK updated to 5.1.0 release
|
||||||
|
|
|
@ -38,7 +38,9 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.lang.IllegalArgumentException
|
import java.lang.IllegalArgumentException
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||||
import org.linphone.LinphoneApplication.Companion.corePreferences
|
import org.linphone.LinphoneApplication.Companion.corePreferences
|
||||||
import org.linphone.R
|
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(
|
sharedViewModel.messageToForwardEvent.observe(
|
||||||
viewLifecycleOwner,
|
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
|
package org.linphone.activities.main.chat.views
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Bundle
|
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.inputmethod.EditorInfo
|
|
||||||
import android.view.inputmethod.InputConnection
|
|
||||||
import androidx.appcompat.widget.AppCompatEditText
|
import androidx.appcompat.widget.AppCompatEditText
|
||||||
import androidx.core.view.inputmethod.EditorInfoCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.core.view.inputmethod.InputConnectionCompat
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.core.view.inputmethod.InputContentInfoCompat
|
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.
|
* Allows for image input inside an EditText, usefull for keyboards with gif support for example.
|
||||||
*/
|
*/
|
||||||
class RichEditText : AppCompatEditText {
|
class RichEditText : AppCompatEditText {
|
||||||
private var mListener: RichInputListener? = null
|
constructor(context: Context) : super(context) {
|
||||||
private var mSupportedMimeTypes: Array<String>? = null
|
initReceiveContentListener()
|
||||||
|
|
||||||
interface RichInputListener {
|
|
||||||
fun onCommitContent(
|
|
||||||
inputContentInfo: InputContentInfoCompat,
|
|
||||||
flags: Int,
|
|
||||||
opts: Bundle?,
|
|
||||||
contentMimeTypes: Array<String>?
|
|
||||||
): Boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(context: Context) : super(context)
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||||
|
initReceiveContentListener()
|
||||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
|
}
|
||||||
|
|
||||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
|
||||||
context,
|
context,
|
||||||
attrs,
|
attrs,
|
||||||
defStyleAttr
|
defStyleAttr
|
||||||
)
|
) {
|
||||||
|
initReceiveContentListener()
|
||||||
fun setListener(listener: RichInputListener) {
|
|
||||||
mListener = listener
|
|
||||||
mSupportedMimeTypes = arrayOf("image/png", "image/gif", "image/jpeg")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateInputConnection(editorInfo: EditorInfo): InputConnection? {
|
private fun initReceiveContentListener() {
|
||||||
val ic = super.onCreateInputConnection(editorInfo)
|
ViewCompat.setOnReceiveContentListener(
|
||||||
EditorInfoCompat.setContentMimeTypes(editorInfo, mSupportedMimeTypes)
|
this, RichContentReceiver.MIME_TYPES,
|
||||||
|
RichContentReceiver { uri ->
|
||||||
val callback =
|
Log.i("[Rich Edit Text] Received URI: $uri")
|
||||||
InputConnectionCompat.OnCommitContentListener { inputContentInfo, flags, opts ->
|
val activity = context as Activity
|
||||||
val listener = mListener
|
val sharedViewModel = activity.run {
|
||||||
listener?.onCommitContent(
|
ViewModelProvider(activity as ViewModelStoreOwner).get(SharedMainViewModel::class.java)
|
||||||
inputContentInfo, flags, opts, mSupportedMimeTypes
|
}
|
||||||
) ?: false
|
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
|
package org.linphone.activities.main.viewmodels
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import org.linphone.activities.main.history.data.GroupedCallLogData
|
import org.linphone.activities.main.history.data.GroupedCallLogData
|
||||||
|
@ -66,6 +67,9 @@ class SharedMainViewModel : ViewModel() {
|
||||||
|
|
||||||
var chatRoomSubject: String = ""
|
var chatRoomSubject: String = ""
|
||||||
|
|
||||||
|
// When using keyboard to share gif or other, see RichContentReceiver & RichEditText classes
|
||||||
|
val richContentUri = MutableLiveData<Event<Uri>>()
|
||||||
|
|
||||||
/* Contacts */
|
/* Contacts */
|
||||||
|
|
||||||
val contactFragmentOpenedEvent: MutableLiveData<Event<Boolean>> by lazy {
|
val contactFragmentOpenedEvent: MutableLiveData<Event<Boolean>> by lazy {
|
||||||
|
|
Loading…
Reference in a new issue