mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-17 21:47:28 +00:00
refactor: use activity dispatcher
This commit is contained in:
parent
bb00754237
commit
9cccbd7aae
@ -1,6 +1,7 @@
|
|||||||
package org.thoughtcrime.securesms.conversation.v2
|
package org.thoughtcrime.securesms.conversation.v2
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
@ -11,9 +12,12 @@ import androidx.core.view.children
|
|||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import kotlinx.android.synthetic.main.album_thumbnail_view.view.*
|
import kotlinx.android.synthetic.main.album_thumbnail_view.view.*
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
|
import org.thoughtcrime.securesms.MediaPreviewActivity
|
||||||
import org.thoughtcrime.securesms.components.CornerMask
|
import org.thoughtcrime.securesms.components.CornerMask
|
||||||
import org.thoughtcrime.securesms.conversation.v2.utilities.KThumbnailView
|
import org.thoughtcrime.securesms.conversation.v2.utilities.KThumbnailView
|
||||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
||||||
|
import org.thoughtcrime.securesms.loki.utilities.ActivityDispatcher
|
||||||
|
import org.thoughtcrime.securesms.longmessage.LongMessageActivity
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||||
import org.thoughtcrime.securesms.mms.Slide
|
import org.thoughtcrime.securesms.mms.Slide
|
||||||
|
|
||||||
@ -35,12 +39,6 @@ class AlbumThumbnailView : FrameLayout {
|
|||||||
private val cornerMask by lazy { CornerMask(this) }
|
private val cornerMask by lazy { CornerMask(this) }
|
||||||
private var slides: List<Slide> = listOf()
|
private var slides: List<Slide> = listOf()
|
||||||
|
|
||||||
sealed class Hit {
|
|
||||||
object ReadMoreHit : Hit()
|
|
||||||
data class SlideHit(val slide: Slide) : Hit()
|
|
||||||
data class DownloadHit(val slide: Slide) : Hit()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun initialize() {
|
private fun initialize() {
|
||||||
LayoutInflater.from(context).inflate(R.layout.album_thumbnail_view, this)
|
LayoutInflater.from(context).inflate(R.layout.album_thumbnail_view, this)
|
||||||
}
|
}
|
||||||
@ -54,25 +52,42 @@ class AlbumThumbnailView : FrameLayout {
|
|||||||
|
|
||||||
// region Interaction
|
// region Interaction
|
||||||
|
|
||||||
fun calculateHitObject(hitRect: Rect): Hit? {
|
fun calculateHitObject(rawRect: Rect, mms: MmsMessageRecord) {
|
||||||
// Z-check in specific order
|
// Z-check in specific order
|
||||||
val testRect = Rect()
|
val testRect = Rect()
|
||||||
// test "Read More"
|
// test "Read More"
|
||||||
albumCellBodyTextReadMore.getHitRect(testRect)
|
albumCellBodyTextReadMore.getGlobalVisibleRect(testRect)
|
||||||
if (Rect.intersects(hitRect, testRect)) {
|
if (Rect.intersects(rawRect, testRect)) {
|
||||||
return Hit.ReadMoreHit
|
// dispatch to activity view
|
||||||
|
ActivityDispatcher.get(context)?.dispatchIntent { context ->
|
||||||
|
LongMessageActivity.getIntent(context, mms.recipient.address, mms.getId(), true)
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
// test each album child
|
// test each album child
|
||||||
albumCellContainer.findViewById<ViewGroup>(R.id.album_thumbnail_root)?.children?.forEachIndexed { index, child ->
|
albumCellContainer.findViewById<ViewGroup>(R.id.album_thumbnail_root)?.children?.forEachIndexed { index, child ->
|
||||||
child.getHitRect(testRect)
|
child.getGlobalVisibleRect(testRect)
|
||||||
if (Rect.intersects(hitRect, testRect)) {
|
if (Rect.intersects(rawRect, testRect)) {
|
||||||
// hit intersects with this particular child
|
// hit intersects with this particular child
|
||||||
slides.getOrNull(index)?.let { slide ->
|
slides.getOrNull(index)?.let { slide ->
|
||||||
return Hit.SlideHit(slide)
|
// dispatch to view image
|
||||||
|
if (MediaPreviewActivity.isContentTypeSupported(slide.contentType) && slide.uri != null) {
|
||||||
|
ActivityDispatcher.get(context)?.dispatchIntent { context ->
|
||||||
|
Intent(context, MediaPreviewActivity::class.java).apply {
|
||||||
|
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
|
setDataAndType(slide.uri, slide.contentType)
|
||||||
|
putExtra(MediaPreviewActivity.ADDRESS_EXTRA, mms.recipient.address)
|
||||||
|
putExtra(MediaPreviewActivity.OUTGOING_EXTRA, mms.isOutgoing)
|
||||||
|
putExtra(MediaPreviewActivity.DATE_EXTRA, mms.timestamp)
|
||||||
|
putExtra(MediaPreviewActivity.SIZE_EXTRA, slide.asAttachment().size)
|
||||||
|
putExtra(MediaPreviewActivity.CAPTION_EXTRA, slide.caption.orNull())
|
||||||
|
putExtra(MediaPreviewActivity.LEFT_IS_RECENT_EXTRA, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bind(glideRequests: GlideRequests, message: MmsMessageRecord,
|
fun bind(glideRequests: GlideRequests, message: MmsMessageRecord,
|
||||||
|
@ -2,6 +2,9 @@ package org.thoughtcrime.securesms.conversation.v2
|
|||||||
|
|
||||||
import android.animation.FloatEvaluator
|
import android.animation.FloatEvaluator
|
||||||
import android.animation.ValueAnimator
|
import android.animation.ValueAnimator
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
@ -46,6 +49,9 @@ import org.thoughtcrime.securesms.database.model.MessageRecord
|
|||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository
|
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository
|
||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel
|
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel
|
||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel.LinkPreviewState
|
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel.LinkPreviewState
|
||||||
|
import org.thoughtcrime.securesms.loki.utilities.ActivityDispatcher
|
||||||
|
import org.thoughtcrime.securesms.loki.utilities.push
|
||||||
|
import org.thoughtcrime.securesms.loki.utilities.show
|
||||||
import org.thoughtcrime.securesms.loki.utilities.toPx
|
import org.thoughtcrime.securesms.loki.utilities.toPx
|
||||||
import org.thoughtcrime.securesms.mms.GlideApp
|
import org.thoughtcrime.securesms.mms.GlideApp
|
||||||
import org.thoughtcrime.securesms.util.DateUtils
|
import org.thoughtcrime.securesms.util.DateUtils
|
||||||
@ -57,7 +63,7 @@ import kotlin.math.*
|
|||||||
// price we pay is a bit of back and forth between the input bar and the conversation activity.
|
// price we pay is a bit of back and forth between the input bar and the conversation activity.
|
||||||
|
|
||||||
class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDelegate,
|
class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDelegate,
|
||||||
InputBarRecordingViewDelegate, ConversationRecyclerViewDelegate {
|
InputBarRecordingViewDelegate, ConversationRecyclerViewDelegate, ActivityDispatcher {
|
||||||
private val scrollButtonFullVisibilityThreshold by lazy { toPx(120.0f, resources) }
|
private val scrollButtonFullVisibilityThreshold by lazy { toPx(120.0f, resources) }
|
||||||
private val scrollButtonNoVisibilityThreshold by lazy { toPx(20.0f, resources) }
|
private val scrollButtonNoVisibilityThreshold by lazy { toPx(20.0f, resources) }
|
||||||
private val screenWidth = Resources.getSystem().displayMetrics.widthPixels
|
private val screenWidth = Resources.getSystem().displayMetrics.widthPixels
|
||||||
@ -76,8 +82,8 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
val adapter = ConversationAdapter(
|
val adapter = ConversationAdapter(
|
||||||
this,
|
this,
|
||||||
cursor,
|
cursor,
|
||||||
onItemPress = { message, position, view, rect ->
|
onItemPress = { message, position, view, rawRect ->
|
||||||
handlePress(message, position, view, rect)
|
handlePress(message, position, view, rawRect)
|
||||||
},
|
},
|
||||||
onItemSwipeToReply = { message, position ->
|
onItemSwipeToReply = { message, position ->
|
||||||
handleSwipeToReply(message, position)
|
handleSwipeToReply(message, position)
|
||||||
@ -138,6 +144,18 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
ApplicationContext.getInstance(this).messageNotifier.setVisibleThread(-1)
|
ApplicationContext.getInstance(this).messageNotifier.setVisibleThread(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getSystemService(name: String): Any? {
|
||||||
|
if (name == ActivityDispatcher.SERVICE) {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
return super.getSystemService(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispatchIntent(body: (Context) -> Intent) {
|
||||||
|
val intent = body(this)
|
||||||
|
push(intent, false)
|
||||||
|
}
|
||||||
|
|
||||||
private fun setUpRecyclerView() {
|
private fun setUpRecyclerView() {
|
||||||
conversationRecyclerView.adapter = adapter
|
conversationRecyclerView.adapter = adapter
|
||||||
val layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, true)
|
val layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, true)
|
||||||
@ -452,7 +470,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
}
|
}
|
||||||
|
|
||||||
// `position` is the adapter position; not the visual position
|
// `position` is the adapter position; not the visual position
|
||||||
private fun handlePress(message: MessageRecord, position: Int, view: VisibleMessageView, hitRect: Rect) {
|
private fun handlePress(message: MessageRecord, position: Int, view: VisibleMessageView, rawRect: Rect) {
|
||||||
val actionMode = this.actionMode
|
val actionMode = this.actionMode
|
||||||
if (actionMode != null) {
|
if (actionMode != null) {
|
||||||
adapter.toggleSelection(message, position)
|
adapter.toggleSelection(message, position)
|
||||||
@ -467,7 +485,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
// We have to use onContentClick (rather than a click listener directly on
|
// We have to use onContentClick (rather than a click listener directly on
|
||||||
// the view) so as to not interfere with all the other gestures. Do not add
|
// the view) so as to not interfere with all the other gestures. Do not add
|
||||||
// onClickListeners directly to message content views.
|
// onClickListeners directly to message content views.
|
||||||
view.onContentClick(hitRect)
|
view.onContentClick(rawRect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ class ConversationAdapter(context: Context, cursor: Cursor, private val onItemPr
|
|||||||
view.messageTimestampTextView.isVisible = isSelected
|
view.messageTimestampTextView.isVisible = isSelected
|
||||||
val position = viewHolder.adapterPosition
|
val position = viewHolder.adapterPosition
|
||||||
view.bind(message, getMessageBefore(position, cursor), getMessageAfter(position, cursor), glide)
|
view.bind(message, getMessageBefore(position, cursor), getMessageAfter(position, cursor), glide)
|
||||||
view.onPress = { x, y -> onItemPress(message, viewHolder.adapterPosition, view, Rect(x,y,x,y)) }
|
view.onPress = { rawX, rawY -> onItemPress(message, viewHolder.adapterPosition, view, Rect(rawX, rawY, rawX, rawY)) }
|
||||||
view.onSwipeToReply = { onItemSwipeToReply(message, viewHolder.adapterPosition) }
|
view.onSwipeToReply = { onItemSwipeToReply(message, viewHolder.adapterPosition) }
|
||||||
view.onLongPress = { onItemLongPress(message, viewHolder.adapterPosition) }
|
view.onLongPress = { onItemLongPress(message, viewHolder.adapterPosition) }
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ import org.thoughtcrime.securesms.mms.GlideRequests
|
|||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
class VisibleMessageContentView : LinearLayout {
|
class VisibleMessageContentView : LinearLayout {
|
||||||
var onContentClick: ((Rect) -> Unit)? = null
|
var onContentClick: ((rawRect: Rect) -> Unit)? = null
|
||||||
|
|
||||||
// region Lifecycle
|
// region Lifecycle
|
||||||
constructor(context: Context) : super(context) { initialize() }
|
constructor(context: Context) : super(context) { initialize() }
|
||||||
@ -96,16 +96,7 @@ class VisibleMessageContentView : LinearLayout {
|
|||||||
isStart = isStartOfMessageCluster,
|
isStart = isStartOfMessageCluster,
|
||||||
isEnd = isEndOfMessageCluster
|
isEnd = isEndOfMessageCluster
|
||||||
)
|
)
|
||||||
onContentClick = {
|
onContentClick = { albumThumbnailView.calculateHitObject(it, message) }
|
||||||
when (val hitObject = albumThumbnailView.calculateHitObject(it)) {
|
|
||||||
is AlbumThumbnailView.Hit.SlideHit -> Log.d("Loki-UI", "clicked display slide ${hitObject.slide}")// open the slide preview
|
|
||||||
is AlbumThumbnailView.Hit.DownloadHit -> Log.d("Loki-UI", "clicked display download")
|
|
||||||
AlbumThumbnailView.Hit.ReadMoreHit -> Log.d("Loki-UI", "clicked the read more display")
|
|
||||||
else -> {
|
|
||||||
Log.d("Loki-UI", "DIDN'T click anything important")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (message.isOpenGroupInvitation) {
|
} else if (message.isOpenGroupInvitation) {
|
||||||
val openGroupInvitationView = OpenGroupInvitationView(context)
|
val openGroupInvitationView = OpenGroupInvitationView(context)
|
||||||
openGroupInvitationView.bind(message, VisibleMessageContentView.getTextColor(context, message))
|
openGroupInvitationView.bind(message, VisibleMessageContentView.getTextColor(context, message))
|
||||||
|
@ -50,7 +50,7 @@ class VisibleMessageView : LinearLayout {
|
|||||||
private var onDownTimestamp = 0L
|
private var onDownTimestamp = 0L
|
||||||
var snIsSelected = false
|
var snIsSelected = false
|
||||||
set(value) { field = value; handleIsSelectedChanged()}
|
set(value) { field = value; handleIsSelectedChanged()}
|
||||||
var onPress: ((x: Int, y: Int) -> Unit)? = null
|
var onPress: ((rawX: Int, rawY: Int) -> Unit)? = null
|
||||||
var onSwipeToReply: (() -> Unit)? = null
|
var onSwipeToReply: (() -> Unit)? = null
|
||||||
var onLongPress: (() -> Unit)? = null
|
var onLongPress: (() -> Unit)? = null
|
||||||
|
|
||||||
@ -272,7 +272,7 @@ class VisibleMessageView : LinearLayout {
|
|||||||
onSwipeToReply?.invoke()
|
onSwipeToReply?.invoke()
|
||||||
} else if ((Date().time - onDownTimestamp) < VisibleMessageView.longPressDurationThreshold) {
|
} else if ((Date().time - onDownTimestamp) < VisibleMessageView.longPressDurationThreshold) {
|
||||||
longPressCallback?.let { gestureHandler.removeCallbacks(it) }
|
longPressCallback?.let { gestureHandler.removeCallbacks(it) }
|
||||||
onPress?.invoke(event.x.toInt(), event.y.toInt())
|
onPress?.invoke(event.rawX.toInt(), event.rawY.toInt())
|
||||||
}
|
}
|
||||||
resetPosition()
|
resetPosition()
|
||||||
}
|
}
|
||||||
@ -297,8 +297,8 @@ class VisibleMessageView : LinearLayout {
|
|||||||
onLongPress?.invoke()
|
onLongPress?.invoke()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onContentClick(hitRect: Rect) {
|
fun onContentClick(rawRect: Rect) {
|
||||||
messageContentView.onContentClick?.invoke(hitRect)
|
messageContentView.onContentClick?.invoke(rawRect)
|
||||||
}
|
}
|
||||||
// endregion
|
// endregion
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
package org.thoughtcrime.securesms.loki.utilities
|
package org.thoughtcrime.securesms.loki.utilities
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
@ -52,4 +56,13 @@ fun AppCompatActivity.show(intent: Intent, isForResult: Boolean = false) {
|
|||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
overridePendingTransition(R.anim.slide_from_bottom, R.anim.fade_scale_out)
|
overridePendingTransition(R.anim.slide_from_bottom, R.anim.fade_scale_out)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ActivityDispatcher {
|
||||||
|
companion object {
|
||||||
|
const val SERVICE = "ActivityDispatcher_SERVICE"
|
||||||
|
@SuppressLint("WrongConstant")
|
||||||
|
fun get(context: Context) = context.getSystemService(SERVICE) as? ActivityDispatcher
|
||||||
|
}
|
||||||
|
fun dispatchIntent(body: (Context)->Intent)
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user