mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2025-06-28 20:29:53 +00:00
android, desktop: go to forwarded item or search result (#5666)
* android, desktop: go to forwarded item or search result * changes * reactions back * button appearance * indentation * change * rename variable * rename function * rename variable * rename variable * fix scroll position
This commit is contained in:
parent
1b757911fa
commit
50232fd179
7 changed files with 591 additions and 448 deletions
|
@ -65,6 +65,7 @@ object ChatModel {
|
||||||
|
|
||||||
// current chat
|
// current chat
|
||||||
val chatId = mutableStateOf<String?>(null)
|
val chatId = mutableStateOf<String?>(null)
|
||||||
|
val openAroundItemId: MutableState<Long?> = mutableStateOf(null)
|
||||||
val chatsContext = ChatsContext(null)
|
val chatsContext = ChatsContext(null)
|
||||||
val reportsChatsContext = ChatsContext(MsgContentTag.Report)
|
val reportsChatsContext = ChatsContext(MsgContentTag.Report)
|
||||||
// declaration of chatsContext should be before any other variable that is taken from ChatsContext class and used in the model, otherwise, strange crash with NullPointerException for "this" parameter in random functions
|
// declaration of chatsContext should be before any other variable that is taken from ChatsContext class and used in the model, otherwise, strange crash with NullPointerException for "this" parameter in random functions
|
||||||
|
@ -3111,6 +3112,13 @@ sealed class CIForwardedFrom {
|
||||||
is Group -> chatName
|
is Group -> chatName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val chatTypeApiIdMsgId: Triple<ChatType, Long, Long?>?
|
||||||
|
get() = when (this) {
|
||||||
|
Unknown -> null
|
||||||
|
is Contact -> if (contactId != null) Triple(ChatType.Direct, contactId, chatItemId) else null
|
||||||
|
is Group -> if (groupId != null) Triple(ChatType.Group, groupId, chatItemId) else null
|
||||||
|
}
|
||||||
|
|
||||||
fun text(chatType: ChatType): String =
|
fun text(chatType: ChatType): String =
|
||||||
if (chatType == ChatType.Local) {
|
if (chatType == ChatType.Local) {
|
||||||
if (chatName.isEmpty()) {
|
if (chatName.isEmpty()) {
|
||||||
|
|
|
@ -1398,7 +1398,8 @@ private suspend fun afterSetChatTTL(rhId: Long?, chatInfo: ChatInfo, progressInd
|
||||||
chat,
|
chat,
|
||||||
navInfo,
|
navInfo,
|
||||||
contentTag = null,
|
contentTag = null,
|
||||||
pagination = pagination
|
pagination = pagination,
|
||||||
|
openAroundItemId = null
|
||||||
)
|
)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "apiGetChat error: ${e.stackTraceToString()}")
|
Log.e(TAG, "apiGetChat error: ${e.stackTraceToString()}")
|
||||||
|
|
|
@ -28,13 +28,15 @@ suspend fun apiLoadMessages(
|
||||||
contentTag: MsgContentTag?,
|
contentTag: MsgContentTag?,
|
||||||
pagination: ChatPagination,
|
pagination: ChatPagination,
|
||||||
search: String = "",
|
search: String = "",
|
||||||
|
openAroundItemId: Long? = null,
|
||||||
visibleItemIndexesNonReversed: () -> IntRange = { 0 .. 0 }
|
visibleItemIndexesNonReversed: () -> IntRange = { 0 .. 0 }
|
||||||
) = coroutineScope {
|
) = coroutineScope {
|
||||||
val (chat, navInfo) = chatModel.controller.apiGetChat(rhId, chatType, apiId, contentTag, pagination, search) ?: return@coroutineScope
|
val (chat, navInfo) = chatModel.controller.apiGetChat(rhId, chatType, apiId, contentTag, pagination, search) ?: return@coroutineScope
|
||||||
// For .initial allow the chatItems to be empty as well as chatModel.chatId to not match this chat because these values become set after .initial finishes
|
// For .initial allow the chatItems to be empty as well as chatModel.chatId to not match this chat because these values become set after .initial finishes
|
||||||
if (((chatModel.chatId.value != chat.id || chat.chatItems.isEmpty()) && pagination !is ChatPagination.Initial && pagination !is ChatPagination.Last)
|
/** When [openAroundItemId] is provided, chatId can be different too */
|
||||||
|
if (((chatModel.chatId.value != chat.id || chat.chatItems.isEmpty()) && pagination !is ChatPagination.Initial && pagination !is ChatPagination.Last && openAroundItemId == null)
|
||||||
|| !isActive) return@coroutineScope
|
|| !isActive) return@coroutineScope
|
||||||
processLoadedChat(chat, navInfo, contentTag, pagination, visibleItemIndexesNonReversed)
|
processLoadedChat(chat, navInfo, contentTag, pagination, openAroundItemId, visibleItemIndexesNonReversed)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun processLoadedChat(
|
suspend fun processLoadedChat(
|
||||||
|
@ -42,6 +44,7 @@ suspend fun processLoadedChat(
|
||||||
navInfo: NavigationInfo,
|
navInfo: NavigationInfo,
|
||||||
contentTag: MsgContentTag?,
|
contentTag: MsgContentTag?,
|
||||||
pagination: ChatPagination,
|
pagination: ChatPagination,
|
||||||
|
openAroundItemId: Long?,
|
||||||
visibleItemIndexesNonReversed: () -> IntRange = { 0 .. 0 }
|
visibleItemIndexesNonReversed: () -> IntRange = { 0 .. 0 }
|
||||||
) {
|
) {
|
||||||
val chatState = chatModel.chatStateForContent(contentTag)
|
val chatState = chatModel.chatStateForContent(contentTag)
|
||||||
|
@ -67,7 +70,7 @@ suspend fun processLoadedChat(
|
||||||
withChats(contentTag) {
|
withChats(contentTag) {
|
||||||
chatItemStatuses.clear()
|
chatItemStatuses.clear()
|
||||||
chatItems.replaceAll(chat.chatItems)
|
chatItems.replaceAll(chat.chatItems)
|
||||||
chatModel.chatId.value = chat.chatInfo.id
|
chatModel.chatId.value = chat.id
|
||||||
splits.value = newSplits
|
splits.value = newSplits
|
||||||
if (chat.chatItems.isNotEmpty()) {
|
if (chat.chatItems.isNotEmpty()) {
|
||||||
unreadAfterItemId.value = chat.chatItems.last().id
|
unreadAfterItemId.value = chat.chatItems.last().id
|
||||||
|
@ -119,10 +122,15 @@ suspend fun processLoadedChat(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is ChatPagination.Around -> {
|
is ChatPagination.Around -> {
|
||||||
newItems.addAll(oldItems)
|
val newSplits = if (openAroundItemId == null) {
|
||||||
val newSplits = removeDuplicatesAndUpperSplits(newItems, chat, splits, visibleItemIndexesNonReversed)
|
newItems.addAll(oldItems)
|
||||||
|
removeDuplicatesAndUpperSplits(newItems, chat, splits, visibleItemIndexesNonReversed)
|
||||||
|
} else {
|
||||||
|
emptyList()
|
||||||
|
}
|
||||||
// currently, items will always be added on top, which is index 0
|
// currently, items will always be added on top, which is index 0
|
||||||
newItems.addAll(0, chat.chatItems)
|
newItems.addAll(0, chat.chatItems)
|
||||||
|
|
||||||
withChats(contentTag) {
|
withChats(contentTag) {
|
||||||
chatItems.replaceAll(newItems)
|
chatItems.replaceAll(newItems)
|
||||||
splits.value = listOf(chat.chatItems.last().id) + newSplits
|
splits.value = listOf(chat.chatItems.last().id) + newSplits
|
||||||
|
@ -130,8 +138,15 @@ suspend fun processLoadedChat(
|
||||||
totalAfter.value = navInfo.afterTotal
|
totalAfter.value = navInfo.afterTotal
|
||||||
unreadTotal.value = chat.chatStats.unreadCount
|
unreadTotal.value = chat.chatStats.unreadCount
|
||||||
unreadAfter.value = navInfo.afterUnread
|
unreadAfter.value = navInfo.afterUnread
|
||||||
// no need to set it, count will be wrong
|
|
||||||
// unreadAfterNewestLoaded.value = navInfo.afterUnread
|
if (openAroundItemId != null) {
|
||||||
|
unreadAfterNewestLoaded.value = navInfo.afterUnread
|
||||||
|
chatModel.openAroundItemId.value = openAroundItemId
|
||||||
|
chatModel.chatId.value = chat.id
|
||||||
|
} else {
|
||||||
|
// no need to set it, count will be wrong
|
||||||
|
// unreadAfterNewestLoaded.value = navInfo.afterUnread
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is ChatPagination.Last -> {
|
is ChatPagination.Last -> {
|
||||||
|
|
|
@ -133,9 +133,12 @@ fun ChatView(
|
||||||
|
|
||||||
SimpleXThemeOverride(overrides ?: CurrentColors.collectAsState().value) {
|
SimpleXThemeOverride(overrides ?: CurrentColors.collectAsState().value) {
|
||||||
val onSearchValueChanged: (String) -> Unit = onSearchValueChanged@{ value ->
|
val onSearchValueChanged: (String) -> Unit = onSearchValueChanged@{ value ->
|
||||||
if (searchText.value == value) return@onSearchValueChanged
|
val sameText = searchText.value == value
|
||||||
val c = chatModel.getChat(chatInfo.id) ?: return@onSearchValueChanged
|
// showSearch can be false with empty text when it was closed manually after clicking on message from search to load .around it
|
||||||
if (chatModel.chatId.value != chatInfo.id) return@onSearchValueChanged
|
// (required on Android to have this check to prevent call to search with old text)
|
||||||
|
val emptyAndClosedSearch = searchText.value.isEmpty() && !showSearch.value && contentTag == null
|
||||||
|
val c = chatModel.getChat(chatInfo.id)
|
||||||
|
if (sameText || emptyAndClosedSearch || c == null || chatModel.chatId.value != chatInfo.id) return@onSearchValueChanged
|
||||||
withBGApi {
|
withBGApi {
|
||||||
apiFindMessages(c, value, contentTag)
|
apiFindMessages(c, value, contentTag)
|
||||||
searchText.value = value
|
searchText.value = value
|
||||||
|
@ -344,7 +347,7 @@ fun ChatView(
|
||||||
val c = chatModel.getChat(chatId)
|
val c = chatModel.getChat(chatId)
|
||||||
if (chatModel.chatId.value != chatId) return@ChatLayout
|
if (chatModel.chatId.value != chatId) return@ChatLayout
|
||||||
if (c != null) {
|
if (c != null) {
|
||||||
apiLoadMessages(c.remoteHostId, c.chatInfo.chatType, c.chatInfo.apiId, contentTag, pagination, searchText.value, visibleItemIndexes)
|
apiLoadMessages(c.remoteHostId, c.chatInfo.chatType, c.chatInfo.apiId, contentTag, pagination, searchText.value, null, visibleItemIndexes)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
deleteMessage = { itemId, mode ->
|
deleteMessage = { itemId, mode ->
|
||||||
|
@ -602,6 +605,10 @@ fun ChatView(
|
||||||
},
|
},
|
||||||
changeNtfsState = { enabled, currentValue -> toggleNotifications(chatRh, chatInfo, enabled, chatModel, currentValue) },
|
changeNtfsState = { enabled, currentValue -> toggleNotifications(chatRh, chatInfo, enabled, chatModel, currentValue) },
|
||||||
onSearchValueChanged = onSearchValueChanged,
|
onSearchValueChanged = onSearchValueChanged,
|
||||||
|
closeSearch = {
|
||||||
|
showSearch.value = false
|
||||||
|
searchText.value = ""
|
||||||
|
},
|
||||||
onComposed,
|
onComposed,
|
||||||
developerTools = chatModel.controller.appPrefs.developerTools.get(),
|
developerTools = chatModel.controller.appPrefs.developerTools.get(),
|
||||||
showViaProxy = chatModel.controller.appPrefs.showSentViaProxy.get(),
|
showViaProxy = chatModel.controller.appPrefs.showSentViaProxy.get(),
|
||||||
|
@ -699,6 +706,7 @@ fun ChatLayout(
|
||||||
markChatRead: () -> Unit,
|
markChatRead: () -> Unit,
|
||||||
changeNtfsState: (MsgFilter, currentValue: MutableState<MsgFilter>) -> Unit,
|
changeNtfsState: (MsgFilter, currentValue: MutableState<MsgFilter>) -> Unit,
|
||||||
onSearchValueChanged: (String) -> Unit,
|
onSearchValueChanged: (String) -> Unit,
|
||||||
|
closeSearch: () -> Unit,
|
||||||
onComposed: suspend (chatId: String) -> Unit,
|
onComposed: suspend (chatId: String) -> Unit,
|
||||||
developerTools: Boolean,
|
developerTools: Boolean,
|
||||||
showViaProxy: Boolean,
|
showViaProxy: Boolean,
|
||||||
|
@ -751,7 +759,7 @@ fun ChatLayout(
|
||||||
useLinkPreviews, linkMode, scrollToItemId, selectedChatItems, showMemberInfo, showChatInfo = info, loadMessages, deleteMessage, deleteMessages, archiveReports,
|
useLinkPreviews, linkMode, scrollToItemId, selectedChatItems, showMemberInfo, showChatInfo = info, loadMessages, deleteMessage, deleteMessages, archiveReports,
|
||||||
receiveFile, cancelFile, joinGroup, acceptCall, acceptFeature, openDirectChat, forwardItem,
|
receiveFile, cancelFile, joinGroup, acceptCall, acceptFeature, openDirectChat, forwardItem,
|
||||||
updateContactStats, updateMemberStats, syncContactConnection, syncMemberConnection, findModelChat, findModelMember,
|
updateContactStats, updateMemberStats, syncContactConnection, syncMemberConnection, findModelChat, findModelMember,
|
||||||
setReaction, showItemDetails, markItemsRead, markChatRead, remember { { onComposed(it) } }, developerTools, showViaProxy,
|
setReaction, showItemDetails, markItemsRead, markChatRead, closeSearch, remember { { onComposed(it) } }, developerTools, showViaProxy,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (chatInfo is ChatInfo.Group && composeState.value.message.text.isNotEmpty()) {
|
if (chatInfo is ChatInfo.Group && composeState.value.message.text.isNotEmpty()) {
|
||||||
|
@ -1160,11 +1168,13 @@ fun BoxScope.ChatItemsList(
|
||||||
showItemDetails: (ChatInfo, ChatItem) -> Unit,
|
showItemDetails: (ChatInfo, ChatItem) -> Unit,
|
||||||
markItemsRead: (List<Long>) -> Unit,
|
markItemsRead: (List<Long>) -> Unit,
|
||||||
markChatRead: () -> Unit,
|
markChatRead: () -> Unit,
|
||||||
|
closeSearch: () -> Unit,
|
||||||
onComposed: suspend (chatId: String) -> Unit,
|
onComposed: suspend (chatId: String) -> Unit,
|
||||||
developerTools: Boolean,
|
developerTools: Boolean,
|
||||||
showViaProxy: Boolean
|
showViaProxy: Boolean
|
||||||
) {
|
) {
|
||||||
val searchValueIsEmpty = remember { derivedStateOf { searchValue.value.isEmpty() } }
|
val searchValueIsEmpty = remember { derivedStateOf { searchValue.value.isEmpty() } }
|
||||||
|
val searchValueIsNotBlank = remember { derivedStateOf { searchValue.value.isNotBlank() } }
|
||||||
val revealedItems = rememberSaveable(stateSaver = serializableSaver()) { mutableStateOf(setOf<Long>()) }
|
val revealedItems = rememberSaveable(stateSaver = serializableSaver()) { mutableStateOf(setOf<Long>()) }
|
||||||
val contentTag = LocalContentTag.current
|
val contentTag = LocalContentTag.current
|
||||||
// not using reversedChatItems inside to prevent possible derivedState bug in Compose when one derived state access can cause crash asking another derived state
|
// not using reversedChatItems inside to prevent possible derivedState bug in Compose when one derived state access can cause crash asking another derived state
|
||||||
|
@ -1177,15 +1187,29 @@ fun BoxScope.ChatItemsList(
|
||||||
val reportsCount = reportsCount(chatInfo.id)
|
val reportsCount = reportsCount(chatInfo.id)
|
||||||
val topPaddingToContent = topPaddingToContent(chatView = contentTag == null, contentTag == null && reportsCount > 0)
|
val topPaddingToContent = topPaddingToContent(chatView = contentTag == null, contentTag == null && reportsCount > 0)
|
||||||
val topPaddingToContentPx = rememberUpdatedState(with(LocalDensity.current) { topPaddingToContent.roundToPx() })
|
val topPaddingToContentPx = rememberUpdatedState(with(LocalDensity.current) { topPaddingToContent.roundToPx() })
|
||||||
|
val numberOfBottomAppBars = numberOfBottomAppBars()
|
||||||
/** determines height based on window info and static height of two AppBars. It's needed because in the first graphic frame height of
|
/** determines height based on window info and static height of two AppBars. It's needed because in the first graphic frame height of
|
||||||
* [composeViewHeight] is unknown, but we need to set scroll position for unread messages already so it will be correct before the first frame appears
|
* [composeViewHeight] is unknown, but we need to set scroll position for unread messages already so it will be correct before the first frame appears
|
||||||
* */
|
* */
|
||||||
val maxHeightForList = rememberUpdatedState(
|
val maxHeightForList = rememberUpdatedState(
|
||||||
with(LocalDensity.current) { LocalWindowHeight().roundToPx() - topPaddingToContentPx.value - (AppBarHeight * fontSizeSqrtMultiplier * 2).roundToPx() }
|
with(LocalDensity.current) { LocalWindowHeight().roundToPx() - topPaddingToContentPx.value - (AppBarHeight * fontSizeSqrtMultiplier * numberOfBottomAppBars).roundToPx() }
|
||||||
)
|
)
|
||||||
val listState = rememberUpdatedState(rememberSaveable(chatInfo.id, searchValueIsEmpty.value, saver = LazyListState.Saver) {
|
val resetListState = remember { mutableStateOf(false) }
|
||||||
val index = mergedItems.value.items.indexOfLast { it.hasUnread() }
|
remember(chatModel.openAroundItemId.value) {
|
||||||
|
if (chatModel.openAroundItemId.value != null) {
|
||||||
|
closeSearch()
|
||||||
|
resetListState.value = !resetListState.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val highlightedItems = remember { mutableStateOf(setOf<Long>()) }
|
||||||
|
val listState = rememberUpdatedState(rememberSaveable(chatInfo.id, searchValueIsEmpty.value, resetListState.value, saver = LazyListState.Saver) {
|
||||||
|
val openAroundItemId = chatModel.openAroundItemId.value
|
||||||
|
val index = mergedItems.value.indexInParentItems[openAroundItemId] ?: mergedItems.value.items.indexOfLast { it.hasUnread() }
|
||||||
val reportsState = reportsListState
|
val reportsState = reportsListState
|
||||||
|
if (openAroundItemId != null) {
|
||||||
|
highlightedItems.value += openAroundItemId
|
||||||
|
chatModel.openAroundItemId.value = null
|
||||||
|
}
|
||||||
if (reportsState != null) {
|
if (reportsState != null) {
|
||||||
reportsListState = null
|
reportsListState = null
|
||||||
reportsState
|
reportsState
|
||||||
|
@ -1221,7 +1245,6 @@ fun BoxScope.ChatItemsList(
|
||||||
|
|
||||||
val remoteHostIdUpdated = rememberUpdatedState(remoteHostId)
|
val remoteHostIdUpdated = rememberUpdatedState(remoteHostId)
|
||||||
val chatInfoUpdated = rememberUpdatedState(chatInfo)
|
val chatInfoUpdated = rememberUpdatedState(chatInfo)
|
||||||
val highlightedItems = remember { mutableStateOf(setOf<Long>()) }
|
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val scrollToItem: (Long) -> Unit = remember {
|
val scrollToItem: (Long) -> Unit = remember {
|
||||||
// In group reports just set the itemId to scroll to so the main ChatView will handle scrolling
|
// In group reports just set the itemId to scroll to so the main ChatView will handle scrolling
|
||||||
|
@ -1238,7 +1261,7 @@ fun BoxScope.ChatItemsList(
|
||||||
scrollToItemId.value = null }
|
scrollToItemId.value = null }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LoadLastItems(loadingMoreItems, remoteHostId, chatInfo)
|
LoadLastItems(loadingMoreItems, resetListState, remoteHostId, chatInfo)
|
||||||
SmallScrollOnNewMessage(listState, reversedChatItems)
|
SmallScrollOnNewMessage(listState, reversedChatItems)
|
||||||
val finishedInitialComposition = remember { mutableStateOf(false) }
|
val finishedInitialComposition = remember { mutableStateOf(false) }
|
||||||
NotifyChatListOnFinishingComposition(finishedInitialComposition, chatInfo, revealedItems, listState, onComposed)
|
NotifyChatListOnFinishingComposition(finishedInitialComposition, chatInfo, revealedItems, listState, onComposed)
|
||||||
|
@ -1296,7 +1319,7 @@ fun BoxScope.ChatItemsList(
|
||||||
highlightedItems.value = setOf()
|
highlightedItems.value = setOf()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ChatItemView(remoteHostId, chatInfo, cItem, composeState, provider, useLinkPreviews = useLinkPreviews, linkMode = linkMode, revealed = revealed, highlighted = highlighted, range = range, fillMaxWidth = fillMaxWidth, selectedChatItems = selectedChatItems, selectChatItem = { selectUnselectChatItem(true, cItem, revealed, selectedChatItems, reversedChatItems) }, deleteMessage = deleteMessage, deleteMessages = deleteMessages, archiveReports = archiveReports, receiveFile = receiveFile, cancelFile = cancelFile, joinGroup = joinGroup, acceptCall = acceptCall, acceptFeature = acceptFeature, openDirectChat = openDirectChat, forwardItem = forwardItem, updateContactStats = updateContactStats, updateMemberStats = updateMemberStats, syncContactConnection = syncContactConnection, syncMemberConnection = syncMemberConnection, findModelChat = findModelChat, findModelMember = findModelMember, scrollToItem = scrollToItem, scrollToQuotedItemFromItem = scrollToQuotedItemFromItem, setReaction = setReaction, showItemDetails = showItemDetails, reveal = reveal, showMemberInfo = showMemberInfo, showChatInfo = showChatInfo, developerTools = developerTools, showViaProxy = showViaProxy, itemSeparation = itemSeparation, showTimestamp = itemSeparation.timestamp)
|
ChatItemView(remoteHostId, chatInfo, cItem, composeState, provider, useLinkPreviews = useLinkPreviews, linkMode = linkMode, revealed = revealed, highlighted = highlighted, range = range, searchIsNotBlank = searchValueIsNotBlank, fillMaxWidth = fillMaxWidth, selectedChatItems = selectedChatItems, selectChatItem = { selectUnselectChatItem(true, cItem, revealed, selectedChatItems, reversedChatItems) }, deleteMessage = deleteMessage, deleteMessages = deleteMessages, archiveReports = archiveReports, receiveFile = receiveFile, cancelFile = cancelFile, joinGroup = joinGroup, acceptCall = acceptCall, acceptFeature = acceptFeature, openDirectChat = openDirectChat, forwardItem = forwardItem, updateContactStats = updateContactStats, updateMemberStats = updateMemberStats, syncContactConnection = syncContactConnection, syncMemberConnection = syncMemberConnection, findModelChat = findModelChat, findModelMember = findModelMember, scrollToItem = scrollToItem, scrollToQuotedItemFromItem = scrollToQuotedItemFromItem, setReaction = setReaction, showItemDetails = showItemDetails, reveal = reveal, showMemberInfo = showMemberInfo, showChatInfo = showChatInfo, developerTools = developerTools, showViaProxy = showViaProxy, itemSeparation = itemSeparation, showTimestamp = itemSeparation.timestamp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1567,9 +1590,9 @@ fun BoxScope.ChatItemsList(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun LoadLastItems(loadingMoreItems: MutableState<Boolean>, remoteHostId: Long?, chatInfo: ChatInfo) {
|
private fun LoadLastItems(loadingMoreItems: MutableState<Boolean>, resetListState: State<Boolean>, remoteHostId: Long?, chatInfo: ChatInfo) {
|
||||||
val contentTag = LocalContentTag.current
|
val contentTag = LocalContentTag.current
|
||||||
LaunchedEffect(remoteHostId, chatInfo.id) {
|
LaunchedEffect(remoteHostId, chatInfo.id, resetListState.value) {
|
||||||
try {
|
try {
|
||||||
loadingMoreItems.value = true
|
loadingMoreItems.value = true
|
||||||
if (chatModel.chatStateForContent(contentTag).totalAfter.value <= 0) return@LaunchedEffect
|
if (chatModel.chatStateForContent(contentTag).totalAfter.value <= 0) return@LaunchedEffect
|
||||||
|
@ -1888,6 +1911,17 @@ fun topPaddingToContent(chatView: Boolean, additionalTopBar: Boolean = false): D
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun numberOfBottomAppBars(): Int {
|
||||||
|
val oneHandUI = remember { appPrefs.oneHandUI.state }
|
||||||
|
val chatBottomBar = remember { appPrefs.chatBottomBar.state }
|
||||||
|
return if (oneHandUI.value && chatBottomBar.value) {
|
||||||
|
2
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun FloatingDate(
|
private fun FloatingDate(
|
||||||
modifier: Modifier,
|
modifier: Modifier,
|
||||||
|
@ -2798,6 +2832,7 @@ fun PreviewChatLayout() {
|
||||||
markChatRead = {},
|
markChatRead = {},
|
||||||
changeNtfsState = { _, _ -> },
|
changeNtfsState = { _, _ -> },
|
||||||
onSearchValueChanged = {},
|
onSearchValueChanged = {},
|
||||||
|
closeSearch = {},
|
||||||
onComposed = {},
|
onComposed = {},
|
||||||
developerTools = false,
|
developerTools = false,
|
||||||
showViaProxy = false,
|
showViaProxy = false,
|
||||||
|
@ -2874,6 +2909,7 @@ fun PreviewGroupChatLayout() {
|
||||||
markChatRead = {},
|
markChatRead = {},
|
||||||
changeNtfsState = { _, _ -> },
|
changeNtfsState = { _, _ -> },
|
||||||
onSearchValueChanged = {},
|
onSearchValueChanged = {},
|
||||||
|
closeSearch = {},
|
||||||
onComposed = {},
|
onComposed = {},
|
||||||
developerTools = false,
|
developerTools = false,
|
||||||
showViaProxy = false,
|
showViaProxy = false,
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -202,7 +202,7 @@ fun FramedItemView(
|
||||||
Column(
|
Column(
|
||||||
Modifier
|
Modifier
|
||||||
.width(IntrinsicSize.Max)
|
.width(IntrinsicSize.Max)
|
||||||
.padding(start = if (tailRendered) msgTailWidthDp else 0.dp, end = if (sent && tailRendered) msgTailWidthDp else 0.dp)
|
.padding(start = if (!sent && tailRendered) msgTailWidthDp else 0.dp, end = if (sent && tailRendered) msgTailWidthDp else 0.dp)
|
||||||
) {
|
) {
|
||||||
PriorityLayout(Modifier, CHAT_IMAGE_LAYOUT_ID) {
|
PriorityLayout(Modifier, CHAT_IMAGE_LAYOUT_ID) {
|
||||||
@Composable
|
@Composable
|
||||||
|
|
|
@ -210,8 +210,26 @@ suspend fun openGroupChat(rhId: Long?, groupId: Long, contentTag: MsgContentTag?
|
||||||
|
|
||||||
suspend fun openChat(rhId: Long?, chatInfo: ChatInfo, contentTag: MsgContentTag? = null) = openChat(rhId, chatInfo.chatType, chatInfo.apiId, contentTag)
|
suspend fun openChat(rhId: Long?, chatInfo: ChatInfo, contentTag: MsgContentTag? = null) = openChat(rhId, chatInfo.chatType, chatInfo.apiId, contentTag)
|
||||||
|
|
||||||
private suspend fun openChat(rhId: Long?, chatType: ChatType, apiId: Long, contentTag: MsgContentTag? = null) =
|
suspend fun openChat(
|
||||||
apiLoadMessages(rhId, chatType, apiId, contentTag, ChatPagination.Initial(ChatPagination.INITIAL_COUNT))
|
rhId: Long?,
|
||||||
|
chatType: ChatType,
|
||||||
|
apiId: Long,
|
||||||
|
contentTag: MsgContentTag? = null,
|
||||||
|
openAroundItemId: Long? = null
|
||||||
|
) =
|
||||||
|
apiLoadMessages(
|
||||||
|
rhId,
|
||||||
|
chatType,
|
||||||
|
apiId,
|
||||||
|
contentTag,
|
||||||
|
if (openAroundItemId != null) {
|
||||||
|
ChatPagination.Around(openAroundItemId, ChatPagination.INITIAL_COUNT)
|
||||||
|
} else {
|
||||||
|
ChatPagination.Initial(ChatPagination.INITIAL_COUNT)
|
||||||
|
},
|
||||||
|
"",
|
||||||
|
openAroundItemId
|
||||||
|
)
|
||||||
|
|
||||||
suspend fun openLoadedChat(chat: Chat, contentTag: MsgContentTag? = null) {
|
suspend fun openLoadedChat(chat: Chat, contentTag: MsgContentTag? = null) {
|
||||||
withChats(contentTag) {
|
withChats(contentTag) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue