Merge pull request #2264 from element-hq/renovate/io.nlopez.compose.rules-detekt-0.x

Update dependency io.nlopez.compose.rules:detekt to v0.3.10
This commit is contained in:
Benoit Marty 2024-01-23 18:55:02 +01:00 committed by GitHub
commit 3faaf208b4
18 changed files with 83 additions and 50 deletions

View file

@ -60,7 +60,7 @@ allprojects {
config.from(files("$rootDir/tools/detekt/detekt.yml")) config.from(files("$rootDir/tools/detekt/detekt.yml"))
} }
dependencies { dependencies {
detektPlugins("io.nlopez.compose.rules:detekt:0.3.9") detektPlugins("io.nlopez.compose.rules:detekt:0.3.10")
} }
// KtLint // KtLint

View file

@ -18,6 +18,8 @@ package io.element.android.features.ftue.impl.migration
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import io.element.android.features.ftue.impl.R import io.element.android.features.ftue.impl.R
@ -32,8 +34,9 @@ fun MigrationScreenView(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
if (migrationState.isMigrating.not()) { if (migrationState.isMigrating.not()) {
val latestOnMigrationFinished by rememberUpdatedState(onMigrationFinished)
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
onMigrationFinished() latestOnMigrationFinished()
} }
} }
SunsetPage( SunsetPage(

View file

@ -28,6 +28,8 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
@ -57,8 +59,9 @@ fun InviteListView(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
if (state.acceptedAction is AsyncData.Success) { if (state.acceptedAction is AsyncData.Success) {
val latestOnInviteAccepted by rememberUpdatedState(onInviteAccepted)
LaunchedEffect(state.acceptedAction) { LaunchedEffect(state.acceptedAction) {
onInviteAccepted(state.acceptedAction.data) latestOnInviteAccepted(state.acceptedAction.data)
} }
} }

View file

@ -18,6 +18,8 @@ package io.element.android.features.lockscreen.impl.unlock
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberUpdatedState
import io.element.android.features.lockscreen.impl.biometric.BiometricUnlockManager import io.element.android.features.lockscreen.impl.biometric.BiometricUnlockManager
import io.element.android.features.lockscreen.impl.biometric.DefaultBiometricUnlockCallback import io.element.android.features.lockscreen.impl.biometric.DefaultBiometricUnlockCallback
import io.element.android.features.lockscreen.impl.pin.DefaultPinCodeManagerCallback import io.element.android.features.lockscreen.impl.pin.DefaultPinCodeManagerCallback
@ -30,15 +32,16 @@ class PinUnlockHelper @Inject constructor(
) { ) {
@Composable @Composable
fun OnUnlockEffect(onUnlock: () -> Unit) { fun OnUnlockEffect(onUnlock: () -> Unit) {
val latestOnUnlock by rememberUpdatedState(onUnlock)
DisposableEffect(Unit) { DisposableEffect(Unit) {
val biometricUnlockCallback = object : DefaultBiometricUnlockCallback() { val biometricUnlockCallback = object : DefaultBiometricUnlockCallback() {
override fun onBiometricUnlockSuccess() { override fun onBiometricUnlockSuccess() {
onUnlock() latestOnUnlock()
} }
} }
val pinCodeVerifiedCallback = object : DefaultPinCodeManagerCallback() { val pinCodeVerifiedCallback = object : DefaultPinCodeManagerCallback() {
override fun onPinCodeVerified() { override fun onPinCodeVerified() {
onUnlock() latestOnUnlock()
} }
} }
biometricUnlockManager.addCallback(biometricUnlockCallback) biometricUnlockManager.addCallback(biometricUnlockCallback)

View file

@ -18,6 +18,8 @@ package io.element.android.features.login.impl.changeserver
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import io.element.android.features.login.impl.dialogs.SlidingSyncNotSupportedDialog import io.element.android.features.login.impl.dialogs.SlidingSyncNotSupportedDialog
@ -63,8 +65,11 @@ fun ChangeServerView(
} }
} }
is AsyncData.Loading -> ProgressDialog() is AsyncData.Loading -> ProgressDialog()
is AsyncData.Success -> LaunchedEffect(state.changeServerAction) { is AsyncData.Success -> {
onDone() val latestOnDone by rememberUpdatedState(onDone)
LaunchedEffect(state.changeServerAction) {
latestOnDone()
}
} }
AsyncData.Uninitialized -> Unit AsyncData.Uninitialized -> Unit
} }

View file

@ -18,6 +18,8 @@ package io.element.android.features.logout.impl.ui
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import io.element.android.features.logout.impl.R import io.element.android.features.logout.impl.R
import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncAction
@ -52,9 +54,11 @@ fun LogoutActionDialog(
onRetry = onForceLogoutClicked, onRetry = onForceLogoutClicked,
onDismiss = onDismissError, onDismiss = onDismissError,
) )
is AsyncAction.Success -> is AsyncAction.Success -> {
val latestOnSuccessLogout by rememberUpdatedState(onSuccessLogout)
LaunchedEffect(state) { LaunchedEffect(state) {
onSuccessLogout(state.data) latestOnSuccessLogout(state.data)
} }
}
} }
} }

View file

@ -41,8 +41,10 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Offset
@ -294,8 +296,11 @@ private fun AttachmentStateView(
) { ) {
when (state) { when (state) {
AttachmentsState.None -> Unit AttachmentsState.None -> Unit
is AttachmentsState.Previewing -> LaunchedEffect(state) { is AttachmentsState.Previewing -> {
onPreviewAttachments(state.attachments) val latestOnPreviewAttachments by rememberUpdatedState(onPreviewAttachments)
LaunchedEffect(state) {
latestOnPreviewAttachments(state.attachments)
}
} }
is AttachmentsState.Sending -> { is AttachmentsState.Sending -> {
ProgressDialog( ProgressDialog(

View file

@ -24,6 +24,8 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -57,8 +59,9 @@ fun AttachmentsPreviewView(
} }
if (state.sendActionState is SendActionState.Done) { if (state.sendActionState is SendActionState.Done) {
val latestOnDismiss by rememberUpdatedState(onDismiss)
LaunchedEffect(state.sendActionState) { LaunchedEffect(state.sendActionState) {
onDismiss() latestOnDismiss()
} }
} }

View file

@ -42,6 +42,7 @@ import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.alpha
@ -193,10 +194,11 @@ private fun BoxScope.TimelineScrollHelper(
} }
} }
val latestOnScrollFinishedAt by rememberUpdatedState(onScrollFinishedAt)
LaunchedEffect(isScrollFinished, isTimelineEmpty) { LaunchedEffect(isScrollFinished, isTimelineEmpty) {
if (isScrollFinished && !isTimelineEmpty) { if (isScrollFinished && !isTimelineEmpty) {
// Notify the parent composable about the first visible item index when scrolling finishes // Notify the parent composable about the first visible item index when scrolling finishes
onScrollFinishedAt(lazyListState.firstVisibleItemIndex) latestOnScrollFinishedAt(lazyListState.firstVisibleItemIndex)
} }
} }

View file

@ -18,6 +18,8 @@ package io.element.android.features.rageshake.api.detection
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -73,9 +75,10 @@ private fun TakeScreenshot(
onScreenshotTaken: (ImageResult) -> Unit onScreenshotTaken: (ImageResult) -> Unit
) { ) {
val view = LocalView.current val view = LocalView.current
val latestOnScreenshotTaken by rememberUpdatedState(onScreenshotTaken)
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
view.screenshot { view.screenshot {
onScreenshotTaken(it) latestOnScreenshotTaken(it)
} }
} }
} }

View file

@ -22,7 +22,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import io.element.android.features.securebackup.impl.loggerTagDisable import io.element.android.features.securebackup.impl.loggerTagDisable
import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.runCatchingUpdatingState import io.element.android.libraries.architecture.runCatchingUpdatingState
import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.encryption.EncryptionService
@ -36,14 +36,14 @@ class SecureBackupEnablePresenter @Inject constructor(
) : Presenter<SecureBackupEnableState> { ) : Presenter<SecureBackupEnableState> {
@Composable @Composable
override fun present(): SecureBackupEnableState { override fun present(): SecureBackupEnableState {
val enableAction = remember { mutableStateOf<AsyncData<Unit>>(AsyncData.Uninitialized) } val enableAction = remember { mutableStateOf<AsyncAction<Unit>>(AsyncAction.Uninitialized) }
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
fun handleEvents(event: SecureBackupEnableEvents) { fun handleEvents(event: SecureBackupEnableEvents) {
when (event) { when (event) {
is SecureBackupEnableEvents.EnableBackup -> is SecureBackupEnableEvents.EnableBackup ->
coroutineScope.enableBackup(enableAction) coroutineScope.enableBackup(enableAction)
SecureBackupEnableEvents.DismissDialog -> { SecureBackupEnableEvents.DismissDialog -> {
enableAction.value = AsyncData.Uninitialized enableAction.value = AsyncAction.Uninitialized
} }
} }
} }
@ -54,7 +54,7 @@ class SecureBackupEnablePresenter @Inject constructor(
) )
} }
private fun CoroutineScope.enableBackup(action: MutableState<AsyncData<Unit>>) = launch { private fun CoroutineScope.enableBackup(action: MutableState<AsyncAction<Unit>>) = launch {
suspend { suspend {
Timber.tag(loggerTagDisable.value).d("Calling encryptionService.enableBackups()") Timber.tag(loggerTagDisable.value).d("Calling encryptionService.enableBackups()")
encryptionService.enableBackups().getOrThrow() encryptionService.enableBackups().getOrThrow()

View file

@ -16,9 +16,9 @@
package io.element.android.features.securebackup.impl.enable package io.element.android.features.securebackup.impl.enable
import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.AsyncAction
data class SecureBackupEnableState( data class SecureBackupEnableState(
val enableAction: AsyncData<Unit>, val enableAction: AsyncAction<Unit>,
val eventSink: (SecureBackupEnableEvents) -> Unit val eventSink: (SecureBackupEnableEvents) -> Unit
) )

View file

@ -17,20 +17,20 @@
package io.element.android.features.securebackup.impl.enable package io.element.android.features.securebackup.impl.enable
import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.AsyncAction
open class SecureBackupEnableStateProvider : PreviewParameterProvider<SecureBackupEnableState> { open class SecureBackupEnableStateProvider : PreviewParameterProvider<SecureBackupEnableState> {
override val values: Sequence<SecureBackupEnableState> override val values: Sequence<SecureBackupEnableState>
get() = sequenceOf( get() = sequenceOf(
aSecureBackupEnableState(), aSecureBackupEnableState(),
aSecureBackupEnableState(enableAction = AsyncData.Loading()), aSecureBackupEnableState(enableAction = AsyncAction.Loading),
aSecureBackupEnableState(enableAction = AsyncData.Failure(Exception("Failed to enable"))), aSecureBackupEnableState(enableAction = AsyncAction.Failure(Exception("Failed to enable"))),
// Add other states here // Add other states here
) )
} }
fun aSecureBackupEnableState( fun aSecureBackupEnableState(
enableAction: AsyncData<Unit> = AsyncData.Uninitialized, enableAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
) = SecureBackupEnableState( ) = SecureBackupEnableState(
enableAction = enableAction, enableAction = enableAction,
eventSink = {} eventSink = {}

View file

@ -19,16 +19,14 @@ package io.element.android.features.securebackup.impl.enable
import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import io.element.android.features.securebackup.impl.R import io.element.android.features.securebackup.impl.R
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.designsystem.atomic.pages.FlowStepPage import io.element.android.libraries.designsystem.atomic.pages.FlowStepPage
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog import io.element.android.libraries.designsystem.components.async.AsyncActionView
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Button import io.element.android.libraries.designsystem.theme.components.Button
@ -41,11 +39,6 @@ fun SecureBackupEnableView(
onBackClicked: () -> Unit, onBackClicked: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
LaunchedEffect(state.enableAction) {
if (state.enableAction is AsyncData.Success) {
onDone()
}
}
FlowStepPage( FlowStepPage(
modifier = modifier, modifier = modifier,
onBackClicked = onBackClicked, onBackClicked = onBackClicked,
@ -53,12 +46,12 @@ fun SecureBackupEnableView(
iconVector = ImageVector.vectorResource(CommonDrawables.ic_key), iconVector = ImageVector.vectorResource(CommonDrawables.ic_key),
buttons = { Buttons(state = state) } buttons = { Buttons(state = state) }
) )
if (state.enableAction is AsyncData.Failure) { AsyncActionView(
ErrorDialog( async = state.enableAction,
content = state.enableAction.error.let { it.message ?: it.toString() }, progressDialog = { },
onDismiss = { state.eventSink.invoke(SecureBackupEnableEvents.DismissDialog) }, onSuccess = { onDone() },
) onErrorDismiss = { state.eventSink.invoke(SecureBackupEnableEvents.DismissDialog) }
} )
} }
@Composable @Composable

View file

@ -20,7 +20,7 @@ import app.cash.molecule.RecompositionMode
import app.cash.molecule.moleculeFlow import app.cash.molecule.moleculeFlow
import app.cash.turbine.test import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.encryption.EncryptionService
import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.AN_EXCEPTION
import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
@ -40,7 +40,7 @@ class SecureBackupEnablePresenterTest {
presenter.present() presenter.present()
}.test { }.test {
val initialState = awaitItem() val initialState = awaitItem()
assertThat(initialState.enableAction).isEqualTo(AsyncData.Uninitialized) assertThat(initialState.enableAction).isEqualTo(AsyncAction.Uninitialized)
} }
} }
@ -53,9 +53,9 @@ class SecureBackupEnablePresenterTest {
val initialState = awaitItem() val initialState = awaitItem()
initialState.eventSink(SecureBackupEnableEvents.EnableBackup) initialState.eventSink(SecureBackupEnableEvents.EnableBackup)
val loadingState = awaitItem() val loadingState = awaitItem()
assertThat(loadingState.enableAction).isInstanceOf(AsyncData.Loading::class.java) assertThat(loadingState.enableAction).isInstanceOf(AsyncAction.Loading::class.java)
val finalState = awaitItem() val finalState = awaitItem()
assertThat(finalState.enableAction).isEqualTo(AsyncData.Success(Unit)) assertThat(finalState.enableAction).isEqualTo(AsyncAction.Success(Unit))
} }
} }
@ -70,12 +70,12 @@ class SecureBackupEnablePresenterTest {
val initialState = awaitItem() val initialState = awaitItem()
initialState.eventSink(SecureBackupEnableEvents.EnableBackup) initialState.eventSink(SecureBackupEnableEvents.EnableBackup)
val loadingState = awaitItem() val loadingState = awaitItem()
assertThat(loadingState.enableAction).isInstanceOf(AsyncData.Loading::class.java) assertThat(loadingState.enableAction).isInstanceOf(AsyncAction.Loading::class.java)
val errorState = awaitItem() val errorState = awaitItem()
assertThat(errorState.enableAction).isEqualTo(AsyncData.Failure<Unit>(AN_EXCEPTION)) assertThat(errorState.enableAction).isEqualTo(AsyncAction.Failure(AN_EXCEPTION))
errorState.eventSink(SecureBackupEnableEvents.DismissDialog) errorState.eventSink(SecureBackupEnableEvents.DismissDialog)
val finalState = awaitItem() val finalState = awaitItem()
assertThat(finalState.enableAction).isEqualTo(AsyncData.Uninitialized) assertThat(finalState.enableAction).isEqualTo(AsyncAction.Uninitialized)
} }
} }

View file

@ -18,6 +18,8 @@ package io.element.android.libraries.designsystem.components.async
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.designsystem.components.ProgressDialog import io.element.android.libraries.designsystem.components.ProgressDialog
@ -67,8 +69,9 @@ fun <T> AsyncActionView(
} }
} }
is AsyncAction.Success -> { is AsyncAction.Success -> {
val latestOnSuccess by rememberUpdatedState(onSuccess)
LaunchedEffect(async) { LaunchedEffect(async) {
onSuccess(async.data) latestOnSuccess(async.data)
} }
} }
} }

View file

@ -18,6 +18,8 @@ package io.element.android.libraries.textcomposer
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.platform.LocalView import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
import io.element.android.libraries.androidutils.ui.awaitWindowFocus import io.element.android.libraries.androidutils.ui.awaitWindowFocus
@ -40,8 +42,10 @@ internal fun <T> SoftKeyboardEffect(
predicate: (T) -> Boolean, predicate: (T) -> Boolean,
) { ) {
val view = LocalView.current val view = LocalView.current
val latestOnRequestFocus by rememberUpdatedState(onRequestFocus)
val latestPredicate by rememberUpdatedState(predicate)
LaunchedEffect(key) { LaunchedEffect(key) {
if (predicate(key)) { if (latestPredicate(key)) {
// Await window focus in case returning from a dialog // Await window focus in case returning from a dialog
view.awaitWindowFocus() view.awaitWindowFocus()
@ -49,7 +53,7 @@ internal fun <T> SoftKeyboardEffect(
view.showKeyboard(andRequestFocus = true) view.showKeyboard(andRequestFocus = true)
// Refocus to the correct view // Refocus to the correct view
onRequestFocus() latestOnRequestFocus()
} }
} }
} }

View file

@ -42,6 +42,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
@ -274,12 +275,13 @@ fun TextComposer(
} }
val menuAction = state.menuAction val menuAction = state.menuAction
val latestOnSuggestionReceived by rememberUpdatedState(onSuggestionReceived)
LaunchedEffect(menuAction) { LaunchedEffect(menuAction) {
if (menuAction is MenuAction.Suggestion) { if (menuAction is MenuAction.Suggestion) {
val suggestion = Suggestion(menuAction.suggestionPattern) val suggestion = Suggestion(menuAction.suggestionPattern)
onSuggestionReceived(suggestion) latestOnSuggestionReceived(suggestion)
} else { } else {
onSuggestionReceived(null) latestOnSuggestionReceived(null)
} }
} }
} }