mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-10-24 23:33:05 +00:00
android: stop orientation locks from stopping recording and looping migration
Tap-to-stop recording locked the orientation by mapping the current rotation to portrait/landscape as if rotation 0 were portrait, which is wrong for every rotation on displays that are landscape by default, so Android changed orientation (on Waydroid: reshaped the window) and recreated MainActivity and the recording stopped. Migration forced portrait; on a display that is landscape by default the activity was recreated, the lock was released in onDispose during that recreation, and the app went back to landscape - an endless recreate loop (reproduced on Waydroid; expected on landscape-default displays). Both now lock the current orientation (SCREEN_ORIENTATION_LOCKED), which does not itself change the orientation, so the activity is not recreated. On Android in landscape, migration's progress ring is sized to the window space between the top of its box and the bottom bars instead of the window width, and its text shrinks with it, so it is visible without scrolling (very short windows keep a 120dp minimum).
This commit is contained in:
1 parent
139ce5f8cc
commit
8f25c5c73c
4 files changed
+39
-19
No files matched your search
@@ -1,6 +1,5 @@
|
||||
package chat.simplex.app
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.*
|
||||
import android.content.Context
|
||||
import chat.simplex.common.platform.Log
|
||||
@@ -361,14 +360,12 @@ class SimplexApp: Application(), LifecycleEventObserver {
|
||||
|
||||
override suspend fun androidUnfinishedBadgePurchases(): List<BadgePurchaseOutcome> = unfinishedBadgePurchases()
|
||||
|
||||
@SuppressLint("SourceLockedOrientationActivity")
|
||||
@Composable
|
||||
override fun androidLockPortraitOrientation() {
|
||||
val context = LocalContext.current
|
||||
DisposableEffect(Unit) {
|
||||
val activity = context as? Activity ?: return@DisposableEffect onDispose {}
|
||||
// Lock orientation to portrait in order to have good experience with calls
|
||||
activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED
|
||||
onDispose {
|
||||
// Unlock orientation
|
||||
activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
||||
|
||||
+1
-8
@@ -27,14 +27,7 @@ actual fun LockToCurrentOrientationUntilDispose() {
|
||||
val context = LocalContext1.current
|
||||
DisposableEffect(Unit) {
|
||||
val activity = (context as Activity?) ?: return@DisposableEffect onDispose {}
|
||||
val manager = context.getSystemService(Activity.WINDOW_SERVICE) as WindowManager
|
||||
val rotation = if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) manager.defaultDisplay.rotation else activity.display?.rotation
|
||||
activity.requestedOrientation = when (rotation) {
|
||||
Surface.ROTATION_90 -> ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
||||
Surface.ROTATION_180 -> ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT
|
||||
Surface.ROTATION_270 -> ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
|
||||
else -> ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
}
|
||||
activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED
|
||||
// Unlock orientation
|
||||
onDispose { activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED }
|
||||
}
|
||||
|
||||
+36
-6
@@ -11,6 +11,10 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.rotate
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.layout.positionInWindow
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalWindowInfo
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
@@ -29,6 +33,7 @@ import chat.simplex.common.views.database.*
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import chat.simplex.common.views.newchat.LinkTextView
|
||||
import chat.simplex.common.views.newchat.SimpleXLinkQRCode
|
||||
import chat.simplex.common.views.onboarding.OnboardingStage
|
||||
import chat.simplex.common.views.usersettings.*
|
||||
import chat.simplex.res.*
|
||||
import dev.icerock.moko.resources.compose.painterResource
|
||||
@@ -427,19 +432,44 @@ private fun ProgressView() {
|
||||
|
||||
@Composable
|
||||
fun LargeProgressView(value: Float, title: String, description: String) {
|
||||
Box(Modifier.padding(DEFAULT_PADDING).fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
val landscape = !appPlatform.isDesktop && windowWidth() > windowHeight()
|
||||
val scrollState = LocalAppBarHandler.current?.scrollState
|
||||
val density = LocalDensity.current
|
||||
val windowPx = LocalWindowInfo.current.containerSize.height
|
||||
val oneHandUI = remember { derivedStateOf { appPrefs.onboardingStage.state.value == OnboardingStage.OnboardingComplete && appPrefs.oneHandUI.state.value } }
|
||||
val bottomBarsPx = if (oneHandUI.value) {
|
||||
WindowInsets.navigationBars.getBottom(density) + with(density) { (AppBarHeight * fontSizeSqrtMultiplier).roundToPx() }
|
||||
} else {
|
||||
WindowInsets.systemBars.getBottom(density)
|
||||
}
|
||||
var contentTopPx by remember { mutableStateOf<Float?>(null) }
|
||||
val size = when {
|
||||
appPlatform.isDesktop -> DEFAULT_START_MODAL_WIDTH * fontSizeSqrtMultiplier
|
||||
landscape -> contentTopPx?.let { top ->
|
||||
(with(density) { (windowPx - top - bottomBarsPx).toDp() } - DEFAULT_PADDING * 2).coerceAtLeast(120.dp)
|
||||
} ?: 120.dp
|
||||
else -> windowWidth() - DEFAULT_PADDING * 2
|
||||
}
|
||||
Box(
|
||||
Modifier
|
||||
.onGloballyPositioned { if (landscape) contentTopPx = it.positionInWindow().y + (scrollState?.value ?: 0) }
|
||||
.padding(DEFAULT_PADDING)
|
||||
.then(if (landscape) Modifier.fillMaxWidth() else Modifier.fillMaxSize()),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
CircularProgressIndicator(
|
||||
progress = value,
|
||||
(if (appPlatform.isDesktop) Modifier.size(DEFAULT_START_MODAL_WIDTH * fontSizeSqrtMultiplier) else Modifier.size(windowWidth() - DEFAULT_PADDING *
|
||||
2))
|
||||
Modifier.size(size)
|
||||
.rotate(-90f),
|
||||
color = MaterialTheme.colors.primary,
|
||||
strokeWidth = 25.dp
|
||||
)
|
||||
val textScale = if (landscape) (size / 300.dp).coerceIn(0.4f, 1f) else 1f
|
||||
val descriptionStyle = MaterialTheme.typography.subtitle1.let { it.copy(fontSize = it.fontSize * textScale) }
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Text(description, color = Color.Transparent)
|
||||
Text(title, style = MaterialTheme.typography.h1.copy(fontSize = 50.sp, fontWeight = FontWeight.Bold), color = MaterialTheme.colors.primary)
|
||||
Text(description, style = MaterialTheme.typography.subtitle1)
|
||||
Text(description, style = LocalTextStyle.current.let { it.copy(fontSize = it.fontSize * textScale) }, color = Color.Transparent)
|
||||
Text(title, style = MaterialTheme.typography.h1.copy(fontSize = 50.sp * textScale, fontWeight = FontWeight.Bold), color = MaterialTheme.colors.primary)
|
||||
Text(description, style = descriptionStyle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,7 +380,7 @@ var platform: PlatformInterface = object : PlatformInterface {}
|
||||
| `androidApiLevel` | `null` | `Build.VERSION.SDK_INT` |
|
||||
| `androidIsPlayStoreBuild` | `false` | `BuildConfig.PLAY_STORE` |
|
||||
| `androidLoadPlayStoreCountry()` | no-op | Request the Play account country (google flavor only) |
|
||||
| `androidLockPortraitOrientation()` | no-op | Lock to `SCREEN_ORIENTATION_PORTRAIT` |
|
||||
| `androidLockPortraitOrientation()` | no-op | Lock to `SCREEN_ORIENTATION_LOCKED` (current orientation) |
|
||||
| `androidAskToAllowBackgroundCalls()` | `true` | Show battery restriction dialog |
|
||||
| `desktopShowAppUpdateNotice()` | no-op | Show update notice (Desktop only) |
|
||||
|
||||
|
||||
Reference in new issue
Block a user