Refactor slide out of MessageDetailsActivity

This commit is contained in:
andrew 2023-07-11 12:28:04 +09:30
parent 172f85ae4f
commit 1845b60dac
4 changed files with 74 additions and 49 deletions

View File

@ -146,6 +146,10 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
} }
}; };
public static Intent getPreviewIntent(Context context, MediaPreviewArgs args) {
return getPreviewIntent(context, args.getSlide(), args.getMmsRecord(), args.getThread());
}
public static Intent getPreviewIntent(Context context, Slide slide, MmsMessageRecord mms, Recipient threadRecipient) { public static Intent getPreviewIntent(Context context, Slide slide, MmsMessageRecord mms, Recipient threadRecipient) {
Intent previewIntent = null; Intent previewIntent = null;
if (MediaPreviewActivity.isContentTypeSupported(slide.getContentType()) && slide.getUri() != null) { if (MediaPreviewActivity.isContentTypeSupported(slide.getContentType()) && slide.getUri() != null) {

View File

@ -0,0 +1,11 @@
package org.thoughtcrime.securesms
import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
import org.thoughtcrime.securesms.mms.Slide
data class MediaPreviewArgs(
val slide: Slide,
val mmsRecord: MmsMessageRecord?,
val thread: Recipient?,
)

View File

@ -38,7 +38,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.layout
import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -49,18 +48,12 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.lifecycleScope import androidx.core.content.ContextCompat
import com.bumptech.glide.integration.compose.ExperimentalGlideComposeApi import com.bumptech.glide.integration.compose.ExperimentalGlideComposeApi
import com.bumptech.glide.integration.compose.GlideImage import com.bumptech.glide.integration.compose.GlideImage
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import network.loki.messenger.R import network.loki.messenger.R
import network.loki.messenger.databinding.ViewVisibleMessageContentBinding import network.loki.messenger.databinding.ViewVisibleMessageContentBinding
import org.session.libsession.messaging.jobs.AttachmentDownloadJob
import org.session.libsession.messaging.jobs.JobQueue
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentTransferProgress
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment
import org.thoughtcrime.securesms.MediaPreviewActivity import org.thoughtcrime.securesms.MediaPreviewActivity
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.database.Storage import org.thoughtcrime.securesms.database.Storage
@ -109,7 +102,7 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
intent.getLongExtra(MESSAGE_TIMESTAMP, -1L).let(viewModel::setMessageTimestamp) intent.getLongExtra(MESSAGE_TIMESTAMP, -1L).let(viewModel::setMessageTimestamp)
if (viewModel.details.value == null) { if (viewModel.state.value == null) {
finish() finish()
return return
} }
@ -117,34 +110,23 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
ComposeView(this) ComposeView(this)
.apply { setContent { MessageDetailsScreen() } } .apply { setContent { MessageDetailsScreen() } }
.let(::setContentView) .let(::setContentView)
viewModel.event.observe(this) {
startActivity(MediaPreviewActivity.getPreviewIntent(this, it))
}
} }
@Composable @Composable
private fun MessageDetailsScreen() { private fun MessageDetailsScreen() {
val state by viewModel.details.observeAsState(MessageDetailsState()) val state by viewModel.state.observeAsState(MessageDetailsState())
AppTheme { AppTheme {
MessageDetails( MessageDetails(
state = state, state = state,
onReply = { setResultAndFinish(ON_REPLY) }, onReply = { setResultAndFinish(ON_REPLY) },
onResend = state.error?.let { { setResultAndFinish(ON_RESEND) } }, onResend = state.error?.let { { setResultAndFinish(ON_RESEND) } },
onDelete = { setResultAndFinish(ON_DELETE) }, onDelete = { setResultAndFinish(ON_DELETE) },
onClickImage = { i -> onClickImage = { viewModel.onClickImage(it) },
val slide = state.attachments[i].slide onAttachmentNeedsDownload = viewModel::onAttachmentNeedsDownload,
// only open to downloaded images
if (slide.transferState == AttachmentTransferProgress.TRANSFER_PROGRESS_FAILED) {
// Restart download here (on IO thread)
(slide.asAttachment() as? DatabaseAttachment)?.let { attachment ->
onAttachmentNeedsDownload(attachment.attachmentId.rowId, state.mmsRecord!!.getId())
}
}
if (!slide.isInProgress) MediaPreviewActivity.getPreviewIntent(
this,
slide,
state.mmsRecord,
state.thread,
).let(::startActivity)
},
onAttachmentNeedsDownload = ::onAttachmentNeedsDownload,
) )
} }
} }
@ -156,12 +138,6 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
finish() finish()
} }
private fun onAttachmentNeedsDownload(attachmentId: Long, mmsId: Long) {
lifecycleScope.launch(Dispatchers.IO) {
JobQueue.shared.add(AttachmentDownloadJob(attachmentId, mmsId))
}
}
} }
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")

View File

@ -1,13 +1,21 @@
package org.thoughtcrime.securesms.conversation.v2 package org.thoughtcrime.securesms.conversation.v2
import android.net.Uri
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import network.loki.messenger.R import network.loki.messenger.R
import org.session.libsession.messaging.jobs.AttachmentDownloadJob
import org.session.libsession.messaging.jobs.JobQueue
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentTransferProgress
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment
import org.session.libsession.utilities.Util import org.session.libsession.utilities.Util
import org.session.libsession.utilities.recipients.Recipient import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.MediaPreviewArgs
import org.thoughtcrime.securesms.database.AttachmentDatabase import org.thoughtcrime.securesms.database.AttachmentDatabase
import org.thoughtcrime.securesms.database.LokiMessageDatabase import org.thoughtcrime.securesms.database.LokiMessageDatabase
import org.thoughtcrime.securesms.database.MmsSmsDatabase import org.thoughtcrime.securesms.database.MmsSmsDatabase
@ -30,15 +38,21 @@ class MessageDetailsViewModel @Inject constructor(
private val threadDb: ThreadDatabase, private val threadDb: ThreadDatabase,
) : ViewModel() { ) : ViewModel() {
private var _state = MutableLiveData(MessageDetailsState())
val state: LiveData<MessageDetailsState> = _state
private var _event = MutableLiveData<MediaPreviewArgs>()
val event: LiveData<MediaPreviewArgs> = _event
fun setMessageTimestamp(timestamp: Long) { fun setMessageTimestamp(timestamp: Long) {
val record = mmsSmsDatabase.getMessageForTimestamp(timestamp) ?: return val record = mmsSmsDatabase.getMessageForTimestamp(timestamp) ?: return
val mmsRecord = record as? MmsMessageRecord val mmsRecord = record as? MmsMessageRecord
_details.value = record.run { _state.value = record.run {
val slides = mmsRecord?.slideDeck?.thumbnailSlides?.toList() ?: emptyList() val slides = mmsRecord?.slideDeck?.slides ?: emptyList()
MessageDetailsState( MessageDetailsState(
attachments = slides.map { Attachment(it, it.details) }, attachments = slides.map(::Attachment),
record = record, record = record,
sent = dateSent.let(::Date).toString().let { TitledText(R.string.message_details_header__sent, it) }, sent = dateSent.let(::Date).toString().let { TitledText(R.string.message_details_header__sent, it) },
received = dateReceived.let(::Date).toString().let { TitledText(R.string.message_details_header__received, it) }, received = dateReceived.let(::Date).toString().let { TitledText(R.string.message_details_header__received, it) },
@ -50,9 +64,6 @@ class MessageDetailsViewModel @Inject constructor(
} }
} }
private var _details = MutableLiveData(MessageDetailsState())
val details: LiveData<MessageDetailsState> = _details
private val Slide.details: List<TitledText> private val Slide.details: List<TitledText>
get() = listOfNotNull( get() = listOfNotNull(
fileName.orNull()?.let { TitledText(R.string.message_details_header__file_id, it) }, fileName.orNull()?.let { TitledText(R.string.message_details_header__file_id, it) },
@ -78,12 +89,38 @@ class MessageDetailsViewModel @Inject constructor(
) )
} }
fun Attachment(slide: Slide): Attachment =
Attachment(slide.details, slide.fileName.orNull(), slide.uri, slide is ImageSlide)
fun onClickImage(index: Int) {
val state = state.value ?: return
val mmsRecord = state.mmsRecord ?: return
val slide = mmsRecord.slideDeck.slides[index] ?: return
// only open to downloaded images
if (slide.transferState == AttachmentTransferProgress.TRANSFER_PROGRESS_FAILED) {
// Restart download here (on IO thread)
(slide.asAttachment() as? DatabaseAttachment)?.let { attachment ->
onAttachmentNeedsDownload(attachment.attachmentId.rowId, state.mmsRecord.getId())
}
}
if (slide.isInProgress) return
_event.value = MediaPreviewArgs(slide, state.mmsRecord, state.thread)
}
fun onAttachmentNeedsDownload(attachmentId: Long, mmsId: Long) {
viewModelScope.launch(Dispatchers.IO) {
JobQueue.shared.add(AttachmentDownloadJob(attachmentId, mmsId))
}
}
} }
data class MessageDetailsState( data class MessageDetailsState(
val attachments: List<Attachment> = emptyList(), val attachments: List<Attachment> = emptyList(),
val imageAttachments: List<Attachment> = attachments.filter { it.hasImage() }, val imageAttachments: List<Attachment> = attachments.filter { it.hasImage },
val nonImageAttachmentFileDetails: List<TitledText>? = attachments.firstOrNull { !it.hasImage() }?.fileDetails, val nonImageAttachmentFileDetails: List<TitledText>? = attachments.firstOrNull { !it.hasImage }?.fileDetails,
val record: MessageRecord? = null, val record: MessageRecord? = null,
val mmsRecord: MmsMessageRecord? = record as? MmsMessageRecord, val mmsRecord: MmsMessageRecord? = record as? MmsMessageRecord,
val sent: TitledText? = null, val sent: TitledText? = null,
@ -97,11 +134,8 @@ data class MessageDetailsState(
} }
data class Attachment( data class Attachment(
val slide: Slide, val fileDetails: List<TitledText>,
val fileDetails: List<TitledText> val fileName: String?,
) { val uri: Uri?,
val fileName: String? get() = slide.fileName.orNull() val hasImage: Boolean
val uri get() = slide.uri )
fun hasImage() = slide is ImageSlide
}