mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-06-03 17:05:08 +00:00
android: smaller new chat button in 1-hand UI mode, line on the correct side of the bar (#4569)
* android: smaller new chat button in 1-hand UI mode, line on the correct side of the bar (wrong color in 1-hand UI mode) * remove comment * desktop: open new chat information buttons on start modal * remove no longer applicable comment * desktop, android: move to chat when accepting from chat list and snsReady * android: keep search visible if keyboard is open on new chat sheet * android: keep search visibile if keyboard is open on chat list * android: scroll modal header on new chat sheet * android: added divider between search and toolbar in one hand ui * make one hand ui toolbar more extensible by using scafold * android: remove tiny paddings around one hand ui toolbars * android: hide toolbar when searching on one hand ui * avoid passing one hand ui as param everywhere * make paddings match in new chat sheet action buttons * flip animation * refactor and divider fix * fix padding * bigger padding * appPrefs --------- Co-authored-by: Diogo Cunha <diogofncunha@gmail.com> Co-authored-by: Avently <7953703+avently@users.noreply.github.com>
This commit is contained in:
+2
-1
@@ -27,6 +27,7 @@ import chat.simplex.common.views.chat.*
|
||||
import chat.simplex.common.views.chat.group.deleteGroupDialog
|
||||
import chat.simplex.common.views.chat.group.leaveGroupDialog
|
||||
import chat.simplex.common.views.chat.item.ItemAction
|
||||
import chat.simplex.common.views.contacts.onRequestAccepted
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import chat.simplex.common.views.newchat.*
|
||||
import chat.simplex.res.MR
|
||||
@@ -129,7 +130,7 @@ fun ChatListNavLinkView(chat: Chat, nextChatSelected: State<Boolean>, oneHandUI:
|
||||
ContactRequestView(chat.chatInfo)
|
||||
}
|
||||
},
|
||||
click = { contactRequestAlertDialog(chat.remoteHostId, chat.chatInfo, chatModel) },
|
||||
click = { contactRequestAlertDialog(chat.remoteHostId, chat.chatInfo, chatModel) { onRequestAccepted(it) } },
|
||||
dropdownMenuItems = {
|
||||
tryOrShowError("${chat.id}ChatListNavLinkDropdown", error = {}) {
|
||||
ContactRequestMenuItems(chat.remoteHostId, chat.chatInfo, chatModel, showMenu)
|
||||
|
||||
+14
-10
@@ -43,14 +43,12 @@ import kotlinx.serialization.json.Json
|
||||
import java.net.URI
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
private fun showNewChatSheet(oneHandUI: State<Boolean>, barTitle: String) {
|
||||
private fun showNewChatSheet(oneHandUI: State<Boolean>) {
|
||||
ModalManager.start.closeModals()
|
||||
ModalManager.end.closeModals()
|
||||
chatModel.newChatSheetVisible.value = true
|
||||
ModalManager.start.showModalCloseable(
|
||||
closeOnTop = !oneHandUI.value,
|
||||
closeBarTitle = if (oneHandUI.value) barTitle else null,
|
||||
endButtons = { Spacer(Modifier.minimumInteractiveComponentSize()) }
|
||||
) { close ->
|
||||
NewChatSheet(rh = chatModel.currentRemoteHost.value, close)
|
||||
DisposableEffect(Unit) {
|
||||
@@ -88,19 +86,21 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf
|
||||
Scaffold(
|
||||
topBar = {
|
||||
if (!oneHandUI.state.value) {
|
||||
Box(Modifier.padding(end = endPadding)) {
|
||||
Column(Modifier.padding(end = endPadding)) {
|
||||
ChatListToolbar(
|
||||
scaffoldState.drawerState,
|
||||
userPickerState,
|
||||
stopped,
|
||||
oneHandUI
|
||||
)
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
},
|
||||
bottomBar = {
|
||||
if (oneHandUI.state.value) {
|
||||
Box(Modifier.padding(end = endPadding)) {
|
||||
Column(Modifier.padding(end = endPadding)) {
|
||||
Divider()
|
||||
ChatListToolbar(
|
||||
scaffoldState.drawerState,
|
||||
userPickerState,
|
||||
@@ -125,7 +125,7 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf
|
||||
FloatingActionButton(
|
||||
onClick = {
|
||||
if (!stopped) {
|
||||
showNewChatSheet(oneHandUI.state, generalGetString(MR.strings.new_chat))
|
||||
showNewChatSheet(oneHandUI.state)
|
||||
}
|
||||
},
|
||||
Modifier
|
||||
@@ -222,14 +222,15 @@ private fun ChatListToolbar(drawerState: DrawerState, userPickerState: MutableSt
|
||||
IconButton(
|
||||
onClick = {
|
||||
if (!stopped) {
|
||||
showNewChatSheet(oneHandUI.state, generalGetString(MR.strings.new_chat))
|
||||
showNewChatSheet(oneHandUI.state)
|
||||
}
|
||||
},
|
||||
) {
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier
|
||||
.background(if (!stopped) MaterialTheme.colors.primary else MaterialTheme.colors.secondary, shape = CircleShape)
|
||||
.padding(DEFAULT_PADDING_HALF)
|
||||
.size(33.dp * fontSizeSqrtMultiplier)
|
||||
){
|
||||
Icon(
|
||||
painterResource(MR.images.ic_edit_filled),
|
||||
@@ -327,7 +328,6 @@ private fun ChatListToolbar(drawerState: DrawerState, userPickerState: MutableSt
|
||||
onSearchValueChanged = {},
|
||||
buttons = barButtons
|
||||
)
|
||||
Divider(Modifier.padding(top = AppBarHeight * fontSizeSqrtMultiplier))
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -551,6 +551,7 @@ private fun ChatList(chatModel: ChatModel, searchText: MutableState<TextFieldVal
|
||||
var scrollDirection by remember { mutableStateOf(ScrollDirection.Idle) }
|
||||
var previousIndex by remember { mutableStateOf(0) }
|
||||
var previousScrollOffset by remember { mutableStateOf(0) }
|
||||
val keyboardState by getKeyboardState()
|
||||
|
||||
LaunchedEffect(listState.firstVisibleItemIndex, listState.firstVisibleItemScrollOffset) {
|
||||
val currentIndex = listState.firstVisibleItemIndex
|
||||
@@ -590,7 +591,10 @@ private fun ChatList(chatModel: ChatModel, searchText: MutableState<TextFieldVal
|
||||
Modifier
|
||||
.offset {
|
||||
val y = if (searchText.value.text.isEmpty()) {
|
||||
if (oneHandUI.state.value && scrollDirection == ScrollDirection.Up) {
|
||||
if (
|
||||
(oneHandUI.state.value && scrollDirection == ScrollDirection.Up) ||
|
||||
(appPlatform.isAndroid && keyboardState == KeyboardState.Opened)
|
||||
) {
|
||||
0
|
||||
} else if (listState.firstVisibleItemIndex == 0) -listState.firstVisibleItemScrollOffset else -1000
|
||||
} else {
|
||||
|
||||
+2
-1
@@ -21,6 +21,7 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.intl.Locale
|
||||
import androidx.compose.ui.unit.*
|
||||
import chat.simplex.common.model.*
|
||||
import chat.simplex.common.model.ChatController.appPrefs
|
||||
import chat.simplex.common.model.ChatController.stopRemoteHostAndReloadHosts
|
||||
import chat.simplex.common.model.ChatModel.controller
|
||||
import chat.simplex.common.ui.theme.*
|
||||
@@ -149,7 +150,7 @@ fun UserPicker(
|
||||
.padding(bottom = 10.dp, top = 10.dp)
|
||||
.graphicsLayer {
|
||||
alpha = animatedFloat.value
|
||||
translationY = (animatedFloat.value - 1) * xOffset
|
||||
translationY = (if (appPrefs.oneHandUI.state.value) -1 else 1) * (animatedFloat.value - 1) * xOffset
|
||||
},
|
||||
contentAlignment = contentAlignment
|
||||
) {
|
||||
|
||||
+4
-2
@@ -5,6 +5,7 @@ import androidx.compose.ui.graphics.Color
|
||||
import dev.icerock.moko.resources.compose.painterResource
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import chat.simplex.common.model.*
|
||||
import chat.simplex.common.model.ChatController.appPrefs
|
||||
import chat.simplex.common.model.ChatModel.withChats
|
||||
import chat.simplex.common.platform.*
|
||||
import chat.simplex.common.views.chat.*
|
||||
@@ -16,7 +17,7 @@ import chat.simplex.common.views.newchat.chatContactType
|
||||
import chat.simplex.res.MR
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
private fun onRequestAccepted(chat: Chat) {
|
||||
fun onRequestAccepted(chat: Chat) {
|
||||
val chatInfo = chat.chatInfo
|
||||
if (chatInfo is ChatInfo.Direct) {
|
||||
ModalManager.start.closeModals()
|
||||
@@ -27,7 +28,8 @@ private fun onRequestAccepted(chat: Chat) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ContactListNavLinkView(chat: Chat, nextChatSelected: State<Boolean>, oneHandUI: State<Boolean>) {
|
||||
fun ContactListNavLinkView(chat: Chat, nextChatSelected: State<Boolean>) {
|
||||
val oneHandUI = remember { appPrefs.oneHandUI.state }
|
||||
val showMenu = remember { mutableStateOf(false) }
|
||||
val rhId = chat.remoteHostId
|
||||
val disabled = chatModel.chatRunning.value == false || chatModel.deletedChats.value.contains(rhId to chat.chatInfo.id)
|
||||
|
||||
+2
-2
@@ -20,7 +20,7 @@ import chat.simplex.res.MR
|
||||
import dev.icerock.moko.resources.compose.painterResource
|
||||
|
||||
@Composable
|
||||
fun CloseSheetBar(close: (() -> Unit)?, showClose: Boolean = true, tintColor: Color = if (close != null) MaterialTheme.colors.primary else MaterialTheme.colors.secondary, arrangement: Arrangement.Vertical = Arrangement.Top, closeBarTitle: String? = null, endButtons: @Composable RowScope.() -> Unit = {}) {
|
||||
fun CloseSheetBar(close: (() -> Unit)?, showClose: Boolean = true, tintColor: Color = if (close != null) MaterialTheme.colors.primary else MaterialTheme.colors.secondary, arrangement: Arrangement.Vertical = Arrangement.Top, closeBarTitle: String? = null, barPaddingValues: PaddingValues = PaddingValues(horizontal = AppBarHorizontalPadding), endButtons: @Composable RowScope.() -> Unit = {}) {
|
||||
var rowModifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(AppBarHeight * fontSizeSqrtMultiplier)
|
||||
@@ -36,7 +36,7 @@ fun CloseSheetBar(close: (() -> Unit)?, showClose: Boolean = true, tintColor: Co
|
||||
.heightIn(min = AppBarHeight * fontSizeSqrtMultiplier)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.padding(horizontal = AppBarHorizontalPadding),
|
||||
modifier = Modifier.padding(barPaddingValues),
|
||||
content = {
|
||||
Row(
|
||||
rowModifier,
|
||||
|
||||
+5
-10
@@ -26,7 +26,6 @@ fun ModalView(
|
||||
background: Color = MaterialTheme.colors.background,
|
||||
modifier: Modifier = Modifier,
|
||||
closeOnTop: Boolean = true,
|
||||
closeBarTitle: String? = null,
|
||||
endButtons: @Composable RowScope.() -> Unit = {},
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
@@ -38,14 +37,10 @@ fun ModalView(
|
||||
if (closeOnTop) {
|
||||
CloseSheetBar(if (enableClose) close else null, showClose, endButtons = endButtons)
|
||||
}
|
||||
Box(if (closeOnTop) modifier else modifier.padding(bottom = AppBarHeight * fontSizeSqrtMultiplier)) {
|
||||
Box(modifier = modifier) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
if (!closeOnTop) {
|
||||
CloseSheetBar(if (enableClose) close else null, showClose, endButtons = endButtons, arrangement = Arrangement.Bottom, closeBarTitle = closeBarTitle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,17 +67,17 @@ class ModalManager(private val placement: ModalPlacement? = null) {
|
||||
// java.lang.IllegalStateException: Reading a state that was created after the snapshot was taken or in a snapshot that has not yet been applied
|
||||
private var passcodeView: MutableStateFlow<(@Composable (close: () -> Unit) -> Unit)?> = MutableStateFlow(null)
|
||||
|
||||
fun showModal(settings: Boolean = false, showClose: Boolean = true, closeOnTop: Boolean = true, closeBarTitle: String? = null,endButtons: @Composable RowScope.() -> Unit = {}, content: @Composable ModalData.() -> Unit) {
|
||||
fun showModal(settings: Boolean = false, showClose: Boolean = true, closeOnTop: Boolean = true, endButtons: @Composable RowScope.() -> Unit = {}, content: @Composable ModalData.() -> Unit) {
|
||||
val data = ModalData()
|
||||
showCustomModal { close ->
|
||||
ModalView(close, showClose = showClose, closeOnTop = closeOnTop, closeBarTitle = closeBarTitle, endButtons = endButtons, content = { data.content() })
|
||||
ModalView(close, showClose = showClose, closeOnTop = closeOnTop, endButtons = endButtons, content = { data.content() })
|
||||
}
|
||||
}
|
||||
|
||||
fun showModalCloseable(settings: Boolean = false, showClose: Boolean = true, closeOnTop: Boolean = true, closeBarTitle: String? = null, endButtons: @Composable RowScope.() -> Unit = {}, content: @Composable ModalData.(close: () -> Unit) -> Unit) {
|
||||
fun showModalCloseable(settings: Boolean = false, showClose: Boolean = true, closeOnTop: Boolean = true, endButtons: @Composable RowScope.() -> Unit = {}, content: @Composable ModalData.(close: () -> Unit) -> Unit) {
|
||||
val data = ModalData()
|
||||
showCustomModal { close ->
|
||||
ModalView(close, showClose = showClose, endButtons = endButtons, closeOnTop = closeOnTop, closeBarTitle = closeBarTitle, content = { data.content(close) })
|
||||
ModalView(close, showClose = showClose, endButtons = endButtons, closeOnTop = closeOnTop, content = { data.content(close) })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+162
-142
@@ -28,6 +28,7 @@ import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.*
|
||||
import chat.simplex.common.model.*
|
||||
import chat.simplex.common.model.ChatController.appPrefs
|
||||
import chat.simplex.common.platform.*
|
||||
import chat.simplex.common.ui.theme.*
|
||||
import chat.simplex.common.views.chatlist.ScrollDirection
|
||||
@@ -39,45 +40,47 @@ import java.net.URI
|
||||
|
||||
@Composable
|
||||
fun NewChatSheet(rh: RemoteHostInfo?, close: () -> Unit) {
|
||||
val oneHandUI = remember { chatModel.controller.appPrefs.oneHandUI }
|
||||
val oneHandUI = remember { appPrefs.oneHandUI.state }
|
||||
val keyboardState by getKeyboardState()
|
||||
val showToolbarInOneHandUI = remember { derivedStateOf { keyboardState == KeyboardState.Closed && oneHandUI.value } }
|
||||
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
if (!oneHandUI.state.value) {
|
||||
Box(contentAlignment = Alignment.Center) {
|
||||
val bottomPadding = DEFAULT_PADDING
|
||||
AppBarTitle(
|
||||
stringResource(MR.strings.new_chat),
|
||||
hostDevice(rh?.remoteHostId),
|
||||
bottomPadding = bottomPadding
|
||||
)
|
||||
Scaffold(
|
||||
bottomBar = {
|
||||
if (showToolbarInOneHandUI.value) {
|
||||
Column {
|
||||
Divider()
|
||||
CloseSheetBar(
|
||||
close = close,
|
||||
showClose = true,
|
||||
endButtons = { Spacer(Modifier.minimumInteractiveComponentSize()) },
|
||||
arrangement = Arrangement.Bottom,
|
||||
closeBarTitle = generalGetString(MR.strings.new_chat),
|
||||
barPaddingValues = PaddingValues(horizontal = 0.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize().padding(it)
|
||||
) {
|
||||
val closeAll = { ModalManager.start.closeModals() }
|
||||
|
||||
val closeAll = { ModalManager.start.closeModals() }
|
||||
|
||||
var modifier = Modifier.fillMaxSize()
|
||||
|
||||
if (oneHandUI.state.value) {
|
||||
modifier = modifier.scale(scaleX = 1f, scaleY = -1f)
|
||||
}
|
||||
|
||||
Column(modifier = modifier) {
|
||||
NewChatSheetLayout(
|
||||
addContact = {
|
||||
ModalManager.start.showModalCloseable { _ -> NewChatView(chatModel.currentRemoteHost.value, NewChatOption.INVITE, close = closeAll ) }
|
||||
},
|
||||
scanPaste = {
|
||||
ModalManager.start.showModalCloseable { _ -> NewChatView(chatModel.currentRemoteHost.value, NewChatOption.CONNECT, showQRCodeScanner = appPlatform.isAndroid, close = closeAll) }
|
||||
},
|
||||
createGroup = {
|
||||
ModalManager.start.showCustomModal { close -> AddGroupView(chatModel, chatModel.currentRemoteHost.value, close, closeAll) }
|
||||
},
|
||||
rh = rh,
|
||||
close = close,
|
||||
oneHandUI = oneHandUI
|
||||
)
|
||||
Column(modifier = Modifier.fillMaxSize().then(if (oneHandUI.value) Modifier.scale(scaleX = 1f, scaleY = -1f) else Modifier)) {
|
||||
NewChatSheetLayout(
|
||||
addContact = {
|
||||
ModalManager.start.showModalCloseable { _ -> NewChatView(chatModel.currentRemoteHost.value, NewChatOption.INVITE, close = closeAll ) }
|
||||
},
|
||||
scanPaste = {
|
||||
ModalManager.start.showModalCloseable { _ -> NewChatView(chatModel.currentRemoteHost.value, NewChatOption.CONNECT, showQRCodeScanner = appPlatform.isAndroid, close = closeAll) }
|
||||
},
|
||||
createGroup = {
|
||||
ModalManager.start.showCustomModal { close -> AddGroupView(chatModel, chatModel.currentRemoteHost.value, close, closeAll) }
|
||||
},
|
||||
rh = rh,
|
||||
close = close
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,7 +93,7 @@ fun chatContactType(chat: Chat): ContactType {
|
||||
return when (val cInfo = chat.chatInfo) {
|
||||
is ChatInfo.ContactRequest -> ContactType.REQUEST
|
||||
is ChatInfo.Direct -> {
|
||||
val contact = cInfo.contact;
|
||||
val contact = cInfo.contact
|
||||
|
||||
when {
|
||||
contact.activeConn == null && contact.profile.contactLink != null -> ContactType.CARD
|
||||
@@ -116,15 +119,15 @@ private fun NewChatSheetLayout(
|
||||
scanPaste: () -> Unit,
|
||||
createGroup: () -> Unit,
|
||||
close: () -> Unit,
|
||||
oneHandUI: SharedPreference<Boolean>
|
||||
) {
|
||||
val oneHandUI = remember { appPrefs.oneHandUI.state }
|
||||
val listState = rememberLazyListState(lazyListState.first, lazyListState.second)
|
||||
val searchText = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) }
|
||||
val searchShowingSimplexLink = remember { mutableStateOf(false) }
|
||||
val searchChatFilteredBySimplexLink = remember { mutableStateOf<String?>(null) }
|
||||
val showUnreadAndFavorites = remember { ChatController.appPrefs.showUnreadAndFavorites.state }.value
|
||||
val baseContactTypes = listOf(ContactType.CARD, ContactType.RECENT, ContactType.REQUEST)
|
||||
val contactTypes by remember(baseContactTypes, searchText.value.text.isEmpty()) {
|
||||
val baseContactTypes = remember { listOf(ContactType.CARD, ContactType.RECENT, ContactType.REQUEST) }
|
||||
val contactTypes by remember(searchText.value.text.isEmpty()) {
|
||||
derivedStateOf { contactTypesSearchTargets(baseContactTypes, searchText.value.text.isEmpty()) }
|
||||
}
|
||||
val allChats by remember(chatModel.chats.value, contactTypes) {
|
||||
@@ -133,6 +136,7 @@ private fun NewChatSheetLayout(
|
||||
var scrollDirection by remember { mutableStateOf(ScrollDirection.Idle) }
|
||||
var previousIndex by remember { mutableStateOf(0) }
|
||||
var previousScrollOffset by remember { mutableStateOf(0) }
|
||||
val keyboardState by getKeyboardState()
|
||||
|
||||
LaunchedEffect(listState.firstVisibleItemIndex, listState.firstVisibleItemScrollOffset) {
|
||||
val currentIndex = listState.firstVisibleItemIndex
|
||||
@@ -160,22 +164,32 @@ private fun NewChatSheetLayout(
|
||||
contactChats = allChats
|
||||
)
|
||||
|
||||
var sectionModifier = Modifier.fillMaxWidth()
|
||||
|
||||
if (oneHandUI.state.value) {
|
||||
sectionModifier = sectionModifier.scale(scaleX = 1f, scaleY = -1f)
|
||||
}
|
||||
|
||||
val sectionModifier = if (oneHandUI.value) Modifier.fillMaxWidth().scale(scaleX = 1f, scaleY = -1f) else Modifier.fillMaxWidth()
|
||||
LazyColumnWithScrollBar(
|
||||
Modifier.fillMaxWidth(),
|
||||
listState
|
||||
) {
|
||||
if (!oneHandUI.value) {
|
||||
item {
|
||||
Box(contentAlignment = Alignment.Center) {
|
||||
val bottomPadding = DEFAULT_PADDING
|
||||
AppBarTitle(
|
||||
stringResource(MR.strings.new_chat),
|
||||
hostDevice(rh?.remoteHostId),
|
||||
bottomPadding = bottomPadding
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
stickyHeader {
|
||||
Column(
|
||||
Modifier
|
||||
.offset {
|
||||
val y = if (searchText.value.text.isEmpty()) {
|
||||
if (oneHandUI.state.value && scrollDirection == ScrollDirection.Up) {
|
||||
if (
|
||||
(oneHandUI.value && scrollDirection == ScrollDirection.Up) ||
|
||||
(appPlatform.isAndroid && keyboardState == KeyboardState.Opened)
|
||||
) {
|
||||
0
|
||||
} else if (listState.firstVisibleItemIndex == 0) -listState.firstVisibleItemScrollOffset else -1000
|
||||
} else {
|
||||
@@ -185,7 +199,7 @@ private fun NewChatSheetLayout(
|
||||
}
|
||||
.background(MaterialTheme.colors.background)
|
||||
) {
|
||||
if (!oneHandUI.state.value) {
|
||||
if (!oneHandUI.value) {
|
||||
Divider()
|
||||
}
|
||||
ContactsSearchBar(
|
||||
@@ -194,13 +208,12 @@ private fun NewChatSheetLayout(
|
||||
searchShowingSimplexLink = searchShowingSimplexLink,
|
||||
searchChatFilteredBySimplexLink = searchChatFilteredBySimplexLink,
|
||||
close = close,
|
||||
oneHandUI = oneHandUI
|
||||
)
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
item {
|
||||
Spacer(Modifier.padding(bottom = DEFAULT_PADDING))
|
||||
Spacer(Modifier.padding(bottom = 27.dp))
|
||||
|
||||
if (searchText.value.text.isEmpty()) {
|
||||
Row {
|
||||
@@ -210,21 +223,18 @@ private fun NewChatSheetLayout(
|
||||
text = stringResource(MR.strings.add_contact_tab),
|
||||
click = addContact,
|
||||
extraPadding = true,
|
||||
oneHandUI = oneHandUI.state
|
||||
)
|
||||
NewChatButton(
|
||||
icon = painterResource(MR.images.ic_qr_code),
|
||||
text = if (appPlatform.isAndroid) stringResource(MR.strings.scan_paste_link) else stringResource(MR.strings.paste_link),
|
||||
click = scanPaste,
|
||||
extraPadding = true,
|
||||
oneHandUI = oneHandUI.state
|
||||
)
|
||||
NewChatButton(
|
||||
icon = painterResource(MR.images.ic_group),
|
||||
text = stringResource(MR.strings.create_group_button),
|
||||
click = createGroup,
|
||||
extraPadding = true,
|
||||
oneHandUI = oneHandUI.state
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -242,11 +252,9 @@ private fun NewChatSheetLayout(
|
||||
ModalManager.start.showCustomModal { closeDeletedChats ->
|
||||
ModalView(
|
||||
close = closeDeletedChats,
|
||||
closeOnTop = !oneHandUI.state.value,
|
||||
closeBarTitle = if (oneHandUI.state.value) generalGetString(MR.strings.deleted_chats) else null,
|
||||
endButtons = { Spacer(Modifier.minimumInteractiveComponentSize()) }
|
||||
closeOnTop = !oneHandUI.value,
|
||||
) {
|
||||
DeletedContactsView(rh = rh, close = {
|
||||
DeletedContactsView(rh = rh, closeDeletedChats = closeDeletedChats, close = {
|
||||
ModalManager.start.closeModals()
|
||||
})
|
||||
}
|
||||
@@ -263,16 +271,16 @@ private fun NewChatSheetLayout(
|
||||
}
|
||||
}
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
if (filteredContactChats.isNotEmpty() && !oneHandUI.state.value) {
|
||||
if (filteredContactChats.isNotEmpty() && !oneHandUI.value) {
|
||||
Text(
|
||||
stringResource(MR.strings.contact_list_header_title).uppercase(), color = MaterialTheme.colors.secondary, style = MaterialTheme.typography.body2,
|
||||
modifier = sectionModifier.padding(start = DEFAULT_PADDING, bottom = 5.dp), fontSize = 12.sp
|
||||
modifier = sectionModifier.padding(start = DEFAULT_PADDING, top = DEFAULT_PADDING_HALF, bottom = DEFAULT_PADDING_HALF), fontSize = 12.sp
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -283,7 +291,7 @@ private fun NewChatSheetLayout(
|
||||
chatModel.chatId.value != null && filteredContactChats.getOrNull(index + 1)?.id == chatModel.chatId.value
|
||||
}
|
||||
}
|
||||
ContactListNavLinkView(chat, nextChatSelected, oneHandUI.state)
|
||||
ContactListNavLinkView(chat, nextChatSelected)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,8 +316,9 @@ private fun NewChatButton(
|
||||
iconColor: Color = MaterialTheme.colors.secondary,
|
||||
disabled: Boolean = false,
|
||||
extraPadding: Boolean = false,
|
||||
oneHandUI: State<Boolean>
|
||||
) {
|
||||
val oneHandUI = remember { appPrefs.oneHandUI.state }
|
||||
|
||||
SectionItemView(click, disabled = disabled) {
|
||||
Row(modifier = if (oneHandUI.value) Modifier.scale(scaleX = 1f, scaleY = -1f) else Modifier) {
|
||||
Icon(icon, text, tint = if (disabled) MaterialTheme.colors.secondary else iconColor)
|
||||
@@ -326,14 +335,10 @@ private fun ContactsSearchBar(
|
||||
searchShowingSimplexLink: MutableState<Boolean>,
|
||||
searchChatFilteredBySimplexLink: MutableState<String?>,
|
||||
close: () -> Unit,
|
||||
oneHandUI: SharedPreference<Boolean>
|
||||
) {
|
||||
var modifier = Modifier.fillMaxWidth();
|
||||
|
||||
if (oneHandUI.state.value) {
|
||||
modifier = modifier.scale(scaleX = 1f, scaleY = -1f)
|
||||
}
|
||||
val oneHandUI = remember { appPrefs.oneHandUI.state }
|
||||
|
||||
val modifier = if (oneHandUI.value) Modifier.fillMaxWidth().scale(scaleX = 1f, scaleY = -1f) else Modifier.fillMaxWidth()
|
||||
var focused by remember { mutableStateOf(false) }
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = modifier) {
|
||||
@@ -416,7 +421,7 @@ private fun ContactsSearchBar(
|
||||
|
||||
@Composable
|
||||
private fun ToggleFilterButton() {
|
||||
val pref = remember { ChatController.appPrefs.showUnreadAndFavorites }
|
||||
val pref = remember { appPrefs.showUnreadAndFavorites }
|
||||
IconButton(onClick = { pref.set(!pref.get()) }) {
|
||||
val sp16 = with(LocalDensity.current) { 16.sp.toDp() }
|
||||
Icon(
|
||||
@@ -471,7 +476,7 @@ private fun filteredContactChats(
|
||||
}
|
||||
|
||||
private fun filterChat(chat: Chat, searchText: String, showUnreadAndFavorites: Boolean): Boolean {
|
||||
var meetsPredicate = true;
|
||||
var meetsPredicate = true
|
||||
val s = searchText.trim().lowercase()
|
||||
val cInfo = chat.chatInfo
|
||||
|
||||
@@ -485,7 +490,7 @@ private fun filterChat(chat: Chat, searchText: String, showUnreadAndFavorites: B
|
||||
meetsPredicate = meetsPredicate && (cInfo.chatSettings?.favorite ?: false)
|
||||
}
|
||||
|
||||
return meetsPredicate;
|
||||
return meetsPredicate
|
||||
}
|
||||
|
||||
private fun viewNameContains(cInfo: ChatInfo, s: String): Boolean =
|
||||
@@ -512,84 +517,99 @@ private fun contactTypesSearchTargets(baseContactTypes: List<ContactType>, searc
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DeletedContactsView(rh: RemoteHostInfo?, close: () -> Unit) {
|
||||
val oneHandUI = remember { chatModel.controller.appPrefs.oneHandUI }
|
||||
private fun DeletedContactsView(rh: RemoteHostInfo?, closeDeletedChats: () -> Unit, close: () -> Unit) {
|
||||
val oneHandUI = remember { appPrefs.oneHandUI.state }
|
||||
val keyboardState by getKeyboardState()
|
||||
val showToolbarInOneHandUI = remember { derivedStateOf { keyboardState == KeyboardState.Closed && oneHandUI.value } }
|
||||
|
||||
var modifier = Modifier.fillMaxSize()
|
||||
|
||||
if (oneHandUI.state.value) {
|
||||
modifier = modifier.scale(scaleX = 1f, scaleY = -1f)
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier,
|
||||
Scaffold(
|
||||
bottomBar = {
|
||||
if (showToolbarInOneHandUI.value) {
|
||||
CloseSheetBar(
|
||||
close = closeDeletedChats,
|
||||
showClose = true,
|
||||
endButtons = { Spacer(Modifier.minimumInteractiveComponentSize()) },
|
||||
arrangement = Arrangement.Bottom,
|
||||
closeBarTitle = generalGetString(MR.strings.deleted_chats),
|
||||
barPaddingValues = PaddingValues(horizontal = 0.dp)
|
||||
)
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
) {
|
||||
if (!oneHandUI.state.value) {
|
||||
Box(contentAlignment = Alignment.Center) {
|
||||
val bottomPadding = DEFAULT_PADDING
|
||||
AppBarTitle(
|
||||
stringResource(MR.strings.deleted_chats),
|
||||
hostDevice(rh?.remoteHostId),
|
||||
bottomPadding = bottomPadding
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val listState = rememberLazyListState(lazyListState.first, lazyListState.second)
|
||||
val searchText = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) }
|
||||
val searchShowingSimplexLink = remember { mutableStateOf(false) }
|
||||
val searchChatFilteredBySimplexLink = remember { mutableStateOf<String?>(null) }
|
||||
val showUnreadAndFavorites = remember { ChatController.appPrefs.showUnreadAndFavorites.state }.value
|
||||
val contactTypes = listOf(ContactType.CHAT_DELETED)
|
||||
val allChats by remember(chatModel.chats.value, contactTypes) {
|
||||
derivedStateOf { filterContactTypes(chatModel.chats.value, contactTypes) }
|
||||
}
|
||||
val filteredContactChats = filteredContactChats(
|
||||
showUnreadAndFavorites = showUnreadAndFavorites,
|
||||
searchChatFilteredBySimplexLink = searchChatFilteredBySimplexLink,
|
||||
searchShowingSimplexLink = searchShowingSimplexLink,
|
||||
searchText = searchText.value.text,
|
||||
contactChats = allChats
|
||||
)
|
||||
|
||||
LazyColumnWithScrollBar(
|
||||
Modifier.fillMaxWidth(),
|
||||
listState
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.padding(it)
|
||||
.then(if (oneHandUI.value) Modifier.scale(scaleX = 1f, scaleY = -1f) else Modifier),
|
||||
) {
|
||||
item {
|
||||
Divider()
|
||||
ContactsSearchBar(
|
||||
listState = listState,
|
||||
searchText = searchText,
|
||||
searchShowingSimplexLink = searchShowingSimplexLink,
|
||||
searchChatFilteredBySimplexLink = searchChatFilteredBySimplexLink,
|
||||
close = close,
|
||||
oneHandUI = oneHandUI
|
||||
)
|
||||
Divider()
|
||||
|
||||
Spacer(Modifier.padding(bottom = DEFAULT_PADDING))
|
||||
}
|
||||
|
||||
itemsIndexed(filteredContactChats) { index, chat ->
|
||||
val nextChatSelected = remember(chat.id, filteredContactChats) {
|
||||
derivedStateOf {
|
||||
chatModel.chatId.value != null && filteredContactChats.getOrNull(index + 1)?.id == chatModel.chatId.value
|
||||
}
|
||||
}
|
||||
ContactListNavLinkView(chat, nextChatSelected, oneHandUI.state)
|
||||
}
|
||||
}
|
||||
if (filteredContactChats.isEmpty() && allChats.isNotEmpty()) {
|
||||
Column(Modifier.fillMaxSize().padding(DEFAULT_PADDING)) {
|
||||
Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
|
||||
Text(
|
||||
generalGetString(MR.strings.no_filtered_contacts),
|
||||
color = MaterialTheme.colors.secondary,
|
||||
modifier = if (oneHandUI.state.value) Modifier.scale(scaleX = 1f, scaleY = -1f) else Modifier
|
||||
if (!oneHandUI.value) {
|
||||
Box(contentAlignment = Alignment.Center) {
|
||||
val bottomPadding = DEFAULT_PADDING
|
||||
AppBarTitle(
|
||||
stringResource(MR.strings.deleted_chats),
|
||||
hostDevice(rh?.remoteHostId),
|
||||
bottomPadding = bottomPadding
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val listState = rememberLazyListState(lazyListState.first, lazyListState.second)
|
||||
val searchText = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) }
|
||||
val searchShowingSimplexLink = remember { mutableStateOf(false) }
|
||||
val searchChatFilteredBySimplexLink = remember { mutableStateOf<String?>(null) }
|
||||
val showUnreadAndFavorites = remember { appPrefs.showUnreadAndFavorites.state }.value
|
||||
val allChats by remember(chatModel.chats.value) {
|
||||
derivedStateOf { filterContactTypes(chatModel.chats.value, listOf(ContactType.CHAT_DELETED)) }
|
||||
}
|
||||
val filteredContactChats = filteredContactChats(
|
||||
showUnreadAndFavorites = showUnreadAndFavorites,
|
||||
searchChatFilteredBySimplexLink = searchChatFilteredBySimplexLink,
|
||||
searchShowingSimplexLink = searchShowingSimplexLink,
|
||||
searchText = searchText.value.text,
|
||||
contactChats = allChats
|
||||
)
|
||||
|
||||
LazyColumnWithScrollBar(
|
||||
Modifier.fillMaxWidth(),
|
||||
listState
|
||||
) {
|
||||
item {
|
||||
if (!oneHandUI.value) {
|
||||
Divider()
|
||||
}
|
||||
ContactsSearchBar(
|
||||
listState = listState,
|
||||
searchText = searchText,
|
||||
searchShowingSimplexLink = searchShowingSimplexLink,
|
||||
searchChatFilteredBySimplexLink = searchChatFilteredBySimplexLink,
|
||||
close = close,
|
||||
)
|
||||
Divider()
|
||||
|
||||
Spacer(Modifier.padding(bottom = DEFAULT_PADDING))
|
||||
}
|
||||
|
||||
itemsIndexed(filteredContactChats) { index, chat ->
|
||||
val nextChatSelected = remember(chat.id, filteredContactChats) {
|
||||
derivedStateOf {
|
||||
chatModel.chatId.value != null && filteredContactChats.getOrNull(index + 1)?.id == chatModel.chatId.value
|
||||
}
|
||||
}
|
||||
ContactListNavLinkView(chat, nextChatSelected)
|
||||
}
|
||||
}
|
||||
if (filteredContactChats.isEmpty() && allChats.isNotEmpty()) {
|
||||
Column(Modifier.fillMaxSize().padding(DEFAULT_PADDING)) {
|
||||
Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
|
||||
Text(
|
||||
generalGetString(MR.strings.no_filtered_contacts),
|
||||
color = MaterialTheme.colors.secondary,
|
||||
modifier = if (oneHandUI.value) Modifier.scale(scaleX = 1f, scaleY = -1f) else Modifier
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-7
@@ -61,9 +61,8 @@ fun ModalData.NewChatView(rh: RemoteHostInfo?, selection: NewChatOption, showQRC
|
||||
/** When [AddContactLearnMore] is open, we don't need to drop [ChatModel.showingInvitation].
|
||||
* Otherwise, it will be called here AFTER [AddContactLearnMore] is launched and will clear the value too soon.
|
||||
* It will be dropped automatically when connection established or when user goes away from this screen.
|
||||
* It applies only to Android because on Desktop center space will not be overlapped by [AddContactLearnMore]
|
||||
**/
|
||||
if (chatModel.showingInvitation.value != null && (ModalManager.start.openModalCount() == 1 || appPlatform.isDesktop)) {
|
||||
if (chatModel.showingInvitation.value != null && ModalManager.start.openModalCount() == 1) {
|
||||
val conn = contactConnection.value
|
||||
if (chatModel.showingInvitation.value?.connChatUsed == false && conn != null) {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
@@ -78,7 +77,7 @@ fun ModalData.NewChatView(rh: RemoteHostInfo?, selection: NewChatOption, showQRC
|
||||
controller.deleteChat(Chat(remoteHostId = rh?.remoteHostId, chatInfo = chatInfo, chatItems = listOf()))
|
||||
if (chatModel.chatId.value == chatInfo.id) {
|
||||
chatModel.chatId.value = null
|
||||
ModalManager.end.closeModals()
|
||||
ModalManager.start.closeModals()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -212,8 +211,7 @@ private fun InviteView(rhId: Long?, connReqInvitation: String, contactConnection
|
||||
Spacer(Modifier.height(10.dp))
|
||||
val incognito = remember { mutableStateOf(controller.appPrefs.incognito.get()) }
|
||||
IncognitoToggle(controller.appPrefs.incognito, incognito) {
|
||||
if (appPlatform.isDesktop) ModalManager.end.closeModals()
|
||||
ModalManager.end.showModal { IncognitoView() }
|
||||
ModalManager.start.showModal { IncognitoView() }
|
||||
}
|
||||
KeyChangeEffect(incognito.value) {
|
||||
withBGApi {
|
||||
@@ -233,8 +231,7 @@ private fun InviteView(rhId: Long?, connReqInvitation: String, contactConnection
|
||||
private fun AddContactLearnMoreButton() {
|
||||
IconButton(
|
||||
{
|
||||
if (appPlatform.isDesktop) ModalManager.end.closeModals()
|
||||
ModalManager.end.showModalCloseable { close ->
|
||||
ModalManager.start.showModalCloseable { close ->
|
||||
AddContactLearnMore(close)
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user