diff --git a/core/data/auth/src/main/java/com/goalpanzi/mission_mate/core/data/auth/AuthTokenProvider.kt b/core/data/auth/src/main/java/com/goalpanzi/mission_mate/core/data/auth/AuthTokenProvider.kt index 034d3ced..684170f1 100644 --- a/core/data/auth/src/main/java/com/goalpanzi/mission_mate/core/data/auth/AuthTokenProvider.kt +++ b/core/data/auth/src/main/java/com/goalpanzi/mission_mate/core/data/auth/AuthTokenProvider.kt @@ -2,6 +2,7 @@ package com.goalpanzi.mission_mate.core.data.auth import com.goalpanzi.mission_mate.core.datastore.datasource.AuthDataSource import com.goalpanzi.mission_mate.core.network.TokenProvider +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.firstOrNull import javax.inject.Inject @@ -17,12 +18,10 @@ class AuthTokenProvider @Inject constructor( } override suspend fun setAccessToken(accessToken: String) { - authDataSource.setAccessToken(accessToken) + authDataSource.setAccessToken(accessToken).collect() } override suspend fun setRefreshToken(refreshToken: String) { - authDataSource.setRefreshToken(refreshToken) + authDataSource.setRefreshToken(refreshToken).collect() } - - } diff --git a/core/designsystem/src/main/java/com/goalpanzi/mission_mate/core/designsystem/ext/Modifier.kt b/core/designsystem/src/main/java/com/goalpanzi/mission_mate/core/designsystem/ext/Modifier.kt index be858e39..aa43a700 100644 --- a/core/designsystem/src/main/java/com/goalpanzi/mission_mate/core/designsystem/ext/Modifier.kt +++ b/core/designsystem/src/main/java/com/goalpanzi/mission_mate/core/designsystem/ext/Modifier.kt @@ -1,9 +1,12 @@ package com.goalpanzi.mission_mate.core.designsystem.ext import android.graphics.BlurMaskFilter +import androidx.compose.foundation.LocalIndication import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.composed import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color @@ -11,8 +14,11 @@ import androidx.compose.ui.graphics.Paint import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.drawOutline import androidx.compose.ui.graphics.drawscope.drawIntoCanvas +import androidx.compose.ui.semantics.Role import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import com.goalpanzi.mission_mate.core.designsystem.util.MultipleEventsCutter +import com.goalpanzi.mission_mate.core.designsystem.util.get fun Modifier.dropShadow( shape: Shape, @@ -54,4 +60,21 @@ fun Modifier.clickableWithoutRipple( ) ) -} \ No newline at end of file +} + +fun Modifier.clickableSingle( + enabled: Boolean = true, + onClickLabel: String? = null, + role: Role? = null, + onClick: () -> Unit +) = composed { + val multipleEventsCutter = remember { MultipleEventsCutter.get() } + Modifier.clickable( + enabled = enabled, + onClickLabel = onClickLabel, + onClick = { multipleEventsCutter.processEvent { onClick() } }, + role = role, + indication = LocalIndication.current, + interactionSource = remember { MutableInteractionSource() } + ) +} diff --git a/core/designsystem/src/main/java/com/goalpanzi/mission_mate/core/designsystem/util/MultipleEventsCutter.kt b/core/designsystem/src/main/java/com/goalpanzi/mission_mate/core/designsystem/util/MultipleEventsCutter.kt new file mode 100644 index 00000000..15783cfc --- /dev/null +++ b/core/designsystem/src/main/java/com/goalpanzi/mission_mate/core/designsystem/util/MultipleEventsCutter.kt @@ -0,0 +1,25 @@ +package com.goalpanzi.mission_mate.core.designsystem.util + + +interface MultipleEventsCutter { + fun processEvent(event: () -> Unit) + + companion object +} + +fun MultipleEventsCutter.Companion.get(): MultipleEventsCutter = + MultipleEventsCutterImpl() + +private class MultipleEventsCutterImpl : MultipleEventsCutter { + private val now: Long + get() = System.currentTimeMillis() + + private var lastEventTimeMs: Long = 0 + + override fun processEvent(event: () -> Unit) { + if (now - lastEventTimeMs >= 300L) { + event.invoke() + } + lastEventTimeMs = now + } +} diff --git a/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/screen/VerificationPreviewScreen.kt b/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/screen/VerificationPreviewScreen.kt index ee967cb3..95b44804 100644 --- a/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/screen/VerificationPreviewScreen.kt +++ b/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/screen/VerificationPreviewScreen.kt @@ -1,8 +1,14 @@ package com.goalpanzi.mission_mate.feature.board.screen +import android.content.Context +import android.net.Uri +import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.focusable import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -22,6 +28,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment @@ -49,6 +56,8 @@ import com.goalpanzi.mission_mate.core.designsystem.component.StableImage import com.goalpanzi.mission_mate.core.designsystem.theme.ColorBlack_FF000000 import com.goalpanzi.mission_mate.core.designsystem.theme.ColorWhite_FFFFFFFF import com.goalpanzi.mission_mate.core.designsystem.theme.MissionMateTypography +import com.goalpanzi.mission_mate.core.designsystem.util.MultipleEventsCutter +import com.goalpanzi.mission_mate.core.designsystem.util.get import com.goalpanzi.mission_mate.feature.board.R import com.goalpanzi.mission_mate.feature.board.model.CharacterUiModel import com.goalpanzi.mission_mate.feature.board.util.ImageCompressor @@ -187,38 +196,56 @@ fun VerificationPreviewScreen( ) } } - - MissionMateButton( - modifier = Modifier - .align(Alignment.BottomCenter) - .padding(horizontal = 24.dp, vertical = 36.dp) - .fillMaxWidth() - .navigationBarsPadding(), - buttonType = MissionMateButtonType.ACTIVE, - onClick = { - val file = ImageCompressor.getCompressedImage(context, uiState.imageUrl.toUri()) - onClickUpload(file) - } - ) { - Text( - text = stringResource(id = R.string.upload), - style = MissionMateTypography.body_xl_bold, - color = ColorWhite_FFFFFFFF - ) - } + UploadButton( + context = context, + filePath = uiState.imageUrl.toUri(), + onClickUpload = onClickUpload + ) } } } } } +@Composable +fun BoxScope.UploadButton( + context: Context, + filePath: Uri, + onClickUpload: (File) -> Unit +) { + val multipleEventsCutter = remember { MultipleEventsCutter.get() } + MissionMateButton( + modifier = Modifier + .align(Alignment.BottomCenter) + .padding(horizontal = 24.dp, vertical = 36.dp) + .fillMaxWidth() + .navigationBarsPadding(), + buttonType = MissionMateButtonType.ACTIVE, + onClick = { + multipleEventsCutter.processEvent { + val file = ImageCompressor.getCompressedImage(context, filePath) + onClickUpload(file) + } + } + ) { + Text( + text = stringResource(id = R.string.upload), + style = MissionMateTypography.body_xl_bold, + color = ColorWhite_FFFFFFFF + ) + } +} + @Composable fun VerificationPreviewLoading() { Box( modifier = Modifier - .background(ColorWhite_FFFFFFFF) + .fillMaxSize() + .background(Color.Transparent) .statusBarsPadding() .navigationBarsPadding() + .focusable() + .clickable {} ) { CircularProgressIndicator( modifier = Modifier.align(Alignment.Center) @@ -252,3 +279,13 @@ fun VerificationPreviewScreenPreview() { onClickUpload = {} ) } + +@Preview +@Composable +fun VerificationPreviewScreenLoadingPreview() { + VerificationPreviewScreen( + onClickClose = {}, + uiState = VerificationPreviewUiState.Loading, + onClickUpload = {} + ) +}