Twidere-App-Android-Twitter.../twidere/src/main/kotlin/org/mariotaku/twidere/fragment/message/MessagesConversationFragmen...

644 lines
26 KiB
Kotlin
Raw Normal View History

2017-02-15 09:11:11 +01:00
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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.mariotaku.twidere.fragment.message
2016-07-02 05:54:53 +02:00
2017-02-14 08:27:28 +01:00
import android.accounts.AccountManager
2017-02-14 13:32:15 +01:00
import android.app.Activity
2017-02-12 15:26:09 +01:00
import android.content.Context
2017-02-14 13:32:15 +01:00
import android.content.Intent
2017-02-28 08:04:04 +01:00
import android.graphics.PorterDuff
2017-06-27 05:45:09 +02:00
import android.graphics.Rect
2017-02-14 13:32:15 +01:00
import android.net.Uri
2017-02-09 17:38:41 +01:00
import android.os.Bundle
2020-01-26 08:35:15 +01:00
import androidx.fragment.app.FragmentActivity
import androidx.loader.app.LoaderManager
import androidx.core.content.ContextCompat
import androidx.loader.content.Loader
import androidx.core.widget.TextViewCompat
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.FixedLinearLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.appcompat.widget.Toolbar
2017-02-15 06:53:53 +01:00
import android.view.*
import com.bumptech.glide.RequestManager
2017-02-14 17:26:48 +01:00
import com.squareup.otto.Subscribe
2017-02-16 07:50:25 +01:00
import kotlinx.android.synthetic.main.activity_premium_dashboard.*
2017-02-10 07:17:48 +01:00
import kotlinx.android.synthetic.main.fragment_messages_conversation.*
2017-02-19 10:41:14 +01:00
import kotlinx.android.synthetic.main.fragment_messages_conversation.view.*
2017-02-19 15:29:08 +01:00
import kotlinx.android.synthetic.main.layout_toolbar_message_conversation_title.*
2017-02-14 13:32:15 +01:00
import org.mariotaku.abstask.library.TaskStarter
2017-02-19 15:29:08 +01:00
import org.mariotaku.chameleon.Chameleon
import org.mariotaku.chameleon.ChameleonUtils
2017-02-14 07:30:07 +01:00
import org.mariotaku.kpreferences.get
2017-05-11 07:01:01 +02:00
import org.mariotaku.ktextension.*
2017-02-14 13:32:15 +01:00
import org.mariotaku.pickncrop.library.MediaPickerActivity
2017-02-10 07:17:48 +01:00
import org.mariotaku.sqliteqb.library.Expression
import org.mariotaku.sqliteqb.library.OrderBy
2017-02-09 17:38:41 +01:00
import org.mariotaku.twidere.R
2017-02-14 13:32:15 +01:00
import org.mariotaku.twidere.TwidereConstants.REQUEST_PICK_MEDIA
2017-02-15 18:03:48 +01:00
import org.mariotaku.twidere.activity.LinkHandlerActivity
2017-02-14 13:32:15 +01:00
import org.mariotaku.twidere.activity.ThemedMediaPickerActivity
import org.mariotaku.twidere.adapter.MediaPreviewAdapter
2017-02-10 07:17:48 +01:00
import org.mariotaku.twidere.adapter.MessagesConversationAdapter
2017-02-14 17:26:48 +01:00
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter
2017-05-11 07:01:01 +02:00
import org.mariotaku.twidere.annotation.AccountType
2017-05-10 15:47:35 +02:00
import org.mariotaku.twidere.constant.IntentConstants.*
2017-02-16 07:50:25 +01:00
import org.mariotaku.twidere.constant.nameFirstKey
2017-02-14 07:30:07 +01:00
import org.mariotaku.twidere.constant.newDocumentApiKey
2017-02-19 15:29:08 +01:00
import org.mariotaku.twidere.constant.profileImageStyleKey
2017-03-02 07:59:19 +01:00
import org.mariotaku.twidere.extension.loadProfileImage
2017-02-19 15:29:08 +01:00
import org.mariotaku.twidere.extension.model.*
2017-02-15 09:11:11 +01:00
import org.mariotaku.twidere.fragment.AbsContentListRecyclerViewFragment
import org.mariotaku.twidere.fragment.EditAltTextDialogFragment
2017-02-19 10:41:14 +01:00
import org.mariotaku.twidere.fragment.iface.IToolBarSupportFragment
2017-02-10 07:17:48 +01:00
import org.mariotaku.twidere.loader.ObjectCursorLoader
2017-02-14 07:30:07 +01:00
import org.mariotaku.twidere.model.*
2017-02-14 17:26:48 +01:00
import org.mariotaku.twidere.model.ParcelableMessageConversation.ConversationType
import org.mariotaku.twidere.model.event.GetMessagesTaskEvent
2017-02-15 18:03:48 +01:00
import org.mariotaku.twidere.model.event.SendMessageTaskEvent
2017-02-14 08:27:28 +01:00
import org.mariotaku.twidere.model.util.AccountUtils
2017-02-10 07:17:48 +01:00
import org.mariotaku.twidere.provider.TwidereDataStore.Messages
2017-02-14 08:27:28 +01:00
import org.mariotaku.twidere.service.LengthyOperationsService
2017-02-14 13:32:15 +01:00
import org.mariotaku.twidere.task.compose.AbsAddMediaTask
2017-02-15 06:32:45 +01:00
import org.mariotaku.twidere.task.compose.AbsDeleteMediaTask
2017-02-16 07:50:25 +01:00
import org.mariotaku.twidere.task.twitter.message.DestroyMessageTask
import org.mariotaku.twidere.task.twitter.message.GetMessagesTask
2017-02-17 11:42:39 +01:00
import org.mariotaku.twidere.task.twitter.message.MarkMessageReadTask
2017-02-16 07:50:25 +01:00
import org.mariotaku.twidere.util.ClipboardUtils
2017-02-12 15:26:09 +01:00
import org.mariotaku.twidere.util.DataStoreUtils
2017-02-14 07:30:07 +01:00
import org.mariotaku.twidere.util.IntentUtils
2017-02-14 13:32:15 +01:00
import org.mariotaku.twidere.util.PreviewGridItemDecoration
2017-02-15 06:53:53 +01:00
import org.mariotaku.twidere.view.ExtendedRecyclerView
2017-02-15 06:32:45 +01:00
import org.mariotaku.twidere.view.holder.compose.MediaPreviewViewHolder
2017-05-12 06:38:24 +02:00
import java.lang.ref.WeakReference
2017-02-12 15:26:09 +01:00
import java.util.concurrent.atomic.AtomicReference
2017-02-09 17:38:41 +01:00
2017-02-14 17:26:48 +01:00
class MessagesConversationFragment : AbsContentListRecyclerViewFragment<MessagesConversationAdapter>(),
2017-02-19 10:41:14 +01:00
IToolBarSupportFragment, LoaderManager.LoaderCallbacks<List<ParcelableMessage>?>,
EditAltTextDialogFragment.EditAltTextCallback {
2017-02-14 13:32:15 +01:00
private lateinit var mediaPreviewAdapter: MediaPreviewAdapter
2017-02-10 07:17:48 +01:00
2020-01-26 08:35:15 +01:00
private val accountKey: UserKey get() = arguments?.getParcelable(EXTRA_ACCOUNT_KEY)!!
2017-02-14 13:32:15 +01:00
2020-01-26 08:35:15 +01:00
private val conversationId: String get() = arguments?.getString(EXTRA_CONVERSATION_ID)!!
2017-02-09 17:38:41 +01:00
2017-02-14 08:27:28 +01:00
private val account: AccountDetails? by lazy {
AccountUtils.getAccountDetails(AccountManager.get(context), accountKey, true)
}
2017-02-14 17:26:48 +01:00
private val loadMoreTaskTag: String
get() = "loadMore:$accountKey:$conversationId"
// Layout manager reversed, so treat start as end
override val reachingEnd: Boolean
get() = super.reachingStart
// Layout manager reversed, so treat end as start
override val reachingStart: Boolean
get() = super.reachingEnd
2017-02-19 10:41:14 +01:00
override val controlBarHeight: Int
get() = toolbar.height
override var controlBarOffset: Float = 1f
override val toolbar: Toolbar
get() = conversationContainer.toolbar
2017-02-09 17:38:41 +01:00
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setHasOptionsMenu(true)
2020-01-26 08:35:15 +01:00
val context = context ?: return
2017-02-15 06:32:45 +01:00
val account = this.account ?: run {
activity?.finish()
return
}
2017-02-14 17:26:48 +01:00
adapter.listener = object : MessagesConversationAdapter.Listener {
2017-02-14 07:30:07 +01:00
override fun onMediaClick(position: Int, media: ParcelableMedia, accountKey: UserKey?) {
val message = adapter.getMessage(position)
2017-02-14 07:30:07 +01:00
IntentUtils.openMediaDirectly(context = context, accountKey = accountKey,
media = message.media, current = media,
newDocument = preferences[newDocumentApiKey], message = message)
}
2017-02-16 07:50:25 +01:00
override fun onMessageLongClick(position: Int, holder: RecyclerView.ViewHolder): Boolean {
return recyclerView.showContextMenuForChild(holder.itemView)
}
2017-02-14 07:30:07 +01:00
}
mediaPreviewAdapter = MediaPreviewAdapter(context, requestManager)
2017-02-14 13:32:15 +01:00
2017-02-15 06:32:45 +01:00
mediaPreviewAdapter.listener = object : MediaPreviewAdapter.Listener {
override fun onRemoveClick(position: Int, holder: MediaPreviewViewHolder) {
val task = DeleteMediaTask(this@MessagesConversationFragment,
arrayOf(mediaPreviewAdapter.getItem(position)))
TaskStarter.execute(task)
}
2017-02-15 06:53:53 +01:00
override fun onEditClick(position: Int, holder: MediaPreviewViewHolder) {
attachedMediaPreview.showContextMenuForChild(holder.itemView)
}
2017-02-15 06:32:45 +01:00
}
2017-02-14 13:32:15 +01:00
attachedMediaPreview.layoutManager = FixedLinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
attachedMediaPreview.adapter = mediaPreviewAdapter
attachedMediaPreview.addItemDecoration(PreviewGridItemDecoration(resources.getDimensionPixelSize(R.dimen.element_spacing_small)))
2017-02-16 07:50:25 +01:00
registerForContextMenu(recyclerView)
2017-02-15 06:53:53 +01:00
registerForContextMenu(attachedMediaPreview)
2017-02-14 13:32:15 +01:00
2017-02-14 08:27:28 +01:00
sendMessage.setOnClickListener {
performSendMessage()
}
2017-02-14 13:32:15 +01:00
addMedia.setOnClickListener {
openMediaPicker()
}
2017-02-20 16:13:48 +01:00
conversationTitleContainer.setOnClickListener {
val intent = IntentUtils.messageConversationInfo(accountKey, conversationId)
2017-02-22 02:08:22 +01:00
startActivityForResult(intent, REQUEST_MANAGE_CONVERSATION_INFO)
2017-02-20 16:13:48 +01:00
}
2017-02-14 08:27:28 +01:00
2017-02-19 15:29:08 +01:00
val activity = this.activity
if (activity is AppCompatActivity) {
activity.supportActionBar?.setDisplayShowTitleEnabled(false)
}
val theme = Chameleon.getOverrideTheme(context, activity)
2017-02-22 02:08:22 +01:00
conversationTitle.setTextColor(ChameleonUtils.getColorDependent(theme.colorToolbar))
conversationSubtitle.setTextColor(ChameleonUtils.getColorDependent(theme.colorToolbar))
2017-02-19 15:29:08 +01:00
conversationAvatar.style = preferences[profileImageStyleKey]
2017-05-12 06:38:24 +02:00
setupEditText()
2017-02-14 17:26:48 +01:00
// No refresh for this fragment
refreshEnabled = false
adapter.loadMoreSupportedPosition = ILoadMoreSupportAdapter.NONE
2017-05-11 07:01:01 +02:00
if (account.type == AccountType.TWITTER) {
2017-02-15 06:32:45 +01:00
addMedia.visibility = View.VISIBLE
} else {
addMedia.visibility = View.GONE
}
2017-05-10 15:47:35 +02:00
if (savedInstanceState != null) {
val list = savedInstanceState.getParcelableArrayList<ParcelableMediaUpdate>(EXTRA_MEDIA)
if (list != null) {
mediaPreviewAdapter.addAll(list)
}
}
2017-02-14 13:32:15 +01:00
updateMediaPreview()
2017-02-14 08:27:28 +01:00
2017-02-10 07:17:48 +01:00
loaderManager.initLoader(0, null, this)
2017-02-14 17:26:48 +01:00
showProgress()
}
override fun onStart() {
super.onStart()
bus.register(this)
}
override fun onStop() {
bus.unregister(this)
super.onStop()
2017-02-09 17:38:41 +01:00
}
2017-02-10 07:17:48 +01:00
2017-05-10 15:47:35 +02:00
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putParcelableArrayList(EXTRA_MEDIA, ArrayList(mediaPreviewAdapter.asList()))
}
2017-02-14 13:32:15 +01:00
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
REQUEST_PICK_MEDIA -> {
2017-05-11 07:01:01 +02:00
when (resultCode) {
Activity.RESULT_OK -> if (data != null) {
val mediaUris = MediaPickerActivity.getMediaUris(data)
val types = data.getBundleExtra(MediaPickerActivity.EXTRA_EXTRAS)?.getIntArray(EXTRA_TYPES)
TaskStarter.execute(AddMediaTask(this, mediaUris, types,
copySrc = false,
deleteSrc = false
))
2017-05-11 07:01:01 +02:00
}
RESULT_SEARCH_GIF -> {
val provider = gifShareProvider ?: return
startActivityForResult(provider.createGifSelectorIntent(), REQUEST_ADD_GIF)
}
2017-02-14 13:32:15 +01:00
}
2017-05-11 07:01:01 +02:00
2017-02-14 13:32:15 +01:00
}
2017-02-22 02:08:22 +01:00
REQUEST_MANAGE_CONVERSATION_INFO -> {
if (resultCode == MessageConversationInfoFragment.RESULT_CLOSE) {
activity?.finish()
}
}
2017-05-11 07:01:01 +02:00
REQUEST_ADD_GIF -> {
if (resultCode == Activity.RESULT_OK && data != null) {
2020-01-26 08:35:15 +01:00
val intent = context?.let {
ThemedMediaPickerActivity.withThemed(it)
.getMedia(data.data!!)
.extras(Bundle { this[EXTRA_TYPES] = intArrayOf(ParcelableMedia.Type.ANIMATED_GIF) })
.build()
}
2017-05-11 07:01:01 +02:00
startActivityForResult(intent, REQUEST_PICK_MEDIA)
}
}
2017-02-14 13:32:15 +01:00
}
}
2017-02-09 17:38:41 +01:00
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.fragment_messages_conversation, container, false)
}
2017-02-19 10:41:14 +01:00
override fun setupWindow(activity: FragmentActivity): Boolean {
return false
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_messages_conversation, menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
}
return false
}
2017-04-28 15:44:45 +02:00
override fun onCreateLoader(id: Int, args: Bundle?): Loader<List<ParcelableMessage>?> {
return ConversationLoader(requireContext(), accountKey, conversationId)
2017-02-10 07:17:48 +01:00
}
override fun onLoadFinished(loader: Loader<List<ParcelableMessage>?>, data: List<ParcelableMessage>?) {
2017-02-14 08:27:28 +01:00
val conversationLoader = loader as? ConversationLoader
val conversation = conversationLoader?.conversation
2017-02-14 17:26:48 +01:00
adapter.setData(conversation, data)
adapter.displaySenderProfile = conversation?.conversation_type == ConversationType.GROUP
if (conversation?.conversation_extras_type == ParcelableMessageConversation.ExtrasType.TWITTER_OFFICIAL) {
adapter.loadMoreSupportedPosition = ILoadMoreSupportAdapter.START
} else {
adapter.loadMoreSupportedPosition = ILoadMoreSupportAdapter.NONE
}
showContent()
2017-02-17 12:34:02 +01:00
if (conversation != null && !conversation.is_temp) {
markRead()
}
2017-02-17 15:27:53 +01:00
updateConversationStatus()
2017-02-14 17:26:48 +01:00
}
2017-04-28 15:44:45 +02:00
override fun onLoaderReset(loader: Loader<List<ParcelableMessage>?>) {
adapter.setData(null, null)
}
override fun onCreateAdapter(context: Context, requestManager: RequestManager): MessagesConversationAdapter {
return MessagesConversationAdapter(context, this.requestManager)
2017-02-14 17:26:48 +01:00
}
override fun onCreateLayoutManager(context: Context): LinearLayoutManager {
return FixedLinearLayoutManager(context, LinearLayoutManager.VERTICAL, true)
}
2017-04-21 11:23:55 +02:00
override fun onCreateItemDecoration(context: Context, recyclerView: RecyclerView,
2020-01-26 08:35:15 +01:00
layoutManager: LinearLayoutManager): RecyclerView.ItemDecoration? {
2017-02-14 17:26:48 +01:00
return null
}
override fun onLoadMoreContents(position: Long) {
if (ILoadMoreSupportAdapter.START !in position) return
2020-01-26 08:35:15 +01:00
val context = context ?: return
2020-06-08 23:07:20 +02:00
val message = adapter.getMessage(adapter.messageRange.last)
2017-02-14 17:26:48 +01:00
setLoadMoreIndicatorPosition(position)
val param = GetMessagesTask.LoadMoreMessageTaskParam(context, accountKey, conversationId,
message.id)
param.taskTag = loadMoreTaskTag
twitterWrapper.getMessagesAsync(param)
}
2020-01-26 08:35:15 +01:00
override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenu.ContextMenuInfo?) {
2017-02-16 07:50:25 +01:00
if (menuInfo !is ExtendedRecyclerView.ContextMenuInfo) return
2020-01-26 08:35:15 +01:00
val context = context ?: return
val activity = activity ?: return
2017-02-16 07:50:25 +01:00
when (menuInfo.recyclerViewId) {
R.id.recyclerView -> {
val message = adapter.getMessage(menuInfo.position)
2017-02-16 07:50:25 +01:00
val conversation = adapter.conversation
menu.setHeaderTitle(message.getSummaryText(context, userColorNameManager, conversation,
preferences[nameFirstKey]))
activity.menuInflater.inflate(R.menu.menu_conversation_message_item, menu)
}
R.id.attachedMediaPreview -> {
menu.setHeaderTitle(R.string.edit_media)
activity.menuInflater.inflate(R.menu.menu_attached_media_edit, menu)
}
2017-02-15 06:53:53 +01:00
}
}
override fun onContextItemSelected(item: MenuItem): Boolean {
2017-02-16 07:50:25 +01:00
val menuInfo = item.menuInfo as? ExtendedRecyclerView.ContextMenuInfo ?: run {
return super.onContextItemSelected(item)
}
2020-01-26 08:35:15 +01:00
val context = context ?: return super.onContextItemSelected(item)
2017-02-16 07:50:25 +01:00
when (menuInfo.recyclerViewId) {
R.id.recyclerView -> {
val message = adapter.getMessage(menuInfo.position)
2017-02-16 07:50:25 +01:00
when (item.itemId) {
R.id.copy -> {
ClipboardUtils.setText(context, message.text_unescaped)
}
R.id.delete -> {
val task = DestroyMessageTask(context, message.account_key,
message.conversation_id, message.id)
TaskStarter.execute(task)
}
}
return true
}
R.id.attachedMediaPreview -> {
when (item.itemId) {
R.id.edit_description -> {
val position = menuInfo.position
val altText = mediaPreviewAdapter.getItem(position).alt_text
executeAfterFragmentResumed { fragment ->
EditAltTextDialogFragment.show(fragment.childFragmentManager, position,
altText)
}
2017-02-15 06:53:53 +01:00
}
}
2017-02-16 07:50:25 +01:00
return true
2017-02-15 06:53:53 +01:00
}
}
return super.onContextItemSelected(item)
}
override fun onSetAltText(position: Int, altText: String?) {
mediaPreviewAdapter.setAltText(position, altText)
}
2017-06-27 05:45:09 +02:00
override fun onApplySystemWindowInsets(insets: Rect) {
view?.setPadding(insets.left, insets.top, insets.right, insets.bottom)
}
2017-02-14 17:26:48 +01:00
@Subscribe
fun onGetMessagesTaskEvent(event: GetMessagesTaskEvent) {
if (!event.running && event.taskTag == loadMoreTaskTag) {
setLoadMoreIndicatorPosition(ILoadMoreSupportAdapter.NONE)
}
2017-02-12 15:26:09 +01:00
}
2017-02-15 18:03:48 +01:00
@Subscribe
fun onSendMessageTaskEvent(event: SendMessageTaskEvent) {
2017-02-15 19:02:59 +01:00
if (!event.success || event.accountKey != accountKey || event.conversationId != conversationId) {
2017-02-15 18:03:48 +01:00
return
}
2020-01-26 08:35:15 +01:00
val arguments = arguments ?: return
val activity = activity ?: return
2017-02-15 18:03:48 +01:00
val newConversationId = event.newConversationId ?: return
arguments[EXTRA_CONVERSATION_ID] = newConversationId
if (activity is LinkHandlerActivity) {
activity.intent = IntentUtils.messageConversation(accountKey, newConversationId)
}
loaderManager.restartLoader(0, null, this)
}
2017-02-14 08:27:28 +01:00
private fun performSendMessage() {
2020-01-26 08:35:15 +01:00
val context = context ?: return
2017-02-14 17:26:48 +01:00
val conversation = adapter.conversation ?: return
2017-02-15 06:32:45 +01:00
val conversationAccount = this.account ?: return
2017-02-17 15:27:53 +01:00
if (conversation.readOnly) return
2017-02-15 19:17:09 +01:00
if (editText.empty && mediaPreviewAdapter.itemCount == 0) {
2017-02-14 08:27:28 +01:00
editText.error = getString(R.string.hint_error_message_no_content)
return
}
2017-05-11 07:01:01 +02:00
if (conversationAccount.type == AccountType.TWITTER) {
2017-02-15 19:17:09 +01:00
if (mediaPreviewAdapter.itemCount > defaultFeatures.twitterDirectMessageMediaLimit) {
2017-02-15 06:32:45 +01:00
editText.error = getString(R.string.error_message_media_message_too_many)
return
} else {
editText.error = null
}
2017-03-07 15:58:26 +01:00
} else if (mediaPreviewAdapter.itemCount > 0) {
2017-02-15 06:32:45 +01:00
editText.error = getString(R.string.error_message_media_message_attachment_not_supported)
return
}
2017-02-14 08:27:28 +01:00
val text = editText.text.toString()
val message = ParcelableNewMessage().apply {
2017-02-15 06:32:45 +01:00
this.account = conversationAccount
2017-02-14 13:32:15 +01:00
this.media = mediaPreviewAdapter.asList().toTypedArray()
2017-02-14 08:27:28 +01:00
this.conversation_id = conversation.id
2017-02-15 19:02:59 +01:00
this.recipient_ids = conversation.participants?.filter {
it.key != accountKey
}?.map {
2017-02-14 08:27:28 +01:00
it.key.id
}?.toTypedArray()
this.text = text
2017-02-15 19:02:59 +01:00
this.is_temp_conversation = conversation.is_temp
2017-02-14 08:27:28 +01:00
}
LengthyOperationsService.sendMessageAsync(context, message)
editText.text = null
2017-02-14 13:32:15 +01:00
// Clear media, those media will be deleted after sent
mediaPreviewAdapter.clear()
updateMediaPreview()
}
private fun openMediaPicker() {
2020-01-26 08:35:15 +01:00
val context = context ?: return
2017-05-11 07:01:01 +02:00
val builder = ThemedMediaPickerActivity.withThemed(context)
builder.pickSources(arrayOf(MediaPickerActivity.SOURCE_CAMERA,
MediaPickerActivity.SOURCE_CAMCORDER,
MediaPickerActivity.SOURCE_GALLERY,
MediaPickerActivity.SOURCE_CLIPBOARD))
2017-05-11 07:01:01 +02:00
if (gifShareProvider != null) {
builder.addEntry(getString(R.string.action_add_gif), "gif", RESULT_SEARCH_GIF)
}
builder.containsVideo(true)
builder.allowMultiple(false)
val intent = builder.build()
2017-02-14 13:32:15 +01:00
startActivityForResult(intent, REQUEST_PICK_MEDIA)
}
private fun attachMedia(media: List<ParcelableMediaUpdate>) {
mediaPreviewAdapter.addAll(media)
updateMediaPreview()
}
2017-02-15 06:32:45 +01:00
private fun removeMedia(media: List<ParcelableMediaUpdate>) {
mediaPreviewAdapter.removeAll(media)
updateMediaPreview()
}
2017-02-14 13:32:15 +01:00
private fun updateMediaPreview() {
attachedMediaPreview.visibility = if (mediaPreviewAdapter.itemCount > 0) {
View.VISIBLE
} else {
View.GONE
}
2017-02-15 06:32:45 +01:00
editText.error = null
2017-02-14 13:32:15 +01:00
}
private fun setProgressVisible(visible: Boolean) {
}
2017-02-17 11:42:39 +01:00
private fun markRead() {
2020-01-26 08:35:15 +01:00
val context = context ?: return
2017-02-17 11:42:39 +01:00
TaskStarter.execute(MarkMessageReadTask(context, accountKey, conversationId))
}
2017-02-17 15:27:53 +01:00
private fun updateConversationStatus() {
2020-01-26 08:35:15 +01:00
val context = context ?: return
val activity = activity ?: return
if (isDetached || activity.isFinishing) return
2017-02-17 15:27:53 +01:00
val conversation = adapter.conversation ?: return
2017-02-22 02:08:22 +01:00
val title = conversation.getTitle(context, userColorNameManager,
2017-02-17 15:27:53 +01:00
preferences[nameFirstKey]).first
val subtitle = conversation.getSubtitle(context)
2017-02-22 02:08:22 +01:00
activity.title = title
2017-02-17 15:27:53 +01:00
val readOnly = conversation.readOnly
2017-02-19 10:41:14 +01:00
addMedia.isEnabled = !readOnly
sendMessage.isEnabled = !readOnly
editText.isEnabled = !readOnly
2017-02-19 15:29:08 +01:00
2017-05-13 08:19:23 +02:00
conversationTitle.spannable = title
if (subtitle != null) {
conversationSubtitle.visibility = View.VISIBLE
2017-05-13 08:19:23 +02:00
conversationSubtitle.spannable = subtitle
} else {
conversationSubtitle.visibility = View.GONE
}
2017-02-28 08:04:04 +01:00
val stateIcon = if (conversation.notificationDisabled) {
2020-01-26 08:35:15 +01:00
ContextCompat.getDrawable(context, R.drawable.ic_message_type_speaker_muted)?.apply {
2017-02-28 08:04:04 +01:00
mutate()
setColorFilter(conversationTitle.currentTextColor, PorterDuff.Mode.SRC_ATOP)
}
} else {
null
}
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(conversationTitle, null,
null, stateIcon, null)
requestManager.loadProfileImage(context, conversation, preferences[profileImageStyleKey])
.into(conversationAvatar)
2017-02-17 15:27:53 +01:00
}
2017-05-12 06:38:24 +02:00
private fun setupEditText() {
editText.imageInputListener = { contentInfo ->
val type = if (contentInfo.description.mimeTypeCount > 0) {
AbsAddMediaTask.inferMediaType(contentInfo.description.getMimeType(0))
} else {
ParcelableMedia.Type.IMAGE
}
val task = AddMediaTask(this, arrayOf(contentInfo.contentUri), intArrayOf(type),
copySrc = true,
deleteSrc = false
)
2017-05-12 06:38:24 +02:00
task.callback = {
contentInfo.releasePermission()
}
TaskStarter.execute(task)
}
}
2017-02-14 13:32:15 +01:00
internal class AddMediaTask(
fragment: MessagesConversationFragment,
2017-05-11 07:01:01 +02:00
sources: Array<Uri>,
2017-05-12 06:38:24 +02:00
types: IntArray?,
copySrc: Boolean,
deleteSrc: Boolean
) : AbsAddMediaTask<((List<ParcelableMediaUpdate>?) -> Unit)?>(fragment.requireContext(), sources, types, copySrc, deleteSrc) {
2017-05-12 06:38:24 +02:00
private val fragmentRef = WeakReference(fragment)
override fun afterExecute(callback: ((List<ParcelableMediaUpdate>?) -> Unit)?, result: List<ParcelableMediaUpdate>?) {
callback?.invoke(result)
val fragment = fragmentRef.get()
if (fragment != null && result != null) {
fragment.setProgressVisible(false)
fragment.attachMedia(result)
}
2017-02-14 13:32:15 +01:00
}
override fun beforeExecute() {
2017-05-12 06:38:24 +02:00
val fragment = fragmentRef.get() ?: return
2017-02-14 13:32:15 +01:00
fragment.setProgressVisible(true)
}
2017-02-14 08:27:28 +01:00
}
2017-02-15 06:32:45 +01:00
internal class DeleteMediaTask(
fragment: MessagesConversationFragment,
val media: Array<ParcelableMediaUpdate>
) : AbsDeleteMediaTask<MessagesConversationFragment>(fragment.requireContext(),
2017-04-14 11:34:36 +02:00
media.mapToArray { Uri.parse(it.uri) }) {
2017-02-15 06:32:45 +01:00
init {
callback = fragment
}
2017-05-13 18:15:52 +02:00
override fun afterExecute(callback: MessagesConversationFragment?, results: BooleanArray) {
2017-04-23 10:39:19 +02:00
if (callback == null) return
2017-02-15 06:32:45 +01:00
callback.setProgressVisible(false)
2017-05-12 06:38:24 +02:00
callback.removeMedia(media.toList())
2017-02-15 06:32:45 +01:00
}
override fun beforeExecute() {
val fragment = callback ?: return
fragment.setProgressVisible(true)
}
}
2017-02-12 15:26:09 +01:00
internal class ConversationLoader(
context: Context,
val accountKey: UserKey,
val conversationId: String
2017-03-05 09:08:09 +01:00
) : ObjectCursorLoader<ParcelableMessage>(context, ParcelableMessage::class.java) {
2017-02-12 15:26:09 +01:00
private val atomicConversation = AtomicReference<ParcelableMessageConversation?>()
val conversation: ParcelableMessageConversation? get() = atomicConversation.get()
init {
uri = Messages.CONTENT_URI
projection = Messages.COLUMNS
selection = Expression.and(Expression.equalsArgs(Messages.ACCOUNT_KEY),
Expression.equalsArgs(Messages.CONVERSATION_ID)).sql
selectionArgs = arrayOf(accountKey.toString(), conversationId)
sortOrder = OrderBy(Messages.SORT_ID, false).sql
2017-04-28 15:44:45 +02:00
isUseCache = false
2017-02-12 15:26:09 +01:00
}
2020-01-26 08:35:15 +01:00
override fun onLoadInBackground(): MutableList<ParcelableMessage>? {
2017-02-12 15:26:09 +01:00
atomicConversation.set(DataStoreUtils.findMessageConversation(context, accountKey, conversationId))
return super.onLoadInBackground()
}
2017-02-10 07:17:48 +01:00
}
2017-02-22 02:08:22 +01:00
companion object {
private const val REQUEST_MANAGE_CONVERSATION_INFO = 101
2017-05-11 07:01:01 +02:00
private const val REQUEST_ADD_GIF = 102
private const val RESULT_SEARCH_GIF = 11
private const val EXTRA_TYPES = "types"
2017-02-22 02:08:22 +01:00
}
2017-02-10 07:17:48 +01:00
}