fix: code review findings - @Stable on FeedPost, derivedStateOf, deduplicate dismiss logic

This commit is contained in:
Paweł Orzech 2026-03-19 14:54:30 +01:00
parent f3ab562a6c
commit c91ccd0afb
No known key found for this signature in database
3 changed files with 17 additions and 23 deletions

View file

@ -2,7 +2,7 @@ package com.swoosh.microblog.data.model
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
// --- API Response/Request Models --- // --- API Response/Request Models ---
@ -107,7 +107,7 @@ enum class QueueStatus {
// --- UI Display Model --- // --- UI Display Model ---
@Immutable @Stable
data class FeedPost( data class FeedPost(
val localId: Long? = null, val localId: Long? = null,
val ghostId: String? = null, val ghostId: String? = null,
@ -133,7 +133,7 @@ data class FeedPost(
val queueStatus: QueueStatus = QueueStatus.NONE val queueStatus: QueueStatus = QueueStatus.NONE
) )
@Immutable @Stable
data class LinkPreview( data class LinkPreview(
val url: String, val url: String,
val title: String?, val title: String?,

View file

@ -68,8 +68,10 @@ fun ComposerScreen(
var showAltTextDialog by remember { mutableStateOf(false) } var showAltTextDialog by remember { mutableStateOf(false) }
var linkInput by remember { mutableStateOf("") } var linkInput by remember { mutableStateOf("") }
var showSendMenu by remember { mutableStateOf(false) } var showSendMenu by remember { mutableStateOf(false) }
var fullScreenImageUri by remember { mutableStateOf<Uri?>(null) }
var fullScreenImageIndex by remember { mutableIntStateOf(-1) } var fullScreenImageIndex by remember { mutableIntStateOf(-1) }
val fullScreenImageUri = if (fullScreenImageIndex >= 0 && fullScreenImageIndex < state.imageUris.size)
state.imageUris[fullScreenImageIndex] else null
val dismissFullScreen = { fullScreenImageIndex = -1 }
// Focus requester for auto-focus on text field // Focus requester for auto-focus on text field
val focusRequester = remember { FocusRequester() } val focusRequester = remember { FocusRequester() }
@ -103,7 +105,9 @@ fun ComposerScreen(
} }
} }
val canSubmit = !state.isSubmitting && (state.text.isNotBlank() || state.imageUris.isNotEmpty()) val canSubmit by remember {
derivedStateOf { !state.isSubmitting && (state.text.isNotBlank() || state.imageUris.isNotEmpty()) }
}
Scaffold( Scaffold(
topBar = { topBar = {
@ -389,8 +393,7 @@ fun ComposerScreen(
imageUris = state.imageUris, imageUris = state.imageUris,
onRemoveImage = viewModel::removeImage, onRemoveImage = viewModel::removeImage,
onAddMore = { multiImagePickerLauncher.launch("image/*") }, onAddMore = { multiImagePickerLauncher.launch("image/*") },
onImageClick = { index, uri -> onImageClick = { index, _ ->
fullScreenImageUri = uri
fullScreenImageIndex = index fullScreenImageIndex = index
} }
) )
@ -623,8 +626,7 @@ fun ComposerScreen(
if (fullScreenImageUri != null) { if (fullScreenImageUri != null) {
Dialog( Dialog(
onDismissRequest = { onDismissRequest = {
fullScreenImageUri = null dismissFullScreen()
fullScreenImageIndex = -1
}, },
properties = DialogProperties(usePlatformDefaultWidth = false) properties = DialogProperties(usePlatformDefaultWidth = false)
) { ) {
@ -644,10 +646,7 @@ fun ComposerScreen(
// Close button at top-left // Close button at top-left
IconButton( IconButton(
onClick = { onClick = { dismissFullScreen() },
fullScreenImageUri = null
fullScreenImageIndex = -1
},
modifier = Modifier modifier = Modifier
.align(Alignment.TopStart) .align(Alignment.TopStart)
.padding(16.dp), .padding(16.dp),
@ -665,8 +664,7 @@ fun ComposerScreen(
if (fullScreenImageIndex >= 0) { if (fullScreenImageIndex >= 0) {
viewModel.removeImage(fullScreenImageIndex) viewModel.removeImage(fullScreenImageIndex)
} }
fullScreenImageUri = null dismissFullScreen()
fullScreenImageIndex = -1
}, },
modifier = Modifier modifier = Modifier
.align(Alignment.BottomCenter) .align(Alignment.BottomCenter)
@ -778,22 +776,19 @@ fun ScheduleDateTimePicker(
onConfirm: (LocalDateTime) -> Unit, onConfirm: (LocalDateTime) -> Unit,
onDismiss: () -> Unit onDismiss: () -> Unit
) { ) {
val today = remember { java.time.LocalDate.now() }
val todayMillis = remember { val todayMillis = remember {
java.time.LocalDate.now() today.atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli()
.atStartOfDay(ZoneId.systemDefault())
.toInstant()
.toEpochMilli()
} }
val currentYear = remember { today.year }
val datePickerState = rememberDatePickerState( val datePickerState = rememberDatePickerState(
selectableDates = object : SelectableDates { selectableDates = object : SelectableDates {
override fun isSelectableDate(utcTimeMillis: Long): Boolean { override fun isSelectableDate(utcTimeMillis: Long): Boolean {
// Allow today and future dates only
return utcTimeMillis >= todayMillis return utcTimeMillis >= todayMillis
} }
override fun isSelectableYear(year: Int): Boolean { override fun isSelectableYear(year: Int): Boolean {
return year >= java.time.LocalDate.now().year return year >= currentYear
} }
} }
) )

View file

@ -19,7 +19,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavDestination.Companion.hierarchy
import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost