Merge pull request #6846 from element-hq/fix/downgrade-detekt

Downgrade detekt compose rules
This commit is contained in:
ganfra
2026-05-28 12:09:15 +02:00
committed by GitHub
24 changed files with 82 additions and 34 deletions
+3 -3
View File
@@ -30,7 +30,7 @@ tasks.register<Delete>("clean").configure {
delete(rootProject.layout.buildDirectory) delete(rootProject.layout.buildDirectory)
} }
private val ktLintVersion = the<LibrariesForLibs>().versions.ktlint.get() private val catalog = the<LibrariesForLibs>()
allprojects { allprojects {
// Detekt // Detekt
@@ -46,7 +46,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.5.8") detektPlugins(catalog.detekt.compose.rules)
detektPlugins(project(":tests:detekt-rules")) detektPlugins(project(":tests:detekt-rules"))
} }
@@ -64,7 +64,7 @@ allprojects {
// See https://github.com/JLLeitschuh/ktlint-gradle#configuration // See https://github.com/JLLeitschuh/ktlint-gradle#configuration
configure<org.jlleitschuh.gradle.ktlint.KtlintExtension> { configure<org.jlleitschuh.gradle.ktlint.KtlintExtension> {
version = ktLintVersion version = catalog.versions.ktlint.get()
android = true android = true
ignoreFailures = false ignoreFailures = false
enableExperimentalRules = true enableExperimentalRules = true
@@ -10,6 +10,7 @@ package io.element.android.features.home.impl.components
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
@@ -160,7 +161,7 @@ fun HomeTopBar(
} }
@Composable @Composable
private fun RoomListMenuItems( private fun RowScope.RoomListMenuItems(
onToggleSearch: () -> Unit, onToggleSearch: () -> Unit,
onMenuActionClick: (RoomListMenuAction) -> Unit, onMenuActionClick: (RoomListMenuAction) -> Unit,
canReportBug: Boolean, canReportBug: Boolean,
@@ -48,6 +48,7 @@ import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.matrix.api.spaces.SpaceServiceFilter import io.element.android.libraries.matrix.api.spaces.SpaceServiceFilter
import io.element.android.libraries.matrix.ui.model.getAvatarData import io.element.android.libraries.matrix.ui.model.getAvatarData
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
import kotlinx.collections.immutable.ImmutableList
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@@ -93,7 +94,7 @@ fun SpaceFiltersView(
SpaceFiltersBottomSheetContent( SpaceFiltersBottomSheetContent(
filters = state.visibleFilters, filters = state.visibleFilters,
searchQuery = state.searchQuery, searchQuery = state.searchQuery,
onFilterSelected = { filter -> onSelectFilter = { filter ->
state.eventSink(SpaceFiltersEvent.Selecting.SelectFilter(filter)) state.eventSink(SpaceFiltersEvent.Selecting.SelectFilter(filter))
} }
) )
@@ -105,9 +106,9 @@ fun SpaceFiltersView(
@Composable @Composable
private fun SpaceFiltersBottomSheetContent( private fun SpaceFiltersBottomSheetContent(
filters: List<SpaceServiceFilter>, filters: ImmutableList<SpaceServiceFilter>,
searchQuery: TextFieldState, searchQuery: TextFieldState,
onFilterSelected: (SpaceServiceFilter) -> Unit, onSelectFilter: (SpaceServiceFilter) -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
Column( Column(
@@ -133,7 +134,7 @@ private fun SpaceFiltersBottomSheetContent(
items(filters) { filter -> items(filters) { filter ->
SpaceFilterItem( SpaceFilterItem(
filter = filter, filter = filter,
onClick = { onFilterSelected(filter) } onClick = { onSelectFilter(filter) }
) )
} }
} }
@@ -147,7 +147,7 @@ private fun DoneButton(
} }
@Composable @Composable
private fun Buttons( private fun ColumnScope.Buttons(
onRetry: () -> Unit, onRetry: () -> Unit,
onCancel: () -> Unit, onCancel: () -> Unit,
) { ) {
@@ -14,6 +14,7 @@ import io.element.android.compound.theme.ElementTheme
import io.element.android.features.location.api.Location import io.element.android.features.location.api.Location
import io.element.android.libraries.designsystem.components.PinVariant import io.element.android.libraries.designsystem.components.PinVariant
import io.element.android.libraries.designsystem.components.rememberLocationPinBitmap import io.element.android.libraries.designsystem.components.rememberLocationPinBitmap
import kotlinx.collections.immutable.ImmutableList
import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.JsonPrimitive
import org.maplibre.compose.expressions.dsl.and import org.maplibre.compose.expressions.dsl.and
import org.maplibre.compose.expressions.dsl.asString import org.maplibre.compose.expressions.dsl.asString
@@ -66,7 +67,7 @@ data class LocationMarkerData(
*/ */
@Composable @Composable
fun LocationPinMarkers( fun LocationPinMarkers(
markers: List<LocationMarkerData>, markers: ImmutableList<LocationMarkerData>,
onMarkerClick: ((LocationMarkerData) -> Unit)? = null, onMarkerClick: ((LocationMarkerData) -> Unit)? = null,
onClusterClick: ((Position) -> Unit)? = null, onClusterClick: ((Position) -> Unit)? = null,
) { ) {
@@ -26,6 +26,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue 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.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@@ -180,6 +181,7 @@ private fun StartLiveLocationActionView(
onActionSuccess: () -> Unit, onActionSuccess: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
val updatedOnActionSuccess by rememberUpdatedState(onActionSuccess)
Box(modifier = modifier) { Box(modifier = modifier) {
val asyncIndicatorState = rememberAsyncIndicatorState() val asyncIndicatorState = rememberAsyncIndicatorState()
AsyncIndicatorHost(state = asyncIndicatorState) AsyncIndicatorHost(state = asyncIndicatorState)
@@ -202,7 +204,7 @@ private fun StartLiveLocationActionView(
} }
} }
is AsyncAction.Success -> { is AsyncAction.Success -> {
LaunchedEffect(action) { onActionSuccess() } LaunchedEffect(action) { updatedOnActionSuccess() }
} }
else -> Unit else -> Unit
} }
@@ -50,6 +50,7 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.maplibre.compose.camera.CameraMoveReason import org.maplibre.compose.camera.CameraMoveReason
import org.maplibre.compose.camera.CameraPosition import org.maplibre.compose.camera.CameraPosition
@@ -172,7 +173,7 @@ fun ShowLocationView(
trackUserLocation = state.isTrackMyLocation trackUserLocation = state.isTrackMyLocation
) )
val markers = remember(state.locationShares) { val markers = remember(state.locationShares) {
state.locationShares.map { it.toMarkerData() } state.locationShares.map { it.toMarkerData() }.toImmutableList()
} }
LocationPinMarkers(markers) LocationPinMarkers(markers)
}, },
@@ -125,7 +125,7 @@ private fun Content(errorScreenType: QrCodeErrorScreenType) {
} }
@Composable @Composable
private fun Buttons( private fun ColumnScope.Buttons(
onRetry: () -> Unit, onRetry: () -> Unit,
onCancel: () -> Unit, onCancel: () -> Unit,
) { ) {
@@ -17,6 +17,7 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.consumeWindowInsets
@@ -412,7 +413,7 @@ fun MessagesView(
} }
@Composable @Composable
internal fun MessagesMenuActions( internal fun RowScope.MessagesMenuActions(
displayThreads: Boolean, displayThreads: Boolean,
roomCallState: RoomCallState, roomCallState: RoomCallState,
onJoinCallClick: (isAudioCall: Boolean) -> Unit, onJoinCallClick: (isAudioCall: Boolean) -> Unit,
@@ -28,6 +28,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.res.stringResource import androidx.compose.ui.res.stringResource
@@ -157,6 +158,7 @@ private fun ScrollHelper(
listState: LazyListState, listState: LazyListState,
onPaginate: () -> Unit, onPaginate: () -> Unit,
) { ) {
val updatedOnPaginate by rememberUpdatedState(onPaginate)
val lastVisibleItemIndex by remember { val lastVisibleItemIndex by remember {
derivedStateOf { listState.firstVisibleItemIndex + listState.layoutInfo.visibleItemsInfo.size - 1 } derivedStateOf { listState.firstVisibleItemIndex + listState.layoutInfo.visibleItemsInfo.size - 1 }
} }
@@ -168,7 +170,7 @@ private fun ScrollHelper(
} }
LaunchedEffect(needsPagination, lastVisibleItemIndex) { LaunchedEffect(needsPagination, lastVisibleItemIndex) {
if (needsPagination) { if (needsPagination) {
onPaginate() updatedOnPaginate()
delay(400L) delay(400L)
} }
} }
@@ -9,7 +9,9 @@
package io.element.android.features.messages.impl.timeline.model.event package io.element.android.features.messages.impl.timeline.model.event
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.produceState import androidx.compose.runtime.produceState
import androidx.compose.runtime.rememberUpdatedState
import io.element.android.features.location.api.Location import io.element.android.features.location.api.Location
import io.element.android.libraries.designsystem.components.PinVariant import io.element.android.libraries.designsystem.components.PinVariant
import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarData
@@ -103,8 +105,9 @@ private fun rememberIsLiveLocationActive(
mode: TimelineItemLocationContent.Mode.Live, mode: TimelineItemLocationContent.Mode.Live,
currentTimeMillis: () -> Long, currentTimeMillis: () -> Long,
): Boolean { ): Boolean {
val updatedCurrentTimeMillis by rememberUpdatedState(currentTimeMillis)
fun TimelineItemLocationContent.Mode.Live.isActive(): Boolean { fun TimelineItemLocationContent.Mode.Live.isActive(): Boolean {
return isActive && endTimestamp > currentTimeMillis() return isActive && endTimestamp > updatedCurrentTimeMillis()
} }
return produceState( return produceState(
initialValue = mode.isActive(), initialValue = mode.isActive(),
@@ -112,7 +115,7 @@ private fun rememberIsLiveLocationActive(
key2 = mode.isActive, key2 = mode.isActive,
) { ) {
if (mode.isActive) { if (mode.isActive) {
val remainingMillis = mode.endTimestamp - currentTimeMillis() val remainingMillis = mode.endTimestamp - updatedCurrentTimeMillis()
delay(remainingMillis) delay(remainingMillis)
} }
value = false value = false
@@ -206,7 +206,7 @@ fun AdvancedSettingsView(
if (state.liveLocationMinimumDistanceUpdate != null) { if (state.liveLocationMinimumDistanceUpdate != null) {
LiveLocationUpdatesSection( LiveLocationUpdatesSection(
value = state.liveLocationMinimumDistanceUpdate, value = state.liveLocationMinimumDistanceUpdate,
onValueSaved = { value -> onSaveValue = { value ->
state.eventSink(AdvancedSettingsEvents.SetLiveLocationMinimumDistanceUpdate(value)) state.eventSink(AdvancedSettingsEvents.SetLiveLocationMinimumDistanceUpdate(value))
}, },
onOpenAppPermissionsClick = onOpenAppSettingsClick, onOpenAppPermissionsClick = onOpenAppSettingsClick,
@@ -339,7 +339,7 @@ private fun ModerationAndSafety(
@Composable @Composable
private fun LiveLocationUpdatesSection( private fun LiveLocationUpdatesSection(
value: Int, value: Int,
onValueSaved: (Int) -> Unit, onSaveValue: (Int) -> Unit,
onOpenAppPermissionsClick: () -> Unit, onOpenAppPermissionsClick: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
@@ -382,7 +382,7 @@ private fun LiveLocationUpdatesSection(
value = sliderValue.toFloat(), value = sliderValue.toFloat(),
onValueChange = { sliderValue = it.roundToInt() }, onValueChange = { sliderValue = it.roundToInt() },
onValueChangeFinish = { onValueChangeFinish = {
onValueSaved(sliderValue) onSaveValue(sliderValue)
}, },
valueRange = valueRange, valueRange = valueRange,
colors = SliderDefaults.colors( colors = SliderDefaults.colors(
@@ -206,7 +206,7 @@ fun RoomDetailsView(
), ),
trailingContent = ListItemContent.Custom { trailingContent = ListItemContent.Custom {
Box( Box(
modifier = modifier modifier = Modifier
.size(8.dp) .size(8.dp)
.clip(CircleShape) .clip(CircleShape)
.background(ElementTheme.colors.iconAccentPrimary) .background(ElementTheme.colors.iconAccentPrimary)
@@ -41,7 +41,7 @@ class AddRoomToSpaceNode(
AddRoomToSpaceView( AddRoomToSpaceView(
state = state, state = state,
onBackClick = callback::onFinish, onBackClick = callback::onFinish,
onRoomsAdded = callback::onFinish, onAddRoom = callback::onFinish,
modifier = modifier modifier = modifier
) )
} }
@@ -23,6 +23,8 @@ import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
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.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
@@ -57,9 +59,10 @@ import kotlinx.collections.immutable.toImmutableList
fun AddRoomToSpaceView( fun AddRoomToSpaceView(
state: AddRoomToSpaceState, state: AddRoomToSpaceState,
onBackClick: () -> Unit, onBackClick: () -> Unit,
onRoomsAdded: () -> Unit, onAddRoom: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
val updatedOnAddRoom by rememberUpdatedState(onAddRoom)
fun onRoomToggled(room: SelectRoomInfo) { fun onRoomToggled(room: SelectRoomInfo) {
state.eventSink(AddRoomToSpaceEvent.ToggleRoom(room)) state.eventSink(AddRoomToSpaceEvent.ToggleRoom(room))
} }
@@ -78,7 +81,7 @@ fun AddRoomToSpaceView(
// Navigate back on success // Navigate back on success
LaunchedEffect(state.saveAction) { LaunchedEffect(state.saveAction) {
if (state.saveAction is AsyncAction.Success) { if (state.saveAction is AsyncAction.Success) {
onRoomsAdded() updatedOnAddRoom()
} }
} }
@@ -247,6 +250,6 @@ internal fun AddRoomToSpaceViewPreview(
AddRoomToSpaceView( AddRoomToSpaceView(
state = state, state = state,
onBackClick = {}, onBackClick = {},
onRoomsAdded = {}, onAddRoom = {},
) )
} }
@@ -125,7 +125,7 @@ private fun AndroidComposeUiTest<ComponentActivity>.setAddRoomToSpaceView(
AddRoomToSpaceView( AddRoomToSpaceView(
state = state, state = state,
onBackClick = onBackClick, onBackClick = onBackClick,
onRoomsAdded = onRoomsAdded, onAddRoom = onRoomsAdded,
) )
} }
} }
+4
View File
@@ -61,6 +61,8 @@ autoservice = "1.1.1"
# quality # quality
detekt = "1.23.8" detekt = "1.23.8"
# Stick to version < 0.5 since error detection is broken. See https://mrmans0n.github.io/compose-rules/detekt/#supported-versions-matrix
detekt_compose_rules = "0.4.28"
# See https://github.com/pinterest/ktlint/releases/ # See https://github.com/pinterest/ktlint/releases/
ktlint = "1.8.0" ktlint = "1.8.0"
androidx-test-ext-junit = "1.3.0" androidx-test-ext-junit = "1.3.0"
@@ -72,6 +74,8 @@ android_gradle_plugin = { module = "com.android.tools.build:gradle", version.ref
compose_compiler_plugin = { module = "org.jetbrains.kotlin:compose-compiler-gradle-plugin", version.ref = "kotlin" } compose_compiler_plugin = { module = "org.jetbrains.kotlin:compose-compiler-gradle-plugin", version.ref = "kotlin" }
# https://developer.android.com/studio/write/java8-support#library-desugaring-versions # https://developer.android.com/studio/write/java8-support#library-desugaring-versions
android_desugar = "com.android.tools:desugar_jdk_libs:2.1.5" android_desugar = "com.android.tools:desugar_jdk_libs:2.1.5"
# Used in build.gradle.kts
detekt_compose_rules = { module = "io.nlopez.compose.rules:detekt", version.ref = "detekt_compose_rules" }
kotlin_gradle_plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } kotlin_gradle_plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
metro_gradle_plugin = { module = "dev.zacsweers.metro:gradle-plugin", version.ref = "metro" } metro_gradle_plugin = { module = "dev.zacsweers.metro:gradle-plugin", version.ref = "metro" }
kotlin_compiler = { module = "org.jetbrains.kotlin:kotlin-compiler", version.ref = "kotlin" } kotlin_compiler = { module = "org.jetbrains.kotlin:kotlin-compiler", version.ref = "kotlin" }
@@ -186,6 +186,7 @@ class SafeChildrenTransitionScope<T : Any, S>(
} }
@OptIn(ExperimentalSharedTransitionApi::class) @OptIn(ExperimentalSharedTransitionApi::class)
@Suppress("ContentSlotReused")
@Composable @Composable
inline fun <reified NavTarget : Any, State> ParentNode<NavTarget>.SafeChildren( inline fun <reified NavTarget : Any, State> ParentNode<NavTarget>.SafeChildren(
navModel: NavModel<NavTarget, State>, navModel: NavModel<NavTarget, State>,
@@ -24,6 +24,8 @@ import androidx.compose.material3.SheetState
import androidx.compose.material3.contentColorFor import androidx.compose.material3.contentColorFor
import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.movableContentOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.Shape
@@ -88,14 +90,15 @@ fun ModalBottomSheet(
dragHandle = dragHandle, dragHandle = dragHandle,
contentWindowInsets = contentWindowInsets, contentWindowInsets = contentWindowInsets,
) { ) {
val movableContent = remember { movableContentOf { content() } }
if (scrollable) { if (scrollable) {
Column( Column(
modifier = Modifier.verticalScroll(rememberScrollState()), modifier = Modifier.verticalScroll(rememberScrollState()),
) { ) {
content() movableContent()
} }
} else { } else {
content() movableContent()
} }
} }
} }
@@ -184,6 +184,7 @@ private fun PickButton(
} }
} }
@Suppress("ModifierClickableOrder")
@Composable @Composable
private fun BoxScope.OverlayEditButton( private fun BoxScope.OverlayEditButton(
onClick: () -> Unit, onClick: () -> Unit,
@@ -13,8 +13,10 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import androidx.compose.runtime.ProduceStateScope import androidx.compose.runtime.ProduceStateScope
import androidx.compose.runtime.State import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState import androidx.compose.runtime.produceState
import androidx.compose.runtime.rememberUpdatedState
import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.core.extensions.mapCatchingExceptions import io.element.android.libraries.core.extensions.mapCatchingExceptions
import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.EventId
@@ -87,8 +89,9 @@ class MediaViewerDataSource(
fun produceState( fun produceState(
producer: suspend ProduceStateScope<ImmutableList<MediaViewerPageData>>.(StateFlow<ImmutableList<MediaViewerPageData>>) -> Unit producer: suspend ProduceStateScope<ImmutableList<MediaViewerPageData>>.(StateFlow<ImmutableList<MediaViewerPageData>>) -> Unit
): State<ImmutableList<MediaViewerPageData>> { ): State<ImmutableList<MediaViewerPageData>> {
val latestProducer by rememberUpdatedState(producer)
return produceState(initialValue = initialData()) { return produceState(initialValue = initialData()) {
producer(dataFlow) latestProducer(dataFlow)
} }
} }
@@ -18,6 +18,7 @@ import androidx.camera.view.PreviewView
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
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.getValue
@@ -114,7 +115,8 @@ fun QrCodeCameraView(
Box(modifier.clipToBounds()) { Box(modifier.clipToBounds()) {
if (LocalInspectionMode.current) { if (LocalInspectionMode.current) {
Box( Box(
modifier = modifier modifier = Modifier
.fillMaxSize()
.background(color = ElementTheme.colors.bgSubtlePrimary), .background(color = ElementTheme.colors.bgSubtlePrimary),
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
) { ) {
@@ -32,6 +32,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.movableContentOf
import androidx.compose.runtime.mutableStateOf 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
@@ -419,7 +420,7 @@ fun TextComposer(
// Re-focus the text input when voice recording ends so the user can continue typing // Re-focus the text input when voice recording ends so the user can continue typing
var previousVoiceMessageState by remember { mutableStateOf(voiceMessageState) } var previousVoiceMessageState by remember { mutableStateOf(voiceMessageState) }
LaunchedEffect(voiceMessageState) { LaunchedEffect(voiceMessageState, onRequestFocus) {
if (voiceMessageState is VoiceMessageState.Idle && previousVoiceMessageState !is VoiceMessageState.Idle) { if (voiceMessageState is VoiceMessageState.Idle && previousVoiceMessageState !is VoiceMessageState.Idle) {
onRequestFocus() onRequestFocus()
} }
@@ -522,6 +523,7 @@ private fun StandardLayout(
.padding(bottom = 8.dp, top = 8.dp) .padding(bottom = 8.dp, top = 8.dp)
.weight(1f) .weight(1f)
) { ) {
val movableVoiceRecording = remember { movableContentOf { voiceRecording() } }
if (voiceMessageState is VoiceMessageState.Idle) { if (voiceMessageState is VoiceMessageState.Idle) {
textInput() textInput()
} else if (composerMode is MessageComposerMode.Special) { } else if (composerMode is MessageComposerMode.Special) {
@@ -530,10 +532,10 @@ private fun StandardLayout(
onResetComposerMode = onResetComposerMode, onResetComposerMode = onResetComposerMode,
isTextEmpty = true, isTextEmpty = true,
) { ) {
voiceRecording() movableVoiceRecording()
} }
} else { } else {
voiceRecording() movableVoiceRecording()
} }
} }
// To avoid loosing keyboard focus, the IconButton has to be defined here and has to be always enabled. // To avoid loosing keyboard focus, the IconButton has to be defined here and has to be always enabled.
+18 -1
View File
@@ -150,7 +150,7 @@ exceptions:
TooGenericExceptionCaught: TooGenericExceptionCaught:
active: false active: false
SwallowedException: SwallowedException:
active: true active: false
ThrowingExceptionsWithoutMessageOrCause: ThrowingExceptionsWithoutMessageOrCause:
active: true active: true
TooGenericExceptionThrown: TooGenericExceptionThrown:
@@ -224,12 +224,27 @@ comments:
Compose: Compose:
CompositionLocalAllowlist: CompositionLocalAllowlist:
active: true active: true
# You can optionally define a list of CompositionLocals that are allowed here
allowedCompositionLocals:
- LocalCompoundColors
- LocalSnackbarDispatcher
- LocalCameraPositionState
- LocalMediaItemPresenterFactories
- LocalTimelineItemPresenterFactories
- LocalRoomMemberProfilesCache
- LocalMentionSpanUpdater
- LocalAnalyticsService
- LocalBuildMeta
- LocalUiTestMode
- LocalSdkIntVersionProvider
CompositionLocalNaming: CompositionLocalNaming:
active: true active: true
ContentEmitterReturningValues: ContentEmitterReturningValues:
active: true active: true
# You can optionally add your own composables here # You can optionally add your own composables here
# contentEmitters: MyComposable,MyOtherComposable # contentEmitters: MyComposable,MyOtherComposable
ModifierComposable:
active: true
ModifierMissing: ModifierMissing:
active: true active: true
ModifierReused: ModifierReused:
@@ -252,6 +267,8 @@ Compose:
active: true active: true
PreviewPublic: PreviewPublic:
active: true active: true
# You can optionally disable that only previews with @PreviewParameter are flagged
previewPublicOnlyIfParams: false
RememberMissing: RememberMissing:
active: true active: true
UnstableCollections: UnstableCollections: