Skip to content

Commit

Permalink
feat: API エラー発生時にスナックバーを表示 (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
kokoichi206 committed Dec 6, 2022
1 parent 1c40e9d commit 326dabe
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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(
Expand Down Expand Up @@ -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()
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "") }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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(
Expand All @@ -39,6 +45,9 @@ fun UserView(
viewModel.searchResults(it)
MainActivity.updateLastSearchDate()
},
onSnackBarShow = {
viewModel.resetError()
},
)
}

Expand All @@ -48,6 +57,7 @@ fun UserViewMain(
onScroll: (Int) -> Unit = {},
onValueChange: (TextFieldValue) -> Unit = {},
onSearch: (String) -> Unit = {},
onSnackBarShow: () -> Unit = {},
) {

val scrollState = rememberLazyListState()
Expand Down Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,8 @@ class UserViewModel @Inject constructor(
}
_uiState.update { it.copy(searchInput = inputText) }
}

fun resetError() {
_uiState.update { it.copy(error = "") }
}
}
Original file line number Diff line number Diff line change
@@ -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,
)
}
}
)
}
}
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@

<!--UserView-->
<string name="searchInputText_hint_users">GitHub のユーザーを検索できるよー</string>

<string name="apiErrorMessage">"通信エラーが発生しました。\n時間をおいて再度お試しください。"</string>
</resources>

0 comments on commit 326dabe

Please sign in to comment.