This commit is contained in:
andrew 2023-07-04 22:10:48 +09:30
parent d6b1440217
commit 8d66d948ca
7 changed files with 112 additions and 45 deletions

View File

@ -1,3 +1,4 @@
buildscript {
repositories {
google()
@ -13,6 +14,11 @@ buildscript {
}
}
plugins {
id 'kotlin-kapt'
id 'com.google.dagger.hilt.android'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'witness'
@ -29,6 +35,9 @@ configurations.all {
dependencies {
implementation("com.google.dagger:hilt-android:2.46.1")
kapt("com.google.dagger:hilt-android-compiler:2.44")
implementation "androidx.appcompat:appcompat:$appcompatVersion"
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation "com.google.android.material:material:$materialVersion"
@ -41,7 +50,6 @@ dependencies {
implementation 'androidx.exifinterface:exifinterface:1.3.4'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion"
implementation "androidx.lifecycle:lifecycle-process:$lifecycleVersion"
@ -328,3 +336,8 @@ def autoResConfig() {
.collect { matcher -> matcher.group(1) }
.sort()
}
// Allow references to generated code
kapt {
correctErrorTypes = true
}

View File

@ -2,6 +2,8 @@ package org.thoughtcrime.securesms.conversation.v2
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import androidx.activity.viewModels
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
@ -39,16 +41,24 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.integration.compose.ExperimentalGlideComposeApi
import com.bumptech.glide.integration.compose.GlideImage
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import network.loki.messenger.R
import network.loki.messenger.databinding.ViewVisibleMessageBinding
import network.loki.messenger.databinding.ViewVisibleMessageContentBinding
import org.session.libsession.messaging.jobs.AttachmentDownloadJob
import org.session.libsession.messaging.jobs.JobQueue
import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.MediaPreviewActivity
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.components.ProfilePictureView
import org.thoughtcrime.securesms.database.Storage
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
import org.thoughtcrime.securesms.mms.ImageSlide
import org.thoughtcrime.securesms.mms.Slide
import org.thoughtcrime.securesms.ui.AppTheme
import org.thoughtcrime.securesms.ui.CarouselNextButton
@ -64,7 +74,6 @@ import org.thoughtcrime.securesms.ui.colorDestructive
import org.thoughtcrime.securesms.ui.destructiveButtonColors
import javax.inject.Inject
@AndroidEntryPoint
class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
@ -73,6 +82,8 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
@Inject
lateinit var storage: Storage
private val viewModel: MessageDetailsViewModel by viewModels()
companion object {
// Extras
const val MESSAGE_TIMESTAMP = "message_timestamp"
@ -82,8 +93,6 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
const val ON_DELETE = 3
}
val viewModel = MessageDetailsViewModel()
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
super.onCreate(savedInstanceState, ready)
@ -116,7 +125,12 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
onResend = { setResultAndFinish(ON_RESEND) },
onDelete = { setResultAndFinish(ON_DELETE) },
onClickImage = { slide ->
MediaPreviewActivity.getPreviewIntent(this, slide, details.mmsRecord, details.sender)
MediaPreviewActivity.getPreviewIntent(
this,
slide,
details.mmsRecord,
details.sender
)
.let(::startActivity)
}
)
@ -144,6 +158,12 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
)
}
private fun onAttachmentNeedsDownload(attachmentId: Long, mmsId: Long) {
lifecycleScope.launch(Dispatchers.IO) {
JobQueue.shared.add(AttachmentDownloadJob(attachmentId, mmsId))
}
}
@Composable
fun MessageDetails(
messageDetails: MessageDetails,
@ -152,27 +172,39 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
onDelete: () -> Unit = {},
onClickImage: (Slide) -> Unit = {},
) {
messageDetails.apply {
AppTheme {
Column(
modifier = Modifier.verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
Attachments(attachments) { onClickImage(it) }
MetaDataCell(messageDetails)
Buttons(
error != null,
onReply,
onResend,
onDelete,
AppTheme {
Column(
modifier = Modifier.verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
messageDetails.mmsRecord?.let { message ->
AndroidView(
modifier = Modifier.padding(32.dp),
factory = {
ViewVisibleMessageContentBinding.inflate(LayoutInflater.from(it)).mainContainerConstraint.apply {
bind(
message,
thread = message.individualRecipient,
onAttachmentNeedsDownload = ::onAttachmentNeedsDownload
)
}
}
)
}
Attachments(messageDetails.attachments) { onClickImage(it) }
MetadataCell(messageDetails)
Buttons(
messageDetails.error != null,
onReply,
onResend,
onDelete,
)
}
}
}
@Composable
fun MetaDataCell(
fun MetadataCell(
messageDetails: MessageDetails,
) {
messageDetails.apply {
@ -205,7 +237,9 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
factory = {
ProfilePictureView(it).apply { update(sender) }
},
modifier = Modifier.width(46.dp).height(46.dp)
modifier = Modifier
.width(46.dp)
.height(46.dp)
)
}
}
@ -245,13 +279,12 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
@Composable
fun Attachments(attachments: List<Attachment>, onClick: (Slide) -> Unit) {
val slide = attachments.firstOrNull()?.slide ?: return
when {
slide.hasImage() -> Carousel(attachments, onClick)
when(attachments.firstOrNull()?.slide) {
is ImageSlide -> Carousel(attachments, onClick)
}
}
@OptIn(ExperimentalFoundationApi::class,)
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun Carousel(attachments: List<Attachment>, onClick: (Slide) -> Unit) {
val imageAttachments = attachments.filter { it.slide.hasImage() }
@ -263,7 +296,11 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
Box(modifier = Modifier.weight(1f)) {
CellPager(pagerState, imageAttachments, onClick)
HorizontalPagerIndicator(pagerState)
ExpandButton(modifier = Modifier.align(Alignment.BottomEnd).padding(8.dp))
ExpandButton(
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(8.dp)
)
}
CarouselNextButton(pagerState)
}
@ -276,7 +313,11 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
ExperimentalGlideComposeApi::class
)
@Composable
private fun CellPager(pagerState: PagerState, imageAttachments: List<Attachment>, onClick: (Slide) -> Unit) {
private fun CellPager(
pagerState: PagerState,
imageAttachments: List<Attachment>,
onClick: (Slide) -> Unit
) {
CellNoMargin {
HorizontalPager(state = pagerState) { i ->
val slide = imageAttachments[i].slide
@ -326,7 +367,8 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
TitledText(
titledText,
modifier = modifier,
valueStyle = LocalTextStyle.current.copy(color = colorDestructive))
valueStyle = LocalTextStyle.current.copy(color = colorDestructive)
)
}
@Composable
@ -334,7 +376,8 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() {
TitledText(
titledText,
modifier = modifier,
valueStyle = LocalTextStyle.current.copy(fontFamily = FontFamily.Monospace))
valueStyle = LocalTextStyle.current.copy(fontFamily = FontFamily.Monospace)
)
}
@Composable

View File

@ -3,6 +3,8 @@ package org.thoughtcrime.securesms.conversation.v2
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import dagger.hilt.android.AndroidEntryPoint
import dagger.hilt.android.lifecycle.HiltViewModel
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment
import org.session.libsession.utilities.Util
import org.session.libsession.utilities.recipients.Recipient
@ -31,9 +33,10 @@ data class Attachment(
val fileDetails: List<TitledText>
)
class MessageDetailsViewModel : ViewModel() {
@Inject
lateinit var attachmentDb: AttachmentDatabase
@HiltViewModel
class MessageDetailsViewModel @Inject constructor(
private val attachmentDb: AttachmentDatabase
): ViewModel() {
fun setMessageRecord(value: MessageRecord?, error: String?) {
val mmsRecord = value as? MmsMessageRecord

View File

@ -38,6 +38,7 @@ import org.thoughtcrime.securesms.conversation.v2.utilities.TextUtilities.getInt
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
import org.thoughtcrime.securesms.database.model.SmsMessageRecord
import org.thoughtcrime.securesms.mms.GlideApp
import org.thoughtcrime.securesms.mms.GlideRequests
import org.thoughtcrime.securesms.util.SearchUtil
import org.thoughtcrime.securesms.util.getAccentColor
@ -60,12 +61,12 @@ class VisibleMessageContentView : ConstraintLayout {
// region Updating
fun bind(
message: MessageRecord,
isStartOfMessageCluster: Boolean,
isEndOfMessageCluster: Boolean,
glide: GlideRequests,
isStartOfMessageCluster: Boolean = true,
isEndOfMessageCluster: Boolean = true,
glide: GlideRequests = GlideApp.with(this),
thread: Recipient,
searchQuery: String?,
contactIsTrusted: Boolean,
searchQuery: String? = null,
contactIsTrusted: Boolean = true,
onAttachmentNeedsDownload: (Long, Long) -> Unit
) {
// Background

View File

@ -46,6 +46,7 @@ import org.thoughtcrime.securesms.database.ThreadDatabase
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.groups.OpenGroupManager
import org.thoughtcrime.securesms.home.UserDetailsBottomSheet
import org.thoughtcrime.securesms.mms.GlideApp
import org.thoughtcrime.securesms.mms.GlideRequests
import org.thoughtcrime.securesms.util.DateUtils
import org.thoughtcrime.securesms.util.disableClipping
@ -70,7 +71,6 @@ class VisibleMessageView : LinearLayout {
@Inject lateinit var mmsDb: MmsDatabase
private val binding by lazy { ViewVisibleMessageBinding.bind(this) }
private val screenWidth = Resources.getSystem().displayMetrics.widthPixels
private val swipeToReplyIcon = ContextCompat.getDrawable(context, R.drawable.ic_baseline_reply_24)!!.mutate()
private val swipeToReplyIconRect = Rect()
private var dx = 0.0f
@ -119,13 +119,13 @@ class VisibleMessageView : LinearLayout {
// region Updating
fun bind(
message: MessageRecord,
previous: MessageRecord?,
next: MessageRecord?,
glide: GlideRequests,
searchQuery: String?,
contact: Contact?,
previous: MessageRecord? = null,
next: MessageRecord? = null,
glide: GlideRequests = GlideApp.with(this),
searchQuery: String? = null,
contact: Contact? = null,
senderSessionID: String,
delegate: VisibleMessageViewDelegate?,
delegate: VisibleMessageViewDelegate? = null,
onAttachmentNeedsDownload: (Long, Long) -> Unit
) {
val threadID = message.threadId

View File

@ -93,11 +93,13 @@ fun CellWithPaddingAndMargin(
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun BoxScope.HorizontalPagerIndicator(pagerState: PagerState) {
Card(shape = RoundedCornerShape(50.dp),
if (pagerState.pageCount >= 2) Card(
shape = RoundedCornerShape(50.dp),
backgroundColor = Color.Black.copy(alpha = 0.4f),
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(8.dp)) {
.padding(8.dp)
) {
Box(modifier = Modifier.padding(8.dp)) {
HorizontalPagerIndicator(
pagerState = pagerState,

View File

@ -1,3 +1,4 @@
buildscript {
repositories {
google()
@ -12,6 +13,10 @@ buildscript {
}
}
plugins{
id("com.google.dagger.hilt.android") version "2.44" apply false
}
allprojects {
repositories {
google()