mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-09-16 08:23:04 +00:00
changes
This commit is contained in:
@@ -31,6 +31,13 @@ class MainActivity: FragmentActivity() {
|
||||
val c = CurrentColors.value.colors
|
||||
platform.androidSetStatusAndNavigationBarAppearance(c.isLight)
|
||||
applyAppLocale(ChatModel.controller.appPrefs.appLanguage)
|
||||
// This flag makes status bar and navigation bar fully transparent. But on API level < 30 it breaks insets entirely
|
||||
// https://issuetracker.google.com/issues/236862874
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q){
|
||||
window.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
|
||||
} else {
|
||||
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
|
||||
}
|
||||
super.onCreate(savedInstanceState)
|
||||
// testJson()
|
||||
// When call ended and orientation changes, it re-process old intent, it's unneeded.
|
||||
|
||||
@@ -7,6 +7,8 @@ import chat.simplex.common.platform.Log
|
||||
import android.content.Intent
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.os.*
|
||||
import android.view.View
|
||||
import android.view.WindowManager.LayoutParams
|
||||
import androidx.compose.animation.core.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
@@ -285,6 +287,13 @@ class SimplexApp: Application(), LifecycleEventObserver {
|
||||
if (windowInsetController?.isAppearanceLightNavigationBars != CurrentColors.value.colors.isLight) {
|
||||
windowInsetController?.isAppearanceLightNavigationBars = CurrentColors.value.colors.isLight
|
||||
}
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||
window.decorView.systemUiVisibility = if (CurrentColors.value.colors.isLight) {
|
||||
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun androidStartCallActivity(acceptCall: Boolean, remoteHostId: Long?, chatId: ChatId?) {
|
||||
|
||||
+19
-17
@@ -8,8 +8,7 @@ import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import chat.simplex.common.model.ChatController.appPrefs
|
||||
import chat.simplex.common.views.chatlist.NavigationBarBackground
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlin.math.absoluteValue
|
||||
@@ -39,14 +38,12 @@ actual fun LazyColumnWithScrollBar(
|
||||
}
|
||||
}
|
||||
}
|
||||
val direction = LocalLayoutDirection.current
|
||||
val paddingEnd = WindowInsets.navigationBars.asPaddingValues().calculateEndPadding(direction)
|
||||
if (connection != null) {
|
||||
LazyColumn(modifier.nestedScroll(connection).padding(end = paddingEnd), state, contentPadding, reverseLayout, verticalArrangement, horizontalAlignment, flingBehavior, userScrollEnabled) {
|
||||
LazyColumn(modifier.nestedScroll(connection), state, contentPadding, reverseLayout, verticalArrangement, horizontalAlignment, flingBehavior, userScrollEnabled) {
|
||||
content()
|
||||
}
|
||||
} else {
|
||||
LazyColumn(modifier.padding(end = paddingEnd), state, contentPadding, reverseLayout, verticalArrangement, horizontalAlignment, flingBehavior, userScrollEnabled) {
|
||||
LazyColumn(modifier, state, contentPadding, reverseLayout, verticalArrangement, horizontalAlignment, flingBehavior, userScrollEnabled) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
@@ -74,25 +71,30 @@ actual fun ColumnWithScrollBar(
|
||||
}
|
||||
}
|
||||
}
|
||||
val direction = LocalLayoutDirection.current
|
||||
if (connection != null) {
|
||||
Box(Modifier.fillMaxHeight()) {
|
||||
if (connection != null) {
|
||||
Column(
|
||||
if (maxIntrinsicSize) {
|
||||
modifier.nestedScroll(connection).verticalScroll(state).height(IntrinsicSize.Max).padding(end = WindowInsets.navigationBars.asPaddingValues().calculateEndPadding(direction))
|
||||
modifier.nestedScroll(connection).verticalScroll(state).height(IntrinsicSize.Max)
|
||||
} else {
|
||||
modifier.nestedScroll(connection).verticalScroll(state).padding(end = WindowInsets.navigationBars.asPaddingValues().calculateEndPadding(direction))
|
||||
}, verticalArrangement, horizontalAlignment) {
|
||||
modifier.nestedScroll(connection).verticalScroll(state)
|
||||
}, verticalArrangement, horizontalAlignment
|
||||
) {
|
||||
content()
|
||||
Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.systemBars))
|
||||
}
|
||||
} else {
|
||||
Column(if (maxIntrinsicSize) {
|
||||
modifier.verticalScroll(state).height(IntrinsicSize.Max).padding(end = WindowInsets.navigationBars.asPaddingValues().calculateEndPadding(direction))
|
||||
} else {
|
||||
modifier.verticalScroll(state).padding(end = WindowInsets.navigationBars.asPaddingValues().calculateEndPadding(direction))
|
||||
}, verticalArrangement, horizontalAlignment) {
|
||||
} else {
|
||||
Column(
|
||||
if (maxIntrinsicSize) {
|
||||
modifier.verticalScroll(state).height(IntrinsicSize.Max)
|
||||
} else {
|
||||
modifier.verticalScroll(state)
|
||||
}, verticalArrangement, horizontalAlignment
|
||||
) {
|
||||
content()
|
||||
Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.systemBars))
|
||||
}
|
||||
}
|
||||
NavigationBarBackground()
|
||||
}
|
||||
}
|
||||
|
||||
+8
-22
@@ -3,17 +3,18 @@ package chat.simplex.common.platform
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.graphics.Rect
|
||||
import android.os.*
|
||||
import android.view.*
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.Toast
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.ime
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import chat.simplex.common.AppScreen
|
||||
import chat.simplex.common.model.clear
|
||||
import chat.simplex.common.ui.theme.SimpleXTheme
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import androidx.compose.ui.platform.LocalContext as LocalContext1
|
||||
import chat.simplex.res.MR
|
||||
@@ -43,28 +44,13 @@ actual fun LocalMultiplatformView(): Any? = LocalView.current
|
||||
|
||||
@Composable
|
||||
actual fun getKeyboardState(): State<KeyboardState> {
|
||||
val keyboardState = remember { mutableStateOf(KeyboardState.Closed) }
|
||||
val view = LocalView.current
|
||||
DisposableEffect(view) {
|
||||
val onGlobalListener = ViewTreeObserver.OnGlobalLayoutListener {
|
||||
val rect = Rect()
|
||||
view.getWindowVisibleDisplayFrame(rect)
|
||||
val screenHeight = view.rootView.height
|
||||
val keypadHeight = screenHeight - rect.bottom
|
||||
keyboardState.value = if (keypadHeight > screenHeight * 0.15) {
|
||||
KeyboardState.Opened
|
||||
} else {
|
||||
KeyboardState.Closed
|
||||
}
|
||||
}
|
||||
view.viewTreeObserver.addOnGlobalLayoutListener(onGlobalListener)
|
||||
|
||||
onDispose {
|
||||
view.viewTreeObserver.removeOnGlobalLayoutListener(onGlobalListener)
|
||||
val density = LocalDensity.current
|
||||
val ime = WindowInsets.ime
|
||||
return remember {
|
||||
derivedStateOf {
|
||||
if (ime.getBottom(density) == 0) KeyboardState.Closed else KeyboardState.Opened
|
||||
}
|
||||
}
|
||||
|
||||
return keyboardState
|
||||
}
|
||||
|
||||
actual fun hideKeyboard(view: Any?, clearFocus: Boolean) {
|
||||
|
||||
+58
-50
@@ -138,65 +138,73 @@ actual fun PlatformUserPicker(modifier: Modifier, pickerState: MutableStateFlow<
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
Box(
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.then(clickableModifier)
|
||||
.drawBehind {
|
||||
val pos = when {
|
||||
dismissState.progress.from == DismissValue.Default && dismissState.progress.to == DismissValue.Default -> 1f
|
||||
dismissState.progress.from == DismissValue.DismissedToEnd && dismissState.progress.to == DismissValue.DismissedToEnd -> 0f
|
||||
dismissState.progress.to == DismissValue.Default -> dismissState.progress.fraction
|
||||
else -> 1 - dismissState.progress.fraction
|
||||
}
|
||||
val colors = CurrentColors.value.colors
|
||||
val resultingColor = if (colors.isLight) colors.onSurface.copy(alpha = ScrimOpacity) else Color.Black.copy(0.64f)
|
||||
drawRect(
|
||||
if (pos != 0f) resultingColor else Color.Transparent,
|
||||
alpha = calculateFraction(pos = pos)
|
||||
)
|
||||
}
|
||||
.graphicsLayer {
|
||||
if (heightValue == 0) {
|
||||
alpha = 0f
|
||||
}
|
||||
translationY = dismissState.offset.value
|
||||
},
|
||||
contentAlignment = Alignment.BottomCenter
|
||||
) {
|
||||
Box {
|
||||
Box(
|
||||
Modifier.onSizeChanged { height.intValue = it.height }
|
||||
) {
|
||||
KeyChangeEffect(pickerIsVisible) {
|
||||
if (pickerState.value.isVisible()) {
|
||||
try {
|
||||
dismissState.animateTo(DismissValue.Default, userPickerAnimSpec())
|
||||
} catch (e: CancellationException) {
|
||||
Log.e(TAG, "Cancelled animateTo: ${e.stackTraceToString()}")
|
||||
pickerState.value = AnimatedViewState.GONE
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.then(clickableModifier)
|
||||
.drawBehind {
|
||||
val pos = calculatePosition(dismissState)
|
||||
val colors = CurrentColors.value.colors
|
||||
val resultingColor = if (colors.isLight) colors.onSurface.copy(alpha = ScrimOpacity) else Color.Black.copy(0.64f)
|
||||
drawRect(
|
||||
if (pos != 0f) resultingColor else Color.Transparent,
|
||||
alpha = calculateFraction(pos = pos)
|
||||
)
|
||||
}
|
||||
.graphicsLayer {
|
||||
if (heightValue == 0) {
|
||||
alpha = 0f
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
dismissState.animateTo(DismissValue.DismissedToEnd, userPickerAnimSpec())
|
||||
} catch (e: CancellationException) {
|
||||
Log.e(TAG, "Cancelled animateTo2: ${e.stackTraceToString()}")
|
||||
pickerState.value = AnimatedViewState.VISIBLE
|
||||
translationY = dismissState.offset.value
|
||||
},
|
||||
contentAlignment = Alignment.BottomCenter
|
||||
) {
|
||||
Box(
|
||||
Modifier.onSizeChanged { height.intValue = it.height }
|
||||
) {
|
||||
KeyChangeEffect(pickerIsVisible) {
|
||||
if (pickerState.value.isVisible()) {
|
||||
try {
|
||||
dismissState.animateTo(DismissValue.Default, userPickerAnimSpec())
|
||||
} catch (e: CancellationException) {
|
||||
Log.e(TAG, "Cancelled animateTo: ${e.stackTraceToString()}")
|
||||
pickerState.value = AnimatedViewState.GONE
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
dismissState.animateTo(DismissValue.DismissedToEnd, userPickerAnimSpec())
|
||||
} catch (e: CancellationException) {
|
||||
Log.e(TAG, "Cancelled animateTo2: ${e.stackTraceToString()}")
|
||||
pickerState.value = AnimatedViewState.VISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val draggableModifier = if (height.intValue != 0)
|
||||
Modifier.draggableBottomDrawerModifier(
|
||||
state = dismissState,
|
||||
swipeDistance = height.intValue.toFloat(),
|
||||
)
|
||||
else Modifier
|
||||
Box(draggableModifier.then(modifier)) {
|
||||
content()
|
||||
val draggableModifier = if (height.intValue != 0)
|
||||
Modifier.draggableBottomDrawerModifier(
|
||||
state = dismissState,
|
||||
swipeDistance = height.intValue.toFloat(),
|
||||
)
|
||||
else Modifier
|
||||
Box(draggableModifier.then(modifier).navigationBarsPadding()) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
NavigationBarBackground(
|
||||
modifier = Modifier.graphicsLayer { alpha = if (calculatePosition(dismissState) > 0.1f) 1f else 0f },
|
||||
color = MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, alpha = 1 - userPickerAlpha())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun calculatePosition(dismissState: DismissState): Float = when {
|
||||
dismissState.progress.from == DismissValue.Default && dismissState.progress.to == DismissValue.Default -> 1f
|
||||
dismissState.progress.from == DismissValue.DismissedToEnd && dismissState.progress.to == DismissValue.DismissedToEnd -> 0f
|
||||
dismissState.progress.to == DismissValue.Default -> dismissState.progress.fraction
|
||||
else -> 1 - dismissState.progress.fraction
|
||||
}
|
||||
|
||||
private fun Modifier.draggableBottomDrawerModifier(
|
||||
state: DismissState,
|
||||
swipeDistance: Float,
|
||||
|
||||
+2
@@ -171,6 +171,8 @@ actual fun GetImageBottomSheet(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.imePadding()
|
||||
.navigationBarsPadding()
|
||||
.onFocusChanged { focusState ->
|
||||
if (!focusState.hasFocus) hideBottomSheet()
|
||||
}
|
||||
|
||||
@@ -12,9 +12,9 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clipToBounds
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import chat.simplex.common.views.usersettings.SetDeliveryReceiptsView
|
||||
import chat.simplex.common.model.*
|
||||
@@ -45,7 +45,22 @@ fun AppScreen() {
|
||||
AppBarHandler.appBarMaxHeightPx = with(LocalDensity.current) { AppBarHeight.roundToPx() }
|
||||
SimpleXTheme {
|
||||
Surface(color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) {
|
||||
MainScreen()
|
||||
// This padding applies to landscape view only taking care of navigation bar and holes in screen in status bar area
|
||||
// (because nav bar and holes located on vertical sides of screen in landscape view)
|
||||
val direction = LocalLayoutDirection.current
|
||||
val safePadding = WindowInsets.safeDrawing.asPaddingValues()
|
||||
val paddingStart = safePadding.calculateStartPadding(direction)
|
||||
val paddingEnd = safePadding.calculateEndPadding(direction)
|
||||
// Such a strange layout is needed because the main content should be covered by solid color in order to hide overflow
|
||||
// of some elements that may have negative offset (so, can't use Row {}).
|
||||
// To check: go to developer settings of Android, choose Display cutout -> Punch hole, and rotate the phone to landscape, open any chat
|
||||
Box {
|
||||
Box(Modifier.padding(start = paddingStart, end = paddingEnd).consumeWindowInsets(PaddingValues(start = paddingStart, end = paddingEnd))) {
|
||||
MainScreen()
|
||||
}
|
||||
Box(Modifier.width(paddingStart).fillMaxHeight().background(MaterialTheme.colors.background))
|
||||
Box(Modifier.align(Alignment.CenterEnd).width(paddingEnd).fillMaxHeight().background(MaterialTheme.colors.background))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -245,7 +260,10 @@ fun AndroidScreen(userPickerState: MutableStateFlow<AnimatedViewState>) {
|
||||
Box(
|
||||
Modifier
|
||||
.graphicsLayer {
|
||||
translationX = -offset.value.dp.toPx()
|
||||
// minOf thing is needed for devices with holes in screen while the user on ChatView rotates his phone from portrait to landscape
|
||||
// because in this case (at least in emulator) maxWidth changes in two steps: big first, smaller on next frame.
|
||||
// But offset is remembered already, so this is a better way than dropping a value of offset
|
||||
translationX = -minOf(offset.value.dp, maxWidth).toPx()
|
||||
}
|
||||
.padding(top = if (showCallArea) ANDROID_CALL_TOP_PADDING else 0.dp)
|
||||
) {
|
||||
@@ -275,7 +293,7 @@ fun AndroidScreen(userPickerState: MutableStateFlow<AnimatedViewState>) {
|
||||
}
|
||||
}
|
||||
Box(Modifier
|
||||
.graphicsLayer { translationX = maxWidth.toPx() - offset.value.dp.toPx() }
|
||||
.graphicsLayer { translationX = maxWidth.toPx() - minOf(offset.value.dp, maxWidth).toPx() }
|
||||
.padding(top = if (showCallArea) ANDROID_CALL_TOP_PADDING else 0.dp)
|
||||
) Box2@{
|
||||
currentChatId.value?.let {
|
||||
|
||||
+11
-7
@@ -20,6 +20,7 @@ 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.common.views.chatlist.NavigationBarBackground
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -170,13 +171,16 @@ fun TerminalLog(floating: Boolean) {
|
||||
ModalManager.start
|
||||
}
|
||||
modalPlace.showModal(endButtons = { ShareButton { clipboard.shareText(item.details) } }) {
|
||||
SelectionContainer(modifier = Modifier.verticalScroll(rememberScrollState()).navigationBarsPadding()) {
|
||||
val details = item.details
|
||||
.let {
|
||||
if (it.length < 100_000) it
|
||||
else it.substring(0, 100_000)
|
||||
}
|
||||
Text(details, modifier = Modifier.heightIn(max = 50_000.dp).padding(horizontal = DEFAULT_PADDING).padding(bottom = DEFAULT_PADDING))
|
||||
Box(Modifier.fillMaxHeight()) {
|
||||
SelectionContainer(modifier = Modifier.verticalScroll(rememberScrollState()).navigationBarsPadding()) {
|
||||
val details = item.details
|
||||
.let {
|
||||
if (it.length < 100_000) it
|
||||
else it.substring(0, 100_000)
|
||||
}
|
||||
Text(details, modifier = Modifier.heightIn(max = 50_000.dp).padding(horizontal = DEFAULT_PADDING).padding(bottom = DEFAULT_PADDING))
|
||||
}
|
||||
NavigationBarBackground()
|
||||
}
|
||||
}
|
||||
}.padding(horizontal = 8.dp, vertical = 4.dp)
|
||||
|
||||
+5
-5
@@ -704,7 +704,7 @@ fun ChatLayout(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ChatInfoToolbar(
|
||||
fun ColumnScope.ChatInfoToolbar(
|
||||
chatInfo: ChatInfo,
|
||||
back: () -> Unit,
|
||||
info: () -> Unit,
|
||||
@@ -866,12 +866,12 @@ fun ChatInfoToolbar(
|
||||
onSearchValueChanged = onSearchValueChanged,
|
||||
buttons = barButtons
|
||||
)
|
||||
Box(Modifier.fillMaxWidth().wrapContentSize(Alignment.TopEnd)) {
|
||||
Box(Modifier.align(Alignment.End)) {
|
||||
DefaultDropdownMenu(showMenu) {
|
||||
menuItems.forEach { it() }
|
||||
}
|
||||
}
|
||||
Divider()
|
||||
Divider(Modifier.background(MaterialTheme.colors.background))
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -1360,8 +1360,8 @@ fun BoxScope.FloatingButtons(
|
||||
onLongClick = { showDropDown.value = true }
|
||||
)
|
||||
|
||||
Box(Modifier.offset { IntOffset(maxWidth.value - DEFAULT_PADDING.roundToPx(), (24.dp + fabSize).roundToPx()) }) {
|
||||
DefaultDropdownMenu(showDropDown) {
|
||||
Box(Modifier.align(Alignment.TopEnd)) {
|
||||
DefaultDropdownMenu(showDropDown, offset = DpOffset(-DEFAULT_PADDING, 24.dp + fabSize)) {
|
||||
ItemAction(
|
||||
generalGetString(MR.strings.mark_read),
|
||||
painterResource(MR.images.ic_check),
|
||||
|
||||
-1
@@ -1045,7 +1045,6 @@ fun ComposeView(
|
||||
)
|
||||
}
|
||||
Spacer(Modifier.imePadding().navigationBarsPadding())
|
||||
// WindowInsets.ime.asPaddingValues().calculateBottomPadding()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -283,6 +283,7 @@ fun ModalData.GroupChatInfoLayout(
|
||||
if (s.isEmpty()) members else members.filter { m -> m.anyNameContains(s) }
|
||||
}
|
||||
}
|
||||
Box {
|
||||
LazyColumnWithScrollBar(
|
||||
Modifier
|
||||
.fillMaxWidth(),
|
||||
@@ -397,9 +398,11 @@ fun ModalData.GroupChatInfoLayout(
|
||||
}
|
||||
}
|
||||
SectionBottomSpacer()
|
||||
Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.systemBars))
|
||||
Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars))
|
||||
}
|
||||
}
|
||||
NavigationBarBackground()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
||||
+27
-10
@@ -12,6 +12,7 @@ import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.blur
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.focus.*
|
||||
import androidx.compose.ui.graphics.*
|
||||
@@ -587,13 +588,29 @@ enum class ScrollDirection {
|
||||
Up, Down, Idle
|
||||
}
|
||||
|
||||
private const val SYSTEM_BAR_BACKGROUND_ALPHA = 0.6f
|
||||
|
||||
@Composable
|
||||
fun StatusBarBackground() {
|
||||
Box(Modifier.background(MaterialTheme.colors.background).windowInsetsTopHeight(WindowInsets.statusBars))
|
||||
fun BoxScope.StatusBarBackground() {
|
||||
if (appPlatform.isAndroid) {
|
||||
val finalColor = MaterialTheme.colors.background.copy(SYSTEM_BAR_BACKGROUND_ALPHA)
|
||||
Box(Modifier.fillMaxWidth().windowInsetsTopHeight(WindowInsets.statusBars).background(finalColor))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ChatList(chatModel: ChatModel, searchText: MutableState<TextFieldValue>) {
|
||||
fun BoxScope.NavigationBarBackground(modifier: Modifier = Modifier, color: Color = MaterialTheme.colors.background) {
|
||||
val keyboardState = getKeyboardState()
|
||||
if (appPlatform.isAndroid && keyboardState.value == KeyboardState.Closed) {
|
||||
val barPadding = WindowInsets.navigationBars.asPaddingValues()
|
||||
val paddingBottom = barPadding.calculateBottomPadding()
|
||||
val finalColor = color.copy(SYSTEM_BAR_BACKGROUND_ALPHA)
|
||||
Box(modifier.align(Alignment.BottomStart).height(paddingBottom).fillMaxWidth().background(finalColor))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BoxScope.ChatList(chatModel: ChatModel, searchText: MutableState<TextFieldValue>) {
|
||||
val listState = rememberLazyListState(lazyListState.first, lazyListState.second)
|
||||
var scrollDirection by remember { mutableStateOf(ScrollDirection.Idle) }
|
||||
var previousIndex by remember { mutableStateOf(0) }
|
||||
@@ -631,10 +648,6 @@ private fun ChatList(chatModel: ChatModel, searchText: MutableState<TextFieldVal
|
||||
val searchShowingSimplexLink = remember { mutableStateOf(false) }
|
||||
val searchChatFilteredBySimplexLink = remember { mutableStateOf<String?>(null) }
|
||||
val chats = filteredChats(showUnreadAndFavorites, searchShowingSimplexLink, searchChatFilteredBySimplexLink, searchText.value.text, allChats.value.toList())
|
||||
Column {
|
||||
if (oneHandUI.value) {
|
||||
StatusBarBackground()
|
||||
}
|
||||
LazyColumnWithScrollBar(
|
||||
Modifier.fillMaxSize().then(if (!oneHandUI.value) Modifier.imePadding() else Modifier),
|
||||
listState,
|
||||
@@ -684,16 +697,20 @@ private fun ChatList(chatModel: ChatModel, searchText: MutableState<TextFieldVal
|
||||
ToggleChatListCard()
|
||||
}
|
||||
}
|
||||
if (!oneHandUI.value) {
|
||||
item { Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars)) }
|
||||
if (appPlatform.isAndroid) {
|
||||
item { Spacer(if (oneHandUI.value) Modifier.windowInsetsTopHeight(WindowInsets.statusBars) else Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chats.isEmpty() && chatModel.chats.value.isNotEmpty()) {
|
||||
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
Text(generalGetString(MR.strings.no_filtered_chats), color = MaterialTheme.colors.secondary)
|
||||
}
|
||||
}
|
||||
if (oneHandUI.value) {
|
||||
StatusBarBackground()
|
||||
} else {
|
||||
NavigationBarBackground()
|
||||
}
|
||||
}
|
||||
|
||||
fun filteredChats(
|
||||
|
||||
+18
-20
@@ -69,24 +69,22 @@ fun ShareListView(chatModel: ChatModel, stopped: Boolean) {
|
||||
}
|
||||
null -> {}
|
||||
}
|
||||
Box(Modifier.padding(it)) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
if (oneHandUI.value) {
|
||||
StatusBarBackground()
|
||||
}
|
||||
if (chatModel.chats.value.isNotEmpty()) {
|
||||
ShareList(
|
||||
chatModel,
|
||||
search = searchInList,
|
||||
isMediaOrFileAttachment = isMediaOrFileAttachment,
|
||||
isVoice = isVoice,
|
||||
hasSimplexLink = hasSimplexLink,
|
||||
)
|
||||
} else {
|
||||
EmptyList()
|
||||
}
|
||||
Box(Modifier.fillMaxSize().padding(it)) {
|
||||
if (chatModel.chats.value.isNotEmpty()) {
|
||||
ShareList(
|
||||
chatModel,
|
||||
search = searchInList,
|
||||
isMediaOrFileAttachment = isMediaOrFileAttachment,
|
||||
isVoice = isVoice,
|
||||
hasSimplexLink = hasSimplexLink,
|
||||
)
|
||||
} else {
|
||||
EmptyList()
|
||||
}
|
||||
if (oneHandUI.value) {
|
||||
StatusBarBackground()
|
||||
} else {
|
||||
NavigationBarBackground()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -228,9 +226,9 @@ private fun ShareList(
|
||||
hasSimplexLink = hasSimplexLink,
|
||||
)
|
||||
}
|
||||
if (!oneHandUI.value) {
|
||||
if (appPlatform.isAndroid) {
|
||||
item {
|
||||
Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars))
|
||||
Spacer(if (oneHandUI.value) Modifier.windowInsetsTopHeight(WindowInsets.statusBars) else Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-1
@@ -143,7 +143,6 @@ fun UserPicker(
|
||||
.fillMaxWidth()
|
||||
.then(if (newChat.isVisible()) Modifier.shadow(8.dp, clip = true) else Modifier)
|
||||
.background(if (appPlatform.isAndroid) MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, alpha = 1 - userPickerAlpha()) else MaterialTheme.colors.surface)
|
||||
.navigationBarsPadding()
|
||||
.padding(bottom = USER_PICKER_SECTION_SPACING - DEFAULT_MIN_SECTION_ITEM_PADDING_VERTICAL),
|
||||
pickerState = userPickerState
|
||||
) {
|
||||
|
||||
+1
-3
@@ -12,7 +12,6 @@ import androidx.compose.desktop.ui.tooling.preview.Preview
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.ui.draw.*
|
||||
import androidx.compose.ui.graphics.*
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.*
|
||||
import chat.simplex.common.platform.appPlatform
|
||||
@@ -100,8 +99,7 @@ fun CloseSheetBar(close: (() -> Unit)?, showClose: Boolean = true, tintColor: Co
|
||||
} else {
|
||||
Spacer(Modifier.weight(1f))
|
||||
}
|
||||
val direction = LocalLayoutDirection.current
|
||||
Row(Modifier.padding(end = WindowInsets.navigationBars.asPaddingValues().calculateEndPadding(direction))) {
|
||||
Row {
|
||||
endButtons()
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -102,7 +102,6 @@ fun AddGroupLayout(
|
||||
ColumnWithScrollBar(
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.padding(horizontal = DEFAULT_PADDING)
|
||||
) {
|
||||
AppBarTitle(stringResource(MR.strings.create_secret_group_title), hostDevice(rhId))
|
||||
Box(
|
||||
@@ -121,7 +120,7 @@ fun AddGroupLayout(
|
||||
}
|
||||
}
|
||||
}
|
||||
Row(Modifier.padding(bottom = DEFAULT_PADDING_HALF).fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
|
||||
Row(Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING, bottom = DEFAULT_PADDING_HALF).fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
|
||||
Text(
|
||||
stringResource(MR.strings.group_display_name_field),
|
||||
fontSize = 16.sp
|
||||
@@ -133,7 +132,9 @@ fun AddGroupLayout(
|
||||
}
|
||||
}
|
||||
}
|
||||
ProfileNameField(displayName, "", { isValidDisplayName(it.trim()) }, focusRequester)
|
||||
Box(Modifier.padding(horizontal = DEFAULT_PADDING)) {
|
||||
ProfileNameField(displayName, "", { isValidDisplayName(it.trim()) }, focusRequester)
|
||||
}
|
||||
Spacer(Modifier.height(8.dp))
|
||||
|
||||
SettingsActionItem(
|
||||
|
||||
+23
-10
@@ -30,8 +30,7 @@ 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
|
||||
import chat.simplex.common.views.chatlist.StatusBarBackground
|
||||
import chat.simplex.common.views.chatlist.*
|
||||
import chat.simplex.common.views.contacts.*
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import chat.simplex.res.MR
|
||||
@@ -183,10 +182,7 @@ private fun ModalData.NewChatSheetLayout(
|
||||
derivedStateOf { filterContactTypes(chatModel.chats.value, deletedContactTypes) }
|
||||
}
|
||||
|
||||
Column {
|
||||
if (oneHandUI.value) {
|
||||
StatusBarBackground()
|
||||
}
|
||||
Box {
|
||||
LazyColumnWithScrollBar(
|
||||
Modifier.fillMaxSize().then(if (!oneHandUI.value) Modifier.imePadding() else Modifier),
|
||||
listState,
|
||||
@@ -350,7 +346,17 @@ private fun ModalData.NewChatSheetLayout(
|
||||
}
|
||||
ContactListNavLinkView(chat, nextChatSelected, showDeletedChatIcon = true)
|
||||
}
|
||||
if (appPlatform.isAndroid) {
|
||||
item {
|
||||
Spacer(if (oneHandUI.value) Modifier.windowInsetsTopHeight(WindowInsets.statusBars) else Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars))
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oneHandUI.value) {
|
||||
StatusBarBackground()
|
||||
} else {
|
||||
NavigationBarBackground()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,10 +594,7 @@ private fun ModalData.DeletedContactsView(rh: RemoteHostInfo?, closeDeletedChats
|
||||
contactChats = allChats
|
||||
)
|
||||
|
||||
Column {
|
||||
if (oneHandUI.value) {
|
||||
StatusBarBackground()
|
||||
}
|
||||
Box {
|
||||
LazyColumnWithScrollBar(
|
||||
Modifier.fillMaxSize().then(if (!oneHandUI.value) Modifier.imePadding() else Modifier),
|
||||
contentPadding = contentPadding,
|
||||
@@ -644,7 +647,17 @@ private fun ModalData.DeletedContactsView(rh: RemoteHostInfo?, closeDeletedChats
|
||||
}
|
||||
ContactListNavLinkView(chat, nextChatSelected, showDeletedChatIcon = false)
|
||||
}
|
||||
if (appPlatform.isAndroid) {
|
||||
item {
|
||||
Spacer(if (oneHandUI.value) Modifier.windowInsetsTopHeight(WindowInsets.statusBars) else Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars))
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oneHandUI.value) {
|
||||
StatusBarBackground()
|
||||
} else {
|
||||
NavigationBarBackground()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user