mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-05-14 21:15:37 +00:00
android, desktop: thread-safe terminal items and floating terminal improvements (#4992)
* android, desktop: thread-safe terminal items and floating terminal improvements * optimization
This commit is contained in:
committed by
GitHub
parent
87fd642951
commit
193e17f7af
+13
@@ -71,6 +71,9 @@ object ChatModel {
|
||||
val groupMembers = mutableStateListOf<GroupMember>()
|
||||
val groupMembersIndexes = mutableStateMapOf<Long, Int>()
|
||||
|
||||
// false: default placement, true: floating window.
|
||||
// Used for deciding to add terminal items on main thread or not. Floating means appPrefs.terminalAlwaysVisible
|
||||
var terminalsVisible = setOf<Boolean>()
|
||||
val terminalItems = mutableStateOf<List<TerminalItem>>(listOf())
|
||||
val userAddress = mutableStateOf<UserContactLinkRec?>(null)
|
||||
val chatItemTTL = mutableStateOf<ChatItemTTL>(ChatItemTTL.None)
|
||||
@@ -772,6 +775,16 @@ object ChatModel {
|
||||
|
||||
fun addTerminalItem(item: TerminalItem) {
|
||||
val maxItems = if (appPreferences.developerTools.get()) 500 else 200
|
||||
if (terminalsVisible.isNotEmpty()) {
|
||||
withApi {
|
||||
addTerminalItem(item, maxItems)
|
||||
}
|
||||
} else {
|
||||
addTerminalItem(item, maxItems)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addTerminalItem(item: TerminalItem, maxItems: Int) {
|
||||
if (terminalItems.value.size >= maxItems) {
|
||||
terminalItems.value = terminalItems.value.subList(1, terminalItems.value.size)
|
||||
}
|
||||
|
||||
+47
-7
@@ -20,11 +20,12 @@ import chat.simplex.common.views.chat.*
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import chat.simplex.common.model.ChatModel
|
||||
import chat.simplex.common.platform.*
|
||||
import chat.simplex.res.MR
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun TerminalView(chatModel: ChatModel, close: () -> Unit) {
|
||||
fun TerminalView(floating: Boolean = false, close: () -> Unit) {
|
||||
val composeState = remember { mutableStateOf(ComposeState(useLinkPreviews = false)) }
|
||||
val close = {
|
||||
close()
|
||||
@@ -37,6 +38,7 @@ fun TerminalView(chatModel: ChatModel, close: () -> Unit) {
|
||||
})
|
||||
TerminalLayout(
|
||||
composeState,
|
||||
floating,
|
||||
sendCommand = { sendCommand(chatModel, composeState) },
|
||||
close
|
||||
)
|
||||
@@ -65,6 +67,7 @@ private fun sendCommand(chatModel: ChatModel, composeState: MutableState<Compose
|
||||
@Composable
|
||||
fun TerminalLayout(
|
||||
composeState: MutableState<ComposeState>,
|
||||
floating: Boolean,
|
||||
sendCommand: () -> Unit,
|
||||
close: () -> Unit
|
||||
) {
|
||||
@@ -118,19 +121,40 @@ fun TerminalLayout(
|
||||
color = MaterialTheme.colors.background,
|
||||
contentColor = LocalContentColor.current
|
||||
) {
|
||||
TerminalLog()
|
||||
TerminalLog(floating)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TerminalLog() {
|
||||
fun TerminalLog(floating: Boolean) {
|
||||
val reversedTerminalItems by remember {
|
||||
derivedStateOf { chatModel.terminalItems.value.asReversed() }
|
||||
}
|
||||
val clipboard = LocalClipboardManager.current
|
||||
LazyColumnWithScrollBar(reverseLayout = true) {
|
||||
val listState = LocalAppBarHandler.current?.listState ?: rememberLazyListState()
|
||||
LaunchedEffect(Unit) {
|
||||
var autoScrollToBottom = true
|
||||
launch {
|
||||
snapshotFlow { listState.layoutInfo.totalItemsCount }
|
||||
.filter { autoScrollToBottom }
|
||||
.collect {
|
||||
try {
|
||||
listState.scrollToItem(0)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, e.stackTraceToString())
|
||||
}
|
||||
}
|
||||
}
|
||||
launch {
|
||||
snapshotFlow { listState.firstVisibleItemIndex }
|
||||
.collect {
|
||||
autoScrollToBottom = listState.firstVisibleItemIndex == 0
|
||||
}
|
||||
}
|
||||
}
|
||||
LazyColumnWithScrollBar(reverseLayout = true, state = listState) {
|
||||
items(reversedTerminalItems, key = { item -> item.id to item.createdAtNanos }) { item ->
|
||||
val rhId = item.remoteHostId
|
||||
val rhIdStr = if (rhId == null) "" else "$rhId "
|
||||
@@ -142,7 +166,12 @@ fun TerminalLog() {
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
ModalManager.start.showModal(endButtons = { ShareButton { clipboard.shareText(item.details) } }) {
|
||||
val modalPlace = if (floating) {
|
||||
ModalManager.floatingTerminal
|
||||
} else {
|
||||
ModalManager.start
|
||||
}
|
||||
modalPlace.showModal(endButtons = { ShareButton { clipboard.shareText(item.details) } }) {
|
||||
SelectionContainer(modifier = Modifier.verticalScroll(rememberScrollState())) {
|
||||
val details = item.details
|
||||
.let {
|
||||
@@ -156,6 +185,16 @@ fun TerminalLog() {
|
||||
)
|
||||
}
|
||||
}
|
||||
DisposableEffect(Unit) {
|
||||
val terminals = chatModel.terminalsVisible.toMutableSet()
|
||||
terminals += floating
|
||||
chatModel.terminalsVisible = terminals
|
||||
onDispose {
|
||||
val terminals = chatModel.terminalsVisible.toMutableSet()
|
||||
terminals -= floating
|
||||
chatModel.terminalsVisible = terminals
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview/*(
|
||||
@@ -169,6 +208,7 @@ fun PreviewTerminalLayout() {
|
||||
TerminalLayout(
|
||||
composeState = remember { mutableStateOf(ComposeState(useLinkPreviews = false)) },
|
||||
sendCommand = {},
|
||||
floating = false,
|
||||
close = {}
|
||||
)
|
||||
}
|
||||
|
||||
+3
-2
@@ -2,10 +2,8 @@ package chat.simplex.common.views.helpers
|
||||
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.animation.core.*
|
||||
import androidx.compose.foundation.ScrollState
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -209,11 +207,14 @@ class ModalManager(private val placement: ModalPlacement? = null) {
|
||||
val end = if (appPlatform.isAndroid) shared else ModalManager(ModalPlacement.END)
|
||||
val fullscreen = if (appPlatform.isAndroid) shared else ModalManager(ModalPlacement.FULLSCREEN)
|
||||
|
||||
val floatingTerminal = if (appPlatform.isAndroid) shared else ModalManager(ModalPlacement.START)
|
||||
|
||||
fun closeAllModalsEverywhere() {
|
||||
start.closeModals()
|
||||
center.closeModals()
|
||||
end.closeModals()
|
||||
fullscreen.closeModals()
|
||||
floatingTerminal.closeModals()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalAnimationApi::class)
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ fun DeveloperView(
|
||||
val unchangedHints = mutableStateOf(unchangedHintPreferences())
|
||||
SectionView {
|
||||
InstallTerminalAppItem(uriHandler)
|
||||
ChatConsoleItem { withAuth(generalGetString(MR.strings.auth_open_chat_console), generalGetString(MR.strings.auth_log_in_using_credential), showCustomModal { it, close -> TerminalView(it, close) }) }
|
||||
ChatConsoleItem { withAuth(generalGetString(MR.strings.auth_open_chat_console), generalGetString(MR.strings.auth_log_in_using_credential), showCustomModal { it, close -> TerminalView(false, close) }) }
|
||||
ResetHintsItem(unchangedHints)
|
||||
SettingsPreferenceItem(painterResource(MR.images.ic_code), stringResource(MR.strings.show_developer_options), developerTools)
|
||||
SectionTextFooter(
|
||||
|
||||
@@ -199,7 +199,13 @@ private fun ApplicationScope.AppWindow(closedByError: MutableState<Boolean>) {
|
||||
768.dp)
|
||||
Window(state = cWindowState, onCloseRequest = { hiddenUntilRestart = true }, title = stringResource(MR.strings.chat_console)) {
|
||||
SimpleXTheme {
|
||||
TerminalView(ChatModel) { hiddenUntilRestart = true }
|
||||
TerminalView(true) { hiddenUntilRestart = true }
|
||||
ModalManager.floatingTerminal.showInView()
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
ModalManager.floatingTerminal.closeModals()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user