diff --git a/presentation/src/main/java/com/whyranoid/presentation/reusable/SingleToast.kt b/presentation/src/main/java/com/whyranoid/presentation/reusable/SingleToast.kt new file mode 100644 index 00000000..1fa83381 --- /dev/null +++ b/presentation/src/main/java/com/whyranoid/presentation/reusable/SingleToast.kt @@ -0,0 +1,28 @@ +package com.whyranoid.presentation.reusable + +import android.content.Context +import android.widget.Toast + +object SingleToast { + + private const val DEFAULT_DURATION = 2_000L + private var lastToastInfo: Pair? = null + + fun show( + context: Context, + message: String, + duration: Int = Toast.LENGTH_SHORT + ) { + if (lastToastInfo?.first != message) { + lastToastInfo = message to System.currentTimeMillis() + Toast.makeText(context, message, duration).show() + } else { + lastToastInfo?.second?.let {lastToastTime -> + if (System.currentTimeMillis() - lastToastTime > DEFAULT_DURATION) { + lastToastInfo = message to System.currentTimeMillis() + Toast.makeText(context, message, duration).show() + } + } + } + } +} \ No newline at end of file diff --git a/presentation/src/main/java/com/whyranoid/presentation/screens/challenge/ChallengeDetailScreen.kt b/presentation/src/main/java/com/whyranoid/presentation/screens/challenge/ChallengeDetailScreen.kt index 0cbdcc21..cd73490f 100644 --- a/presentation/src/main/java/com/whyranoid/presentation/screens/challenge/ChallengeDetailScreen.kt +++ b/presentation/src/main/java/com/whyranoid/presentation/screens/challenge/ChallengeDetailScreen.kt @@ -1,6 +1,5 @@ package com.whyranoid.presentation.screens.challenge -import android.widget.Toast import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -45,6 +44,7 @@ import com.whyranoid.presentation.component.ChallengeGoalContent import com.whyranoid.presentation.component.UserIcon import com.whyranoid.presentation.component.bottomsheet.ChallengeExitModalBottomSheetContainer import com.whyranoid.presentation.component.button.WalkiePositiveButton +import com.whyranoid.presentation.reusable.SingleToast import com.whyranoid.presentation.reusable.WalkieCircularProgressIndicator import com.whyranoid.presentation.theme.SystemColor import com.whyranoid.presentation.theme.WalkieTypography @@ -75,12 +75,12 @@ fun ChallengeDetailScreen( viewModel.collectSideEffect { when (it) { ChallengeDetailSideEffect.StartChallengeSuccess -> { - Toast.makeText(context, "챌린지를 성공적으로 시작하였습니다.", Toast.LENGTH_SHORT).show() + SingleToast.show(context, "챌린지를 성공적으로 시작하였습니다.") navController.popBackStack() } ChallengeDetailSideEffect.StartChallengeFailure -> { - Toast.makeText(context, "챌린지를 시작할 수 없습니다.", Toast.LENGTH_SHORT).show() + SingleToast.show(context, "챌린지를 시작할 수 없습니다.") } } } diff --git a/presentation/src/main/java/com/whyranoid/presentation/screens/challenge/ChallengeExitScreen.kt b/presentation/src/main/java/com/whyranoid/presentation/screens/challenge/ChallengeExitScreen.kt index c2638fe1..e3fa1fa6 100644 --- a/presentation/src/main/java/com/whyranoid/presentation/screens/challenge/ChallengeExitScreen.kt +++ b/presentation/src/main/java/com/whyranoid/presentation/screens/challenge/ChallengeExitScreen.kt @@ -11,7 +11,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material.Text +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue diff --git a/presentation/src/main/java/com/whyranoid/presentation/screens/community/CommentScreen.kt b/presentation/src/main/java/com/whyranoid/presentation/screens/community/CommentScreen.kt index fc6c1c97..50e34fa9 100644 --- a/presentation/src/main/java/com/whyranoid/presentation/screens/community/CommentScreen.kt +++ b/presentation/src/main/java/com/whyranoid/presentation/screens/community/CommentScreen.kt @@ -1,7 +1,6 @@ package com.whyranoid.presentation.screens.community import android.util.Log -import android.widget.Toast import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -19,11 +18,11 @@ import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField -import androidx.compose.material.CircularProgressIndicator -import androidx.compose.material.Icon -import androidx.compose.material.LocalTextStyle -import androidx.compose.material.Scaffold -import androidx.compose.material.Text +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.Icon +import androidx.compose.material3.LocalTextStyle +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.KeyboardArrowLeft import androidx.compose.runtime.Composable @@ -56,6 +55,7 @@ import com.whyranoid.domain.repository.UserRepository import com.whyranoid.domain.usecase.GetMyUidUseCase import com.whyranoid.domain.usecase.community.SendCommentUseCase import com.whyranoid.presentation.component.bar.WalkieTopBar +import com.whyranoid.presentation.reusable.SingleToast import com.whyranoid.presentation.theme.WalkieColor import com.whyranoid.presentation.theme.WalkieTheme import com.whyranoid.presentation.theme.WalkieTypography @@ -128,7 +128,7 @@ fun CommentScreen( isProgress = false }.onFailure { isProgress = false - Toast.makeText(context, "댓글 작성에 실패했습니다.", Toast.LENGTH_SHORT).show() + SingleToast.show(context, "댓글 작성에 실패했습니다.") } } }, diff --git a/presentation/src/main/java/com/whyranoid/presentation/screens/mypage/editprofile/EditProfileScreen.kt b/presentation/src/main/java/com/whyranoid/presentation/screens/mypage/editprofile/EditProfileScreen.kt index 792a4b1b..b13c5701 100644 --- a/presentation/src/main/java/com/whyranoid/presentation/screens/mypage/editprofile/EditProfileScreen.kt +++ b/presentation/src/main/java/com/whyranoid/presentation/screens/mypage/editprofile/EditProfileScreen.kt @@ -1,7 +1,6 @@ package com.whyranoid.presentation.screens.mypage.editprofile import android.Manifest -import android.widget.Toast import androidx.activity.compose.BackHandler import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts @@ -61,6 +60,7 @@ import com.whyranoid.presentation.R import com.whyranoid.presentation.component.button.CircularIconButton import com.whyranoid.presentation.component.button.WalkieBottomSheetButton import com.whyranoid.presentation.component.button.WalkiePositiveButton +import com.whyranoid.presentation.reusable.SingleToast import com.whyranoid.presentation.reusable.WalkieTextField import com.whyranoid.presentation.theme.WalkieTypography import com.whyranoid.presentation.util.createImageFile @@ -215,7 +215,7 @@ fun EditProfileContent( LaunchedEffect(viewModel.isMyInfoChanged) { viewModel.isMyInfoChanged.collectLatest { - Toast.makeText(context, "정보가 수정되었습니다.", Toast.LENGTH_SHORT).show() + SingleToast.show(context, "정보가 수정되었습니다.") popBackStack() } } @@ -368,7 +368,7 @@ fun EditProfileContent( if (it.matches(nickNameRegex)) { nickName = it } else { - Toast.makeText(context, "닉네임은 30자 이내로 영문,숫자,마침표,_만 입력해주세요.", Toast.LENGTH_SHORT).show() + SingleToast.show(context, "닉네임은 30자 이내로 영문,숫자,마침표,_만 입력해주세요.") } } ) diff --git a/presentation/src/main/java/com/whyranoid/presentation/screens/signin/SignInInitialScreen.kt b/presentation/src/main/java/com/whyranoid/presentation/screens/signin/SignInInitialScreen.kt index e6ff3d22..d8f87602 100644 --- a/presentation/src/main/java/com/whyranoid/presentation/screens/signin/SignInInitialScreen.kt +++ b/presentation/src/main/java/com/whyranoid/presentation/screens/signin/SignInInitialScreen.kt @@ -21,7 +21,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Scaffold -import androidx.compose.material.Text +import androidx.compose.material3.Text import androidx.compose.material.rememberScaffoldState import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope @@ -41,6 +41,7 @@ import com.google.android.gms.common.api.ApiException import com.google.android.gms.tasks.Task import com.whyranoid.domain.usecase.RequestLoginUseCase import com.whyranoid.presentation.R +import com.whyranoid.presentation.reusable.SingleToast import com.whyranoid.presentation.theme.WalkieTheme import com.whyranoid.presentation.theme.WalkieTypography import kotlinx.coroutines.launch @@ -55,6 +56,7 @@ fun SignInInitialScreen( ) { val scope = rememberCoroutineScope() val scaffoldState = rememberScaffoldState() + val context = LocalContext.current val requestLoginUseCase = get() @@ -79,18 +81,14 @@ fun SignInInitialScreen( account = account, goToAgreeState = goToAgreeState, ) { errorMsg -> - scope.launch { - scaffoldState.snackbarHostState.showSnackbar(errorMsg) - } + SingleToast.show(context, errorMsg) } } } } } else { - scope.launch { - scaffoldState.snackbarHostState.showSnackbar("계정 연결에 실패했습니다.") - } + SingleToast.show(context, "계정 연결에 실패했습니다.") } } @@ -111,7 +109,6 @@ fun SignInInitialScreen( .padding(bottom = 232.dp), ) - val context = LocalContext.current Box( modifier = Modifier .align(Alignment.BottomCenter) @@ -151,12 +148,12 @@ fun SignInInitialScreen( private fun handleSignInResult( account: GoogleSignInAccount, goToAgreeState: (authId: String, name: String, url: String?) -> Unit, - showErrorSnackBar: (msg: String) -> Unit, + showErrorToast: (String) -> Unit ) { runCatching { - val uid = requireNotNull(account.id) { showErrorSnackBar("authId is null") } - val name = requireNotNull(account.displayName) { showErrorSnackBar("name is null") } - val url = account.photoUrl?.let { it.toString() } + val uid = requireNotNull(account.id) { showErrorToast("authId is null") } + val name = requireNotNull(account.displayName) { showErrorToast("name is null") } + val url = account.photoUrl?.toString() goToAgreeState(uid, name, url) } }