parent
922ca6b874
commit
df3a1ab26f
|
|
@ -184,7 +184,8 @@ fun Message(
|
||||||
onReply: () -> Unit = {},
|
onReply: () -> Unit = {},
|
||||||
onAddReaction: () -> Unit = {},
|
onAddReaction: () -> Unit = {},
|
||||||
fromWebhook: Boolean = false,
|
fromWebhook: Boolean = false,
|
||||||
webhookName: String? = null
|
webhookName: String? = null,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val author = RevoltAPI.userCache[message.author] ?: return CircularProgressIndicator()
|
val author = RevoltAPI.userCache[message.author] ?: return CircularProgressIndicator()
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
@ -200,7 +201,7 @@ fun Message(
|
||||||
|
|
||||||
val authorIsBlocked = remember(author) { author.relationship == "Blocked" }
|
val authorIsBlocked = remember(author) { author.relationship == "Blocked" }
|
||||||
|
|
||||||
Column(Modifier.animateContentSize()) {
|
Column(modifier.animateContentSize()) {
|
||||||
if (message.tail == false) {
|
if (message.tail == false) {
|
||||||
Spacer(modifier = Modifier.height(10.dp))
|
Spacer(modifier = Modifier.height(10.dp))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
package chat.revolt.internals.extensions
|
||||||
|
|
||||||
|
import androidx.compose.foundation.gestures.awaitEachGesture
|
||||||
|
import androidx.compose.foundation.gestures.awaitFirstDown
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.input.pointer.PointerEvent
|
||||||
|
import androidx.compose.ui.input.pointer.PointerEventPass
|
||||||
|
import androidx.compose.ui.input.pointer.PointerInputChange
|
||||||
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
|
|
||||||
|
fun Modifier.supportSwipeReply(
|
||||||
|
pass: PointerEventPass = PointerEventPass.Main,
|
||||||
|
onDown: (pointer: PointerInputChange) -> Unit,
|
||||||
|
onMove: (changes: List<PointerInputChange>) -> Unit,
|
||||||
|
onUp: () -> Unit,
|
||||||
|
) = this.then(
|
||||||
|
Modifier.pointerInput(pass) {
|
||||||
|
awaitEachGesture {
|
||||||
|
val down = awaitFirstDown(pass = pass, requireUnconsumed = false)
|
||||||
|
onDown(down)
|
||||||
|
do {
|
||||||
|
val event: PointerEvent = awaitPointerEvent(
|
||||||
|
pass = pass
|
||||||
|
)
|
||||||
|
|
||||||
|
onMove(event.changes)
|
||||||
|
|
||||||
|
} while (event.changes.any { it.pressed })
|
||||||
|
onUp()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
@ -804,8 +804,10 @@ fun ChatRouterScreen(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
var useSidebarGesture by remember { mutableStateOf(true) }
|
||||||
DismissibleNavigationDrawer(
|
DismissibleNavigationDrawer(
|
||||||
drawerState = drawerState,
|
drawerState = drawerState,
|
||||||
|
gesturesEnabled = useSidebarGesture,
|
||||||
drawerContent = {
|
drawerContent = {
|
||||||
DismissibleDrawerSheet(
|
DismissibleDrawerSheet(
|
||||||
drawerContainerColor = Color.Transparent,
|
drawerContainerColor = Color.Transparent,
|
||||||
|
|
@ -842,7 +844,11 @@ fun ChatRouterScreen(
|
||||||
toggleDrawer = {
|
toggleDrawer = {
|
||||||
toggleDrawerLambda()
|
toggleDrawerLambda()
|
||||||
},
|
},
|
||||||
drawerState = drawerState
|
drawerState = drawerState,
|
||||||
|
drawerGestureEnabled = useSidebarGesture,
|
||||||
|
setDrawerGestureEnabled = {
|
||||||
|
useSidebarGesture = it
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -884,7 +890,9 @@ fun ChannelNavigator(
|
||||||
topNav: NavController,
|
topNav: NavController,
|
||||||
useDrawer: Boolean,
|
useDrawer: Boolean,
|
||||||
toggleDrawer: () -> Unit,
|
toggleDrawer: () -> Unit,
|
||||||
drawerState: DrawerState? = null
|
drawerState: DrawerState? = null,
|
||||||
|
drawerGestureEnabled: Boolean = true,
|
||||||
|
setDrawerGestureEnabled: (Boolean) -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
|
@ -922,7 +930,10 @@ fun ChannelNavigator(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
useDrawer = useDrawer
|
useDrawer = useDrawer,
|
||||||
|
drawerGestureEnabled = drawerGestureEnabled,
|
||||||
|
setDrawerGestureEnabled = setDrawerGestureEnabled,
|
||||||
|
drawerState = drawerState,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package chat.revolt.screens.chat.views.channel
|
package chat.revolt.screens.chat.views.channel
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.ContentValues
|
import android.content.ContentValues
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
|
|
@ -17,6 +18,7 @@ import androidx.compose.animation.AnimatedContent
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.Crossfade
|
import androidx.compose.animation.Crossfade
|
||||||
import androidx.compose.animation.core.animateDpAsState
|
import androidx.compose.animation.core.animateDpAsState
|
||||||
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.animation.core.animateIntAsState
|
import androidx.compose.animation.core.animateIntAsState
|
||||||
import androidx.compose.animation.fadeIn
|
import androidx.compose.animation.fadeIn
|
||||||
import androidx.compose.animation.fadeOut
|
import androidx.compose.animation.fadeOut
|
||||||
|
|
@ -27,12 +29,14 @@ import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
|
|
@ -42,6 +46,7 @@ import androidx.compose.foundation.layout.imeAnimationTarget
|
||||||
import androidx.compose.foundation.layout.imePadding
|
import androidx.compose.foundation.layout.imePadding
|
||||||
import androidx.compose.foundation.layout.navigationBars
|
import androidx.compose.foundation.layout.navigationBars
|
||||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||||
|
import androidx.compose.foundation.layout.offset
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.requiredHeight
|
import androidx.compose.foundation.layout.requiredHeight
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
|
|
@ -60,6 +65,7 @@ import androidx.compose.material3.AssistChip
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.material3.DrawerState
|
||||||
import androidx.compose.material3.DropdownMenu
|
import androidx.compose.material3.DropdownMenu
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
|
@ -81,6 +87,7 @@ import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
|
@ -90,8 +97,12 @@ import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
|
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||||
|
import androidx.compose.ui.input.pointer.PointerInputChange
|
||||||
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.Placeholder
|
import androidx.compose.ui.text.Placeholder
|
||||||
|
|
@ -120,6 +131,8 @@ import chat.revolt.api.routes.channel.react
|
||||||
import chat.revolt.api.routes.microservices.autumn.FileArgs
|
import chat.revolt.api.routes.microservices.autumn.FileArgs
|
||||||
import chat.revolt.api.schemas.ChannelType
|
import chat.revolt.api.schemas.ChannelType
|
||||||
import chat.revolt.api.schemas.Message
|
import chat.revolt.api.schemas.Message
|
||||||
|
import chat.revolt.api.settings.LoadedSettings
|
||||||
|
import chat.revolt.api.settings.MessageReplyStyle
|
||||||
import chat.revolt.callbacks.Action
|
import chat.revolt.callbacks.Action
|
||||||
import chat.revolt.callbacks.ActionChannel
|
import chat.revolt.callbacks.ActionChannel
|
||||||
import chat.revolt.components.chat.DateDivider
|
import chat.revolt.components.chat.DateDivider
|
||||||
|
|
@ -140,6 +153,7 @@ import chat.revolt.components.screens.chat.TypingIndicator
|
||||||
import chat.revolt.components.skeletons.MessageSkeleton
|
import chat.revolt.components.skeletons.MessageSkeleton
|
||||||
import chat.revolt.components.skeletons.MessageSkeletonVariant
|
import chat.revolt.components.skeletons.MessageSkeletonVariant
|
||||||
import chat.revolt.internals.extensions.rememberChannelPermissions
|
import chat.revolt.internals.extensions.rememberChannelPermissions
|
||||||
|
import chat.revolt.internals.extensions.supportSwipeReply
|
||||||
import chat.revolt.internals.extensions.zero
|
import chat.revolt.internals.extensions.zero
|
||||||
import chat.revolt.sheets.ChannelInfoSheet
|
import chat.revolt.sheets.ChannelInfoSheet
|
||||||
import chat.revolt.sheets.MessageContextSheet
|
import chat.revolt.sheets.MessageContextSheet
|
||||||
|
|
@ -151,6 +165,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.datetime.Instant
|
import kotlinx.datetime.Instant
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import kotlin.math.abs
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
sealed class ChannelScreenItem {
|
sealed class ChannelScreenItem {
|
||||||
|
|
@ -182,6 +197,7 @@ private fun pxAsDp(px: Int): Dp {
|
||||||
|
|
||||||
private const val NOT_ENOUGH_SPACE_FOR_PANES_THRESHOLD = 500
|
private const val NOT_ENOUGH_SPACE_FOR_PANES_THRESHOLD = 500
|
||||||
|
|
||||||
|
@SuppressLint("UnusedBoxWithConstraintsScope")
|
||||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
|
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun ChannelScreen(
|
fun ChannelScreen(
|
||||||
|
|
@ -189,6 +205,9 @@ fun ChannelScreen(
|
||||||
onToggleDrawer: () -> Unit,
|
onToggleDrawer: () -> Unit,
|
||||||
useDrawer: Boolean,
|
useDrawer: Boolean,
|
||||||
useBackButton: Boolean = false,
|
useBackButton: Boolean = false,
|
||||||
|
drawerGestureEnabled: Boolean = true,
|
||||||
|
setDrawerGestureEnabled: (Boolean) -> Unit = {},
|
||||||
|
drawerState: DrawerState? = null,
|
||||||
backButtonAction: (() -> Unit)? = null,
|
backButtonAction: (() -> Unit)? = null,
|
||||||
useChatUI: Boolean = false,
|
useChatUI: Boolean = false,
|
||||||
viewModel: ChannelScreenViewModel = hiltViewModel()
|
viewModel: ChannelScreenViewModel = hiltViewModel()
|
||||||
|
|
@ -196,6 +215,8 @@ fun ChannelScreen(
|
||||||
// <editor-fold desc="State and effects">
|
// <editor-fold desc="State and effects">
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
val haptic = LocalHapticFeedback.current
|
||||||
|
val config = LocalConfiguration.current
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
viewModel.listenToWsEvents()
|
viewModel.listenToWsEvents()
|
||||||
|
|
@ -381,6 +402,7 @@ fun ChannelScreen(
|
||||||
// </editor-fold>
|
// </editor-fold>
|
||||||
// <editor-fold desc="UI elements">
|
// <editor-fold desc="UI elements">
|
||||||
val lazyListState = rememberLazyListState()
|
val lazyListState = rememberLazyListState()
|
||||||
|
var disableScroll by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
val isScrolledToBottom = remember(lazyListState) {
|
val isScrolledToBottom = remember(lazyListState) {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
|
|
@ -654,6 +676,7 @@ fun ChannelScreen(
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
state = lazyListState,
|
state = lazyListState,
|
||||||
|
userScrollEnabled = !disableScroll,
|
||||||
reverseLayout = true,
|
reverseLayout = true,
|
||||||
contentPadding = PaddingValues(top = 16.dp, bottom = 32.dp)
|
contentPadding = PaddingValues(top = 16.dp, bottom = 32.dp)
|
||||||
) {
|
) {
|
||||||
|
|
@ -693,53 +716,189 @@ fun ChannelScreen(
|
||||||
) { index ->
|
) { index ->
|
||||||
when (val item = viewModel.items[index]) {
|
when (val item = viewModel.items[index]) {
|
||||||
is ChannelScreenItem.RegularMessage -> {
|
is ChannelScreenItem.RegularMessage -> {
|
||||||
Message(
|
var offsetX by remember { mutableFloatStateOf(0f) }
|
||||||
message = item.message,
|
val animOffsetX by animateFloatAsState(
|
||||||
onMessageContextMenu = {
|
when {
|
||||||
item.message.id?.let { messageId ->
|
offsetX > -20f -> 0f
|
||||||
messageContextSheetTarget = messageId
|
else -> offsetX
|
||||||
messageContextSheetShown = true
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
onAvatarClick = {
|
label = "X offset of message for replies"
|
||||||
if (item.message.webhook != null) {
|
)
|
||||||
scope.launch {
|
var markGestureInvalid by remember { mutableStateOf(false) }
|
||||||
ActionChannel.send(Action.OpenWebhookSheet)
|
var hapticFeedbackPerformed by remember {
|
||||||
|
mutableStateOf(
|
||||||
|
false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
var onMoveHandler: (List<PointerInputChange>) -> Unit =
|
||||||
|
{ changeList: List<PointerInputChange> ->
|
||||||
|
changeList
|
||||||
|
.firstOrNull()
|
||||||
|
?.let {
|
||||||
|
val deltaX =
|
||||||
|
it.position.x - it.previousPosition.x
|
||||||
|
val deltaY =
|
||||||
|
it.position.y - it.previousPosition.y
|
||||||
|
|
||||||
|
val couldBeTopDownScroll =
|
||||||
|
deltaX > -30f
|
||||||
|
&& abs(deltaY) > 30f
|
||||||
|
// too far in to consider it an accident
|
||||||
|
&& offsetX >= -100f
|
||||||
|
if (couldBeTopDownScroll) {
|
||||||
|
offsetX = 0f
|
||||||
|
markGestureInvalid = true
|
||||||
|
return@let
|
||||||
|
}
|
||||||
|
|
||||||
|
val goesTowardsLeft =
|
||||||
|
it.position.x < it.previousPosition.x
|
||||||
|
if (goesTowardsLeft || offsetX <= -20f) {
|
||||||
|
if (markGestureInvalid) {
|
||||||
|
return@let
|
||||||
|
}
|
||||||
|
offsetX += deltaX
|
||||||
|
setDrawerGestureEnabled(
|
||||||
|
false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (goesTowardsLeft && offsetX <= -30f) {
|
||||||
|
disableScroll = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
goesTowardsLeft
|
||||||
|
&& offsetX <= -300f
|
||||||
|
&& !hapticFeedbackPerformed
|
||||||
|
) {
|
||||||
|
hapticFeedbackPerformed = true
|
||||||
|
haptic.performHapticFeedback(
|
||||||
|
HapticFeedbackType.GestureThresholdActivate
|
||||||
|
)
|
||||||
|
} else if (
|
||||||
|
hapticFeedbackPerformed
|
||||||
|
&& offsetX >= -100f
|
||||||
|
) {
|
||||||
|
hapticFeedbackPerformed = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
item.message.author?.let { author ->
|
|
||||||
|
Box {
|
||||||
|
Message(
|
||||||
|
message = item.message,
|
||||||
|
onMessageContextMenu = {
|
||||||
|
item.message.id?.let { messageId ->
|
||||||
|
messageContextSheetTarget = messageId
|
||||||
|
messageContextSheetShown = true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onAvatarClick = {
|
||||||
|
if (item.message.webhook != null) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
ActionChannel.send(
|
ActionChannel.send(Action.OpenWebhookSheet)
|
||||||
Action.OpenUserSheet(
|
}
|
||||||
author,
|
} else {
|
||||||
viewModel.channel?.server
|
item.message.author?.let { author ->
|
||||||
|
scope.launch {
|
||||||
|
ActionChannel.send(
|
||||||
|
Action.OpenUserSheet(
|
||||||
|
author,
|
||||||
|
viewModel.channel?.server
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onNameClick = {
|
||||||
|
val author =
|
||||||
|
item.message.author?.let { RevoltAPI.userCache[it] }
|
||||||
|
?: return@Message
|
||||||
|
viewModel.putAtCursorPosition("@${author.username}#${author.discriminator}")
|
||||||
|
},
|
||||||
|
canReply = true,
|
||||||
|
onReply = {
|
||||||
|
item.message.id?.let { messageId ->
|
||||||
|
scope.launch {
|
||||||
|
viewModel.addReplyTo(
|
||||||
|
messageId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
onAddReaction = {
|
||||||
|
item.message.id?.let { messageId ->
|
||||||
|
reactSheetTarget = messageId
|
||||||
|
reactSheetShown = true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fromWebhook = item.message.webhook != null,
|
||||||
|
webhookName = item.message.webhook?.name,
|
||||||
|
modifier = Modifier
|
||||||
|
.offset(
|
||||||
|
x = with(LocalDensity.current) { animOffsetX.toDp() }
|
||||||
|
)
|
||||||
|
.then(
|
||||||
|
if (LoadedSettings.messageReplyStyle == MessageReplyStyle.SwipeFromEnd)
|
||||||
|
Modifier.supportSwipeReply(
|
||||||
|
onDown = {},
|
||||||
|
onMove = onMoveHandler,
|
||||||
|
onUp = {
|
||||||
|
if (offsetX <= -300f) {
|
||||||
|
scope.launch {
|
||||||
|
item.message.id?.let {
|
||||||
|
viewModel.addReplyTo(
|
||||||
|
it
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setDrawerGestureEnabled(true)
|
||||||
|
markGestureInvalid = false
|
||||||
|
disableScroll = false
|
||||||
|
hapticFeedbackPerformed = false
|
||||||
|
offsetX = 0f
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else Modifier
|
||||||
|
)
|
||||||
|
)
|
||||||
|
BoxWithConstraints(Modifier.fillMaxHeight()) {
|
||||||
|
Row(
|
||||||
|
Modifier
|
||||||
|
.fillMaxHeight()
|
||||||
|
.offset(
|
||||||
|
x = with(LocalDensity.current) {
|
||||||
|
maxWidth - abs(
|
||||||
|
animOffsetX
|
||||||
|
).toDp()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.background(
|
||||||
|
MaterialTheme.colorScheme.primary.copy(
|
||||||
|
alpha = 0.1f
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(
|
||||||
|
8.dp,
|
||||||
|
Alignment.Start
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
when {
|
||||||
|
offsetX <= -300f -> "stop"
|
||||||
|
else -> "keep"
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
onNameClick = {
|
}
|
||||||
val author =
|
|
||||||
item.message.author?.let { RevoltAPI.userCache[it] }
|
|
||||||
?: return@Message
|
|
||||||
viewModel.putAtCursorPosition("@${author.username}#${author.discriminator}")
|
|
||||||
},
|
|
||||||
canReply = true,
|
|
||||||
onReply = {
|
|
||||||
item.message.id?.let { messageId ->
|
|
||||||
scope.launch { viewModel.addReplyTo(messageId) }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onAddReaction = {
|
|
||||||
item.message.id?.let { messageId ->
|
|
||||||
reactSheetTarget = messageId
|
|
||||||
reactSheetShown = true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fromWebhook = item.message.webhook != null,
|
|
||||||
webhookName = item.message.webhook?.name
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is ChannelScreenItem.ProspectiveMessage -> {
|
is ChannelScreenItem.ProspectiveMessage -> {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue