Fix detekt issue:
Lambda parameters in a @Composable that are referenced directly inside of restarting effects can cause issues or unpredictable behavior. If restarting the effect is ok, you can add the reference to this parameter as a key in that effect, so when the parameter changes, a new effect is created. However, if the effect is not to be restarted, you will need to use `rememberUpdatedState` on the parameter and use its result in the effect. See https://mrmans0n.github.io/compose-rules/rules/#be-mindful-of-the-arguments-you-use-inside-of-a-restarting-effect for more information. [LambdaParameterInRestartableEffect]
This commit is contained in:
committed by
Benoit Marty
parent
fa09b70411
commit
cff076b508
@@ -32,7 +32,7 @@ fun MigrationScreenView(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
if (migrationState.isMigrating.not()) {
|
||||
LaunchedEffect(Unit) {
|
||||
LaunchedEffect(onMigrationFinished) {
|
||||
onMigrationFinished()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ fun InviteListView(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
if (state.acceptedAction is AsyncData.Success) {
|
||||
LaunchedEffect(state.acceptedAction) {
|
||||
LaunchedEffect(state.acceptedAction, onInviteAccepted) {
|
||||
onInviteAccepted(state.acceptedAction.data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ package io.element.android.features.lockscreen.impl.unlock
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
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.DefaultBiometricUnlockCallback
|
||||
import io.element.android.features.lockscreen.impl.pin.DefaultPinCodeManagerCallback
|
||||
@@ -30,15 +32,16 @@ class PinUnlockHelper @Inject constructor(
|
||||
) {
|
||||
@Composable
|
||||
fun OnUnlockEffect(onUnlock: () -> Unit) {
|
||||
val latestOnUnlock by rememberUpdatedState(onUnlock)
|
||||
DisposableEffect(Unit) {
|
||||
val biometricUnlockCallback = object : DefaultBiometricUnlockCallback() {
|
||||
override fun onBiometricUnlockSuccess() {
|
||||
onUnlock()
|
||||
latestOnUnlock()
|
||||
}
|
||||
}
|
||||
val pinCodeVerifiedCallback = object : DefaultPinCodeManagerCallback() {
|
||||
override fun onPinCodeVerified() {
|
||||
onUnlock()
|
||||
latestOnUnlock()
|
||||
}
|
||||
}
|
||||
biometricUnlockManager.addCallback(biometricUnlockCallback)
|
||||
|
||||
@@ -63,7 +63,7 @@ fun ChangeServerView(
|
||||
}
|
||||
}
|
||||
is AsyncData.Loading -> ProgressDialog()
|
||||
is AsyncData.Success -> LaunchedEffect(state.changeServerAction) {
|
||||
is AsyncData.Success -> LaunchedEffect(state.changeServerAction, onDone) {
|
||||
onDone()
|
||||
}
|
||||
AsyncData.Uninitialized -> Unit
|
||||
|
||||
@@ -53,7 +53,7 @@ fun LogoutActionDialog(
|
||||
onDismiss = onDismissError,
|
||||
)
|
||||
is AsyncAction.Success ->
|
||||
LaunchedEffect(state) {
|
||||
LaunchedEffect(state, onSuccessLogout) {
|
||||
onSuccessLogout(state.data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ private fun AttachmentStateView(
|
||||
) {
|
||||
when (state) {
|
||||
AttachmentsState.None -> Unit
|
||||
is AttachmentsState.Previewing -> LaunchedEffect(state) {
|
||||
is AttachmentsState.Previewing -> LaunchedEffect(state, onPreviewAttachments) {
|
||||
onPreviewAttachments(state.attachments)
|
||||
}
|
||||
is AttachmentsState.Sending -> {
|
||||
|
||||
@@ -57,7 +57,7 @@ fun AttachmentsPreviewView(
|
||||
}
|
||||
|
||||
if (state.sendActionState is SendActionState.Done) {
|
||||
LaunchedEffect(state.sendActionState) {
|
||||
LaunchedEffect(state.sendActionState, onDismiss) {
|
||||
onDismiss()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
@@ -193,10 +194,11 @@ private fun BoxScope.TimelineScrollHelper(
|
||||
}
|
||||
}
|
||||
|
||||
val latestOnScrollFinishedAt by rememberUpdatedState(onScrollFinishedAt)
|
||||
LaunchedEffect(isScrollFinished, isTimelineEmpty) {
|
||||
if (isScrollFinished && !isTimelineEmpty) {
|
||||
// Notify the parent composable about the first visible item index when scrolling finishes
|
||||
onScrollFinishedAt(lazyListState.firstVisibleItemIndex)
|
||||
latestOnScrollFinishedAt(lazyListState.firstVisibleItemIndex)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ private fun TakeScreenshot(
|
||||
onScreenshotTaken: (ImageResult) -> Unit
|
||||
) {
|
||||
val view = LocalView.current
|
||||
LaunchedEffect(Unit) {
|
||||
LaunchedEffect(onScreenshotTaken) {
|
||||
view.screenshot {
|
||||
onScreenshotTaken(it)
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ fun <T> AsyncActionView(
|
||||
}
|
||||
}
|
||||
is AsyncAction.Success -> {
|
||||
LaunchedEffect(async) {
|
||||
LaunchedEffect(async, onSuccess) {
|
||||
onSuccess(async.data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ package io.element.android.libraries.textcomposer
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
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.viewinterop.AndroidView
|
||||
import io.element.android.libraries.androidutils.ui.awaitWindowFocus
|
||||
@@ -40,7 +42,8 @@ internal fun <T> SoftKeyboardEffect(
|
||||
predicate: (T) -> Boolean,
|
||||
) {
|
||||
val view = LocalView.current
|
||||
LaunchedEffect(key) {
|
||||
val latestOnRequestFocus by rememberUpdatedState(onRequestFocus)
|
||||
LaunchedEffect(key, predicate) {
|
||||
if (predicate(key)) {
|
||||
// Await window focus in case returning from a dialog
|
||||
view.awaitWindowFocus()
|
||||
@@ -49,7 +52,7 @@ internal fun <T> SoftKeyboardEffect(
|
||||
view.showKeyboard(andRequestFocus = true)
|
||||
|
||||
// Refocus to the correct view
|
||||
onRequestFocus()
|
||||
latestOnRequestFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
@@ -274,12 +275,13 @@ fun TextComposer(
|
||||
}
|
||||
|
||||
val menuAction = state.menuAction
|
||||
val latestOnSuggestionReceived by rememberUpdatedState(onSuggestionReceived)
|
||||
LaunchedEffect(menuAction) {
|
||||
if (menuAction is MenuAction.Suggestion) {
|
||||
val suggestion = Suggestion(menuAction.suggestionPattern)
|
||||
onSuggestionReceived(suggestion)
|
||||
latestOnSuggestionReceived(suggestion)
|
||||
} else {
|
||||
onSuggestionReceived(null)
|
||||
latestOnSuggestionReceived(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user