From 326dabe6aa853fe1da101e7c24d01c38bbc6c60c Mon Sep 17 00:00:00 2001 From: "takahiro.tominaga" Date: Tue, 6 Dec 2022 22:43:12 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20API=20=E3=82=A8=E3=83=A9=E3=83=BC?= =?UTF-8?q?=E7=99=BA=E7=94=9F=E6=99=82=E3=81=AB=E3=82=B9=E3=83=8A=E3=83=83?= =?UTF-8?q?=E3=82=AF=E3=83=90=E3=83=BC=E3=82=92=E8=A1=A8=E7=A4=BA=20(#9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../code_check/presentation/main/MainView.kt | 33 +++++++++++++ .../presentation/main/MainViewModel.kt | 4 ++ .../code_check/presentation/user/UserView.kt | 37 ++++++++++++++ .../presentation/user/UserViewModel.kt | 4 ++ .../presentation/util/SnackbarSetting.kt | 48 +++++++++++++++++++ app/src/main/res/values/strings.xml | 2 + 6 files changed, 128 insertions(+) create mode 100644 app/src/main/kotlin/jp/co/yumemi/android/code_check/presentation/util/SnackbarSetting.kt diff --git a/app/src/main/kotlin/jp/co/yumemi/android/code_check/presentation/main/MainView.kt b/app/src/main/kotlin/jp/co/yumemi/android/code_check/presentation/main/MainView.kt index d5e8166..8ecefb0 100644 --- a/app/src/main/kotlin/jp/co/yumemi/android/code_check/presentation/main/MainView.kt +++ b/app/src/main/kotlin/jp/co/yumemi/android/code_check/presentation/main/MainView.kt @@ -3,10 +3,13 @@ package jp.co.yumemi.android.code_check.presentation.main import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material.SnackbarHostState import androidx.compose.runtime.* +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.testTag @@ -22,7 +25,10 @@ import jp.co.yumemi.android.code_check.presentation.main.component.OneRepository import jp.co.yumemi.android.code_check.presentation.main.component.RecentSearched import jp.co.yumemi.android.code_check.presentation.util.CustomCircularProgressIndicator import jp.co.yumemi.android.code_check.presentation.util.SearchBar +import jp.co.yumemi.android.code_check.presentation.util.SnackbarSetting import jp.co.yumemi.android.code_check.presentation.util.TestTags +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch @Composable fun MainView( @@ -131,6 +137,33 @@ fun MainView( } } } + + // snackBar の状態管理用 + val snackBarCoroutineScope = rememberCoroutineScope() + val snackBarHostState = remember { SnackbarHostState() } + var snackBarJob: Job? by remember { mutableStateOf(null) } + + val snackBarMessage = stringResource(id = R.string.apiErrorMessage) + LaunchedEffect(uiState.error) { + if (uiState.error.isNotEmpty()) { + snackBarJob?.cancel() + snackBarJob = snackBarCoroutineScope.launch { + snackBarHostState.showSnackbar(snackBarMessage) + } + viewModel.resetError() + } + } + Box( + modifier = Modifier + .fillMaxSize(), + contentAlignment = Alignment.Center, + ) { + SnackbarSetting( + snackbarHostState = snackBarHostState, + modifier = Modifier + .fillMaxWidth() + ) + } } } diff --git a/app/src/main/kotlin/jp/co/yumemi/android/code_check/presentation/main/MainViewModel.kt b/app/src/main/kotlin/jp/co/yumemi/android/code_check/presentation/main/MainViewModel.kt index ae8cfda..8672e47 100644 --- a/app/src/main/kotlin/jp/co/yumemi/android/code_check/presentation/main/MainViewModel.kt +++ b/app/src/main/kotlin/jp/co/yumemi/android/code_check/presentation/main/MainViewModel.kt @@ -77,4 +77,8 @@ class MainViewModel @Inject constructor( fun setShowRecent(showRecent: Boolean) { _uiState.update { it.copy(showRecent = showRecent) } } + + fun resetError() { + _uiState.update { it.copy(error = "") } + } } diff --git a/app/src/main/kotlin/jp/co/yumemi/android/code_check/presentation/user/UserView.kt b/app/src/main/kotlin/jp/co/yumemi/android/code_check/presentation/user/UserView.kt index 7d69d31..7695d7f 100644 --- a/app/src/main/kotlin/jp/co/yumemi/android/code_check/presentation/user/UserView.kt +++ b/app/src/main/kotlin/jp/co/yumemi/android/code_check/presentation/user/UserView.kt @@ -3,10 +3,13 @@ package jp.co.yumemi.android.code_check.presentation.user import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material.SnackbarHostState import androidx.compose.runtime.* +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.testTag @@ -20,7 +23,10 @@ import jp.co.yumemi.android.code_check.presentation.MainActivity import jp.co.yumemi.android.code_check.presentation.util.SearchBar import jp.co.yumemi.android.code_check.presentation.user.component.OneUser import jp.co.yumemi.android.code_check.presentation.util.CustomCircularProgressIndicator +import jp.co.yumemi.android.code_check.presentation.util.SnackbarSetting import jp.co.yumemi.android.code_check.presentation.util.TestTags +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch @Composable fun UserView( @@ -39,6 +45,9 @@ fun UserView( viewModel.searchResults(it) MainActivity.updateLastSearchDate() }, + onSnackBarShow = { + viewModel.resetError() + }, ) } @@ -48,6 +57,7 @@ fun UserViewMain( onScroll: (Int) -> Unit = {}, onValueChange: (TextFieldValue) -> Unit = {}, onSearch: (String) -> Unit = {}, + onSnackBarShow: () -> Unit = {}, ) { val scrollState = rememberLazyListState() @@ -111,6 +121,33 @@ fun UserViewMain( } } } + + // snackBar の状態管理用 + val snackBarCoroutineScope = rememberCoroutineScope() + val snackBarHostState = remember { SnackbarHostState() } + var snackBarJob: Job? by remember { mutableStateOf(null) } + + val snackBarMessage = stringResource(id = R.string.apiErrorMessage) + LaunchedEffect(uiState.error) { + if (uiState.error.isNotEmpty()) { + snackBarJob?.cancel() + snackBarJob = snackBarCoroutineScope.launch { + snackBarHostState.showSnackbar(snackBarMessage) + } + onSnackBarShow() + } + } + Box( + modifier = Modifier + .fillMaxSize(), + contentAlignment = Alignment.Center, + ) { + SnackbarSetting( + snackbarHostState = snackBarHostState, + modifier = Modifier + .fillMaxWidth() + ) + } } @Preview( diff --git a/app/src/main/kotlin/jp/co/yumemi/android/code_check/presentation/user/UserViewModel.kt b/app/src/main/kotlin/jp/co/yumemi/android/code_check/presentation/user/UserViewModel.kt index 0406d49..dc3621e 100644 --- a/app/src/main/kotlin/jp/co/yumemi/android/code_check/presentation/user/UserViewModel.kt +++ b/app/src/main/kotlin/jp/co/yumemi/android/code_check/presentation/user/UserViewModel.kt @@ -62,4 +62,8 @@ class UserViewModel @Inject constructor( } _uiState.update { it.copy(searchInput = inputText) } } + + fun resetError() { + _uiState.update { it.copy(error = "") } + } } diff --git a/app/src/main/kotlin/jp/co/yumemi/android/code_check/presentation/util/SnackbarSetting.kt b/app/src/main/kotlin/jp/co/yumemi/android/code_check/presentation/util/SnackbarSetting.kt new file mode 100644 index 0000000..8cee9db --- /dev/null +++ b/app/src/main/kotlin/jp/co/yumemi/android/code_check/presentation/util/SnackbarSetting.kt @@ -0,0 +1,48 @@ +package jp.co.yumemi.android.code_check.presentation.util + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@Composable +fun SnackbarSetting( + snackbarHostState: SnackbarHostState, + modifier: Modifier = Modifier, +) { + Box( + modifier = modifier, + ) { + SnackbarHost( + modifier = Modifier.align(Alignment.BottomCenter), + hostState = snackbarHostState, + snackbar = { snackbarData: SnackbarData -> + Card( + shape = RoundedCornerShape(8.dp), + modifier = Modifier + .padding(4.dp) + .wrapContentSize() + .border( + width = 2.dp, + color = androidx.compose.material3.MaterialTheme.colorScheme.outline, + shape = RoundedCornerShape(8.dp) + ) + .align(Alignment.Center) + ) { + Text( + modifier = Modifier + .background(androidx.compose.material3.MaterialTheme.colorScheme.secondary) + .padding(8.dp), + text = snackbarData.message, + color = androidx.compose.material3.MaterialTheme.colorScheme.onSecondary, + ) + } + } + ) + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ebd913f..175e45f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -11,4 +11,6 @@ GitHub のユーザーを検索できるよー + + "通信エラーが発生しました。\n時間をおいて再度お試しください。" \ No newline at end of file