From bf0e02addde87fdcd5858ccf701ab7512d8253a7 Mon Sep 17 00:00:00 2001 From: kooo5252 Date: Fri, 16 Aug 2024 11:07:38 +0900 Subject: [PATCH 1/8] [Refactoring] Fix typo warnings. --- .../droidkaigi/confsched/profilecard/ProfileCardScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt b/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt index 4a0464f29..e03870a50 100644 --- a/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt +++ b/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt @@ -94,7 +94,7 @@ import org.jetbrains.compose.resources.stringResource import kotlin.io.encoding.Base64 import kotlin.io.encoding.ExperimentalEncodingApi -const val profileCardScreenRoute = "profilecard" +const val profileCardScreenRoute = "profileCard" const val ProfileCardEditScreenTestTag = "ProfileCardEditScreenTestTag" const val ProfileCardNicknameTextFieldTestTag = "ProfileCardNicknameTextFieldTestTag" From 36fdc38a399fe08eafc221d376a813671ff1ae08 Mon Sep 17 00:00:00 2001 From: kooo5252 Date: Fri, 16 Aug 2024 11:08:49 +0900 Subject: [PATCH 2/8] Create a data class to effectively diff compare stored image data. --- .../droidkaigi/confsched/model/ProfileCard.kt | 30 +++++++++++++++++++ .../profilecard/ProfileCardScreen.kt | 3 +- .../profilecard/ProfileCardScreenPresenter.kt | 3 +- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/ProfileCard.kt b/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/ProfileCard.kt index 0628f4d91..98982e7e3 100644 --- a/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/ProfileCard.kt +++ b/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/ProfileCard.kt @@ -1,5 +1,8 @@ package io.github.droidkaigi.confsched.model +import kotlin.io.encoding.Base64 +import kotlin.io.encoding.ExperimentalEncodingApi + sealed interface ProfileCard { data object Loading : ProfileCard @@ -14,6 +17,33 @@ sealed interface ProfileCard { ) : ProfileCard } +data class ImageData internal constructor( + val image: String, + val imageBase64: ByteArray, +) { + constructor(image: String) : this(image, image.decodeBase64Bytes()) + constructor(imageBase64: ByteArray) : this(imageBase64.toBase64(), imageBase64) + + private val imageHash: Int = imageBase64.contentHashCode() + + override fun equals(other: Any?): Boolean { + return this === other + || other is ImageData && imageHash == other.imageHash + } + + override fun hashCode(): Int { + return imageHash + } + + companion object { + @OptIn(ExperimentalEncodingApi::class) + private fun ByteArray.toBase64(): String = Base64.encode(this) + + @OptIn(ExperimentalEncodingApi::class) + private fun String.decodeBase64Bytes(): ByteArray = Base64.decode(this) + } +} + enum class ProfileCardTheme { Iguana, Hedgehog, diff --git a/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt b/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt index e03870a50..3137d97e7 100644 --- a/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt +++ b/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt @@ -83,6 +83,7 @@ import io.github.droidkaigi.confsched.compose.EventEmitter import io.github.droidkaigi.confsched.compose.rememberEventEmitter import io.github.droidkaigi.confsched.designsystem.theme.LocalProfileCardScreenTheme import io.github.droidkaigi.confsched.designsystem.theme.ProvideProfileCardScreenTheme +import io.github.droidkaigi.confsched.model.ImageData import io.github.droidkaigi.confsched.model.ProfileCard import io.github.droidkaigi.confsched.model.ProfileCardTheme import io.github.droidkaigi.confsched.profilecard.component.PhotoPickerButton @@ -126,7 +127,7 @@ internal sealed interface ProfileCardUiState { val nickname: String = "", val occupation: String? = null, val link: String? = null, - val image: String? = null, + val imageData: ImageData? = null, val theme: ProfileCardTheme = ProfileCardTheme.entries.first(), ) : ProfileCardUiState diff --git a/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreenPresenter.kt b/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreenPresenter.kt index 6f8989be2..b90e43ca8 100644 --- a/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreenPresenter.kt +++ b/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreenPresenter.kt @@ -7,6 +7,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.setValue import io.github.droidkaigi.confsched.compose.SafeLaunchedEffect +import io.github.droidkaigi.confsched.model.ImageData import io.github.droidkaigi.confsched.model.ProfileCard import io.github.droidkaigi.confsched.model.ProfileCardRepository import io.github.droidkaigi.confsched.model.localProfileCardRepository @@ -31,7 +32,7 @@ private fun ProfileCard.toEditUiState(): ProfileCardUiState.Edit { nickname = nickname, occupation = occupation, link = link, - image = image, + imageData = image?.run(::ImageData), theme = theme, ) ProfileCard.DoesNotExists, ProfileCard.Loading -> ProfileCardUiState.Edit() From e371db566e1333b76499f4c3f6e3627b6179f092 Mon Sep 17 00:00:00 2001 From: kooo5252 Date: Fri, 16 Aug 2024 11:10:03 +0900 Subject: [PATCH 3/8] Add properties to retain data while editing profiles. --- .../confsched/profilecard/ProfileCardScreenPresenter.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreenPresenter.kt b/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreenPresenter.kt index b90e43ca8..e9673897d 100644 --- a/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreenPresenter.kt +++ b/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreenPresenter.kt @@ -12,6 +12,7 @@ import io.github.droidkaigi.confsched.model.ProfileCard import io.github.droidkaigi.confsched.model.ProfileCardRepository import io.github.droidkaigi.confsched.model.localProfileCardRepository import io.github.droidkaigi.confsched.ui.providePresenterDefaults +import io.github.takahirom.rin.rememberRetained import kotlinx.coroutines.flow.Flow internal sealed interface ProfileCardScreenEvent @@ -59,7 +60,8 @@ internal fun profileCardScreenPresenter( ): ProfileCardScreenState = providePresenterDefaults { userMessageStateHolder -> val profileCard: ProfileCard by rememberUpdatedState(repository.profileCard()) var isLoading: Boolean by remember { mutableStateOf(false) } - val editUiState: ProfileCardUiState.Edit by rememberUpdatedState(profileCard.toEditUiState()) + var editingUiState: ProfileCardUiState.Edit? by rememberRetained { mutableStateOf(null) } + val editUiState: ProfileCardUiState.Edit by rememberUpdatedState(editingUiState ?: profileCard.toEditUiState()) val cardUiState: ProfileCardUiState.Card? by rememberUpdatedState(profileCard.toCardUiState()) var uiType: ProfileCardUiType by remember { mutableStateOf(ProfileCardUiType.Loading) } From 0c33b8ad89cf50ab7c019434b2d9f8506cf1cee0 Mon Sep 17 00:00:00 2001 From: kooo5252 Date: Fri, 16 Aug 2024 11:12:00 +0900 Subject: [PATCH 4/8] Add profile editing screen update event. --- .../droidkaigi/confsched/profilecard/ProfileCardScreen.kt | 4 ++++ .../confsched/profilecard/ProfileCardScreenPresenter.kt | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt b/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt index 3137d97e7..d363d6b32 100644 --- a/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt +++ b/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt @@ -204,6 +204,9 @@ internal fun ProfileCardScreen( ProfileCardUiType.Edit -> { EditScreen( uiState = uiState.editUiState, + onUpdateEditingState = { + eventEmitter.tryEmit(EditScreenEvent.Update(it)) + }, onClickCreate = { eventEmitter.tryEmit(EditScreenEvent.Create(it)) }, @@ -241,6 +244,7 @@ internal fun ProfileCardScreen( @Composable internal fun EditScreen( uiState: ProfileCardUiState.Edit, + onUpdateEditingState: (ProfileCardUiState.Edit) -> Unit, onClickCreate: (ProfileCard.Exists) -> Unit, modifier: Modifier = Modifier, contentPadding: PaddingValues = PaddingValues(), diff --git a/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreenPresenter.kt b/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreenPresenter.kt index e9673897d..441b945ba 100644 --- a/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreenPresenter.kt +++ b/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreenPresenter.kt @@ -19,6 +19,7 @@ internal sealed interface ProfileCardScreenEvent internal sealed interface EditScreenEvent : ProfileCardScreenEvent { data object SelectImage : EditScreenEvent + data class Update(val editUiState: ProfileCardUiState.Edit) : EditScreenEvent data class Create(val profileCard: ProfileCard.Exists) : EditScreenEvent } @@ -87,6 +88,10 @@ internal fun profileCardScreenPresenter( userMessageStateHolder.showMessage("Share Profile Card") } + is EditScreenEvent.Update -> { + editingUiState = it.editUiState + } + is EditScreenEvent.Create -> { userMessageStateHolder.showMessage("Create Profile Card") repository.save(it.profileCard) From f786b84c718e6b0a5b837ae9460a0c8065423522 Mon Sep 17 00:00:00 2001 From: kooo5252 Date: Fri, 16 Aug 2024 11:14:35 +0900 Subject: [PATCH 5/8] Use Presenter data and events in profile editing screen. --- .../profilecard/ProfileCardScreen.kt | 48 +++++++------------ 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt b/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt index d363d6b32..1070e2727 100644 --- a/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt +++ b/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt @@ -38,11 +38,7 @@ import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -92,8 +88,6 @@ import io.github.droidkaigi.confsched.ui.UserMessageStateHolder import io.github.droidkaigi.confsched.ui.component.AnimatedTextTopAppBar import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.stringResource -import kotlin.io.encoding.Base64 -import kotlin.io.encoding.ExperimentalEncodingApi const val profileCardScreenRoute = "profileCard" @@ -249,13 +243,8 @@ internal fun EditScreen( modifier: Modifier = Modifier, contentPadding: PaddingValues = PaddingValues(), ) { - var nickname by remember { mutableStateOf(uiState.nickname) } - var occupation by remember { mutableStateOf(uiState.occupation) } - var link by remember { mutableStateOf(uiState.link) } val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() - var imageByteArray: ByteArray? by remember { mutableStateOf(uiState.image?.decodeBase64Bytes()) } - val image by remember { derivedStateOf { imageByteArray?.toImageBitmap() } } - var selectedTheme by remember { mutableStateOf(uiState.theme) } + val image = remember(uiState.imageData) { uiState.imageData?.imageBase64?.toImageBitmap() } Scaffold( modifier = modifier.testTag(ProfileCardEditScreenTestTag).padding(contentPadding), @@ -279,21 +268,21 @@ internal fun EditScreen( InputColumn( label = stringResource(ProfileCardRes.string.nick_name), - value = nickname, + value = uiState.nickname, testTag = ProfileCardNicknameTextFieldTestTag, - onValueChanged = { nickname = it }, + onValueChanged = { onUpdateEditingState(uiState.copy(nickname = it)) }, ) InputColumn( label = stringResource(ProfileCardRes.string.occupation), - value = occupation ?: "", + value = uiState.occupation ?: "", testTag = ProfileCardOccupationTextFieldTestTag, - onValueChanged = { occupation = it }, + onValueChanged = { onUpdateEditingState(uiState.copy(occupation = it)) }, ) InputColumn( label = stringResource(ProfileCardRes.string.link_text), - value = link ?: "", + value = uiState.link ?: "", testTag = ProfileCardLinkTextFieldTestTag, - onValueChanged = { link = it }, + onValueChanged = { onUpdateEditingState(uiState.copy(link = it)) }, ) Column( @@ -311,7 +300,7 @@ internal fun EditScreen( .align(Alignment.BottomStart), ) IconButton( - onClick = { imageByteArray = null }, + onClick = { onUpdateEditingState(uiState.copy(imageData = null)) }, modifier = Modifier .graphicsLayer { translationX = 12.dp.toPx() @@ -328,7 +317,7 @@ internal fun EditScreen( } } ?: run { PhotoPickerButton( - onSelectedImage = { imageByteArray = it }, + onSelectedImage = { onUpdateEditingState(uiState.copy(imageData = ImageData(it))) }, modifier = Modifier.testTag(ProfileCardSelectImageButtonTestTag), ) { Icon(Icons.Default.Add, null) @@ -340,16 +329,19 @@ internal fun EditScreen( Text(stringResource(ProfileCardRes.string.select_theme)) - ThemePiker(selectedTheme = selectedTheme, onClickImage = { selectedTheme = it }) + ThemePiker( + selectedTheme = uiState.theme, + onClickImage = { onUpdateEditingState(uiState.copy(theme = it)) } + ) Button( onClick = { onClickCreate( ProfileCard.Exists( - nickname = nickname, - occupation = occupation, - link = link, - image = imageByteArray?.toBase64(), + nickname = uiState.nickname, + occupation = uiState.occupation, + link = uiState.link, + image = uiState.imageData?.image, theme = uiState.theme, ), ) @@ -487,12 +479,6 @@ fun Modifier.selectedBorder( this } -@OptIn(ExperimentalEncodingApi::class) -private fun ByteArray.toBase64(): String = Base64.encode(this) - -@OptIn(ExperimentalEncodingApi::class) -private fun String.decodeBase64Bytes(): ByteArray = Base64.decode(this) - @Composable internal fun CardScreen( uiState: ProfileCardUiState.Card, From caed3efd838088b11eafa7724ee2a91855aab82c Mon Sep 17 00:00:00 2001 From: kooo5252 Date: Fri, 16 Aug 2024 12:12:59 +0900 Subject: [PATCH 6/8] [Refactoring] Encapsulate edit screen validation logic in UiState class. --- .../profilecard/ProfileCardScreen.kt | 83 +++++++------------ 1 file changed, 31 insertions(+), 52 deletions(-) diff --git a/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt b/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt index 840883641..31bf3ee86 100644 --- a/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt +++ b/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt @@ -133,7 +133,32 @@ internal sealed interface ProfileCardUiState { val link: String = "", val imageData: ImageData? = null, val theme: ProfileCardTheme = ProfileCardTheme.Iguana, - ) : ProfileCardUiState + ) : ProfileCardUiState { + val nicknameError @Composable get() = if (nickname.isEmpty()) stringResource( + ProfileCardRes.string.enter_validate_format, + stringResource(ProfileCardRes.string.nickname), + ) else "" + + val occupationError @Composable get() = if (occupation.isEmpty()) stringResource( + ProfileCardRes.string.enter_validate_format, + stringResource(ProfileCardRes.string.occupation), + ) else "" + + val linkError @Composable get() = if (link.isEmpty()) stringResource( + ProfileCardRes.string.enter_validate_format, + stringResource(ProfileCardRes.string.occupation), + ) else "" + + val imageError @Composable get() = if (imageData == null) stringResource( + ProfileCardRes.string.add_validate_format, + stringResource(ProfileCardRes.string.image), + ) else "" + + val isValidInputs = nickname.isNotEmpty() + && occupation.isNotEmpty() + && link.isNotEmpty() + && imageData != null + } data class Card( val nickname: String, @@ -256,19 +281,6 @@ internal fun EditScreen( val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() val image = remember(uiState.imageData) { uiState.imageData?.imageBase64?.toImageBitmap() } - val (nicknameError, occupationError, linkError, imageError) = rememberValidationErrors( - uiState.nickname, - uiState.occupation, - uiState.link, - image, - ) - - val isValidInputs by remember { - derivedStateOf { - uiState.nickname.isNotEmpty() && uiState.occupation.isNotEmpty() && uiState.link.isNotEmpty() && image != null - } - } - Scaffold( modifier = modifier.testTag(ProfileCardEditScreenTestTag).padding(contentPadding), topBar = { @@ -293,14 +305,14 @@ internal fun EditScreen( InputFieldWithError( value = uiState.nickname, labelString = stringResource(ProfileCardRes.string.nickname), - errorMessage = nicknameError, + errorMessage = uiState.nicknameError, textFieldTestTag = ProfileCardNicknameTextFieldTestTag, onValueChange = { onUpdateEditingState(uiState.copy(nickname = it)) }, ) InputFieldWithError( value = uiState.occupation, labelString = stringResource(ProfileCardRes.string.occupation), - errorMessage = occupationError, + errorMessage = uiState.occupationError, textFieldTestTag = ProfileCardOccupationTextFieldTestTag, onValueChange = { onUpdateEditingState(uiState.copy(occupation = it)) }, ) @@ -309,7 +321,7 @@ internal fun EditScreen( InputFieldWithError( value = uiState.link, labelString = linkLabel, - errorMessage = linkError, + errorMessage = uiState.linkError, textFieldTestTag = ProfileCardLinkTextFieldTestTag, onValueChange = { onUpdateEditingState(uiState.copy(link = it)) }, ) @@ -321,7 +333,7 @@ internal fun EditScreen( ImagePickerWithError( image = image, onSelectedImage = { onUpdateEditingState(uiState.copy(imageData = ImageData(it))) }, - errorMessage = imageError, + errorMessage = uiState.imageError, onClearImage = { onUpdateEditingState(uiState.copy(imageData = null)) }, ) @@ -344,7 +356,7 @@ internal fun EditScreen( ), ) }, - enabled = isValidInputs, + enabled = uiState.isValidInputs, modifier = Modifier.fillMaxWidth() .testTag(ProfileCardCreateButtonTestTag), ) { @@ -367,39 +379,6 @@ internal fun Label(label: String) { ) } -@Composable -private fun rememberValidationErrors( - nickname: String, - occupation: String, - link: String, - image: ImageBitmap?, -): List { - val nicknameValidationErrorString = stringResource( - ProfileCardRes.string.enter_validate_format, - stringResource(ProfileCardRes.string.nickname), - ) - val occupationValidationErrorString = stringResource( - ProfileCardRes.string.enter_validate_format, - stringResource(ProfileCardRes.string.occupation), - ) - val linkValidationErrorString = stringResource( - ProfileCardRes.string.enter_validate_format, - stringResource(ProfileCardRes.string.link), - ) - val imageValidationErrorString = stringResource( - ProfileCardRes.string.add_validate_format, - stringResource(ProfileCardRes.string.image), - ) - - return remember(nickname, occupation, link, image) { - val nicknameError = if (nickname.isEmpty()) nicknameValidationErrorString else "" - val occupationError = if (occupation.isEmpty()) occupationValidationErrorString else "" - val linkError = if (link.isEmpty()) linkValidationErrorString else "" - val imageError = if (image == null) imageValidationErrorString else "" - listOf(nicknameError, occupationError, linkError, imageError) - } -} - @OptIn(ExperimentalMaterial3Api::class) @Composable private fun InputFieldWithError( From 418e372ea1ab2c34491d345910a55722905e78e0 Mon Sep 17 00:00:00 2001 From: kooo5252 Date: Fri, 16 Aug 2024 12:27:45 +0900 Subject: [PATCH 7/8] fix the detekt issues. --- .../droidkaigi/confsched/model/ProfileCard.kt | 8 +-- .../profilecard/ProfileCardScreen.kt | 68 +++++++++++-------- 2 files changed, 45 insertions(+), 31 deletions(-) diff --git a/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/ProfileCard.kt b/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/ProfileCard.kt index 707457439..8b800f00c 100644 --- a/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/ProfileCard.kt +++ b/core/model/src/commonMain/kotlin/io/github/droidkaigi/confsched/model/ProfileCard.kt @@ -23,14 +23,14 @@ data class ImageData internal constructor( val image: String, val imageBase64: ByteArray, ) { + private val imageHash: Int = imageBase64.contentHashCode() + constructor(image: String) : this(image, image.decodeBase64Bytes()) constructor(imageBase64: ByteArray) : this(imageBase64.toBase64(), imageBase64) - private val imageHash: Int = imageBase64.contentHashCode() - override fun equals(other: Any?): Boolean { - return this === other - || other is ImageData && imageHash == other.imageHash + return this === other || + other is ImageData && imageHash == other.imageHash } override fun hashCode(): Int { diff --git a/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt b/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt index 31bf3ee86..90e66a4de 100644 --- a/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt +++ b/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt @@ -41,8 +41,6 @@ import androidx.compose.material3.Text import androidx.compose.material3.TextFieldDefaults.indicatorLine import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -134,30 +132,46 @@ internal sealed interface ProfileCardUiState { val imageData: ImageData? = null, val theme: ProfileCardTheme = ProfileCardTheme.Iguana, ) : ProfileCardUiState { - val nicknameError @Composable get() = if (nickname.isEmpty()) stringResource( - ProfileCardRes.string.enter_validate_format, - stringResource(ProfileCardRes.string.nickname), - ) else "" - - val occupationError @Composable get() = if (occupation.isEmpty()) stringResource( - ProfileCardRes.string.enter_validate_format, - stringResource(ProfileCardRes.string.occupation), - ) else "" - - val linkError @Composable get() = if (link.isEmpty()) stringResource( - ProfileCardRes.string.enter_validate_format, - stringResource(ProfileCardRes.string.occupation), - ) else "" - - val imageError @Composable get() = if (imageData == null) stringResource( - ProfileCardRes.string.add_validate_format, - stringResource(ProfileCardRes.string.image), - ) else "" - - val isValidInputs = nickname.isNotEmpty() - && occupation.isNotEmpty() - && link.isNotEmpty() - && imageData != null + val nicknameError @Composable get() = if (nickname.isEmpty()) { + stringResource( + ProfileCardRes.string.enter_validate_format, + stringResource(ProfileCardRes.string.nickname), + ) + } else { + "" + } + + val occupationError @Composable get() = if (occupation.isEmpty()) { + stringResource( + ProfileCardRes.string.enter_validate_format, + stringResource(ProfileCardRes.string.occupation), + ) + } else { + "" + } + + val linkError @Composable get() = if (link.isEmpty()) { + stringResource( + ProfileCardRes.string.enter_validate_format, + stringResource(ProfileCardRes.string.occupation), + ) + } else { + "" + } + + val imageError @Composable get() = if (imageData == null) { + stringResource( + ProfileCardRes.string.add_validate_format, + stringResource(ProfileCardRes.string.image), + ) + } else { + "" + } + + val isValidInputs = nickname.isNotEmpty() && + occupation.isNotEmpty() && + link.isNotEmpty() && + imageData != null } data class Card( @@ -341,7 +355,7 @@ internal fun EditScreen( ThemePiker( selectedTheme = uiState.theme, - onClickImage = { onUpdateEditingState(uiState.copy(theme = it)) } + onClickImage = { onUpdateEditingState(uiState.copy(theme = it)) }, ) Button( From f5441fa9d64051e4868f950cc572b492a2c16d41 Mon Sep 17 00:00:00 2001 From: kooo5252 Date: Fri, 16 Aug 2024 12:35:44 +0900 Subject: [PATCH 8/8] Fix typo. --- .../droidkaigi/confsched/profilecard/ProfileCardScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt b/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt index 90e66a4de..5dc1c4faf 100644 --- a/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt +++ b/feature/profilecard/src/commonMain/kotlin/io/github/droidkaigi/confsched/profilecard/ProfileCardScreen.kt @@ -153,7 +153,7 @@ internal sealed interface ProfileCardUiState { val linkError @Composable get() = if (link.isEmpty()) { stringResource( ProfileCardRes.string.enter_validate_format, - stringResource(ProfileCardRes.string.occupation), + stringResource(ProfileCardRes.string.link), ) } else { ""