From 4de6fe71c38ea9cbbb5dfcec2193379763e784a2 Mon Sep 17 00:00:00 2001 From: yjyoon-dev Date: Mon, 25 Jul 2022 10:46:20 +0900 Subject: [PATCH 01/10] =?UTF-8?q?fix:=20baseUrl=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EB=B0=8F=20properties=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/build.gradle.kts | 7 +++++++ .../main/java/dev/yjyoon/kwnotice/data/di/DataModule.kt | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/data/build.gradle.kts b/data/build.gradle.kts index acfa405..de2bc94 100644 --- a/data/build.gradle.kts +++ b/data/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.konan.properties.Properties + plugins { id("com.android.library") id("dagger.hilt.android.plugin") @@ -5,6 +7,9 @@ plugins { kotlin("kapt") } +val properties = Properties() +properties.load(project.rootProject.file("local.properties").inputStream()) + android { namespace = "dev.yjyoon.kwnotice.data" compileSdk = 32 @@ -12,6 +17,8 @@ android { defaultConfig { minSdk = 24 targetSdk = 32 + + buildConfigField("String", "BASE_URL", properties["base_url"] as String) } compileOptions { isCoreLibraryDesugaringEnabled = true diff --git a/data/src/main/java/dev/yjyoon/kwnotice/data/di/DataModule.kt b/data/src/main/java/dev/yjyoon/kwnotice/data/di/DataModule.kt index 6cc2c1b..e105e9e 100644 --- a/data/src/main/java/dev/yjyoon/kwnotice/data/di/DataModule.kt +++ b/data/src/main/java/dev/yjyoon/kwnotice/data/di/DataModule.kt @@ -11,6 +11,7 @@ import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent +import dev.yjyoon.kwnotice.data.BuildConfig import dev.yjyoon.kwnotice.data.local.dao.FavoriteDao import dev.yjyoon.kwnotice.data.local.db.FavoriteDatabase import dev.yjyoon.kwnotice.data.remote.api.NoticeService @@ -26,7 +27,7 @@ internal object DataModule { @Provides @Singleton @Named("BaseUrl") - fun provideBaseUrl(): String = "https://n6f11u33jf.execute-api.ap-northeast-2.amazonaws.com/v1/" + fun provideBaseUrl(): String = BuildConfig.BASE_URL @Provides @Singleton From 0ba9639cac687d0c47d3bbf12f4ea5228a7b7fdc Mon Sep 17 00:00:00 2001 From: yjyoon-dev Date: Mon, 25 Jul 2022 11:10:24 +0900 Subject: [PATCH 02/10] =?UTF-8?q?feat:=20=EC=A6=90=EA=B2=A8=EC=B0=BE?= =?UTF-8?q?=EA=B8=B0=20=EA=B3=B5=EB=B0=B1=20=ED=99=94=EB=A9=B4=20UI=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/favorite/FavoriteScreen.kt | 61 ++++++++++++++++++- .../ui/favorite/FavoriteUiState.kt | 1 + .../ui/favorite/FavoriteViewModel.kt | 14 +++-- presentation/src/main/res/values/strings.xml | 2 + 4 files changed, 72 insertions(+), 6 deletions(-) diff --git a/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteScreen.kt b/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteScreen.kt index c2a5146..ded044d 100644 --- a/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteScreen.kt +++ b/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteScreen.kt @@ -2,17 +2,31 @@ package dev.yjyoon.kwnotice.presentation.ui.favorite import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.size +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Favorite +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import dev.yjyoon.kwnotice.domain.model.Favorite import dev.yjyoon.kwnotice.presentation.R import dev.yjyoon.kwnotice.presentation.ui.component.KwNoticeLoading import dev.yjyoon.kwnotice.presentation.ui.component.KwNoticeSearchTopAppBar +import dev.yjyoon.kwnotice.presentation.ui.theme.KwNoticeTheme @Composable fun FavoriteScreen( @@ -67,13 +81,58 @@ fun FavoriteScreen( onMonthFilterChange = onMonthFilterChange ) } + FavoriteUiState.Empty -> { + FavoriteEmpty( + Modifier + .align(Alignment.Center) + .fillMaxWidth() + ) + } FavoriteUiState.Loading -> { KwNoticeLoading() } FavoriteUiState.Failure -> { - + // no-op } } } } } + +@Composable +fun FavoriteEmpty(modifier: Modifier = Modifier) { + Column( + modifier = modifier, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Icon( + imageVector = Icons.Default.Favorite, + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.size(32.dp) + ) + Spacer(Modifier.height(12.dp)) + Text( + text = stringResource(id = R.string.favorite_empty), + color = MaterialTheme.colorScheme.onSurfaceVariant, + textAlign = TextAlign.Center + ) + } +} + +@Preview(showBackground = true) +@Composable +private fun FavoriteScreenPreview() { + KwNoticeTheme { + FavoriteScreen( + uiState = FavoriteUiState.Empty, + filterState = FavoriteFilterState.Unspecified, + onSearch = {}, + onInitFilter = {}, + onMonthFilterChange = {}, + onTypeFilterChange = {}, + onUnbookmark = {}, + onClickFavorite = {} + ) + } +} diff --git a/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteUiState.kt b/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteUiState.kt index 8b621de..c1400c0 100644 --- a/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteUiState.kt +++ b/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteUiState.kt @@ -9,6 +9,7 @@ sealed interface FavoriteUiState { val months: List ) : FavoriteUiState + object Empty : FavoriteUiState object Loading : FavoriteUiState object Failure : FavoriteUiState } diff --git a/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteViewModel.kt b/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteViewModel.kt index 3ba46ce..bb280ec 100644 --- a/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteViewModel.kt +++ b/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteViewModel.kt @@ -22,11 +22,15 @@ class FavoriteViewModel @Inject constructor( ) : BaseViewModel() { val uiState = getAllFavoriteListUseCase().map { - FavoriteUiState.Success( - favorites = it, - types = it.map { favorite -> favorite.type }.distinct(), - months = it.map { favorite -> favorite.date.monthValue }.distinct() - ) + if (it.isNotEmpty()) { + FavoriteUiState.Success( + favorites = it, + types = it.map { favorite -> favorite.type }.distinct(), + months = it.map { favorite -> favorite.date.monthValue }.distinct() + ) + } else { + FavoriteUiState.Empty + } } .stateIn( viewModelScope, diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index 9f8a87e..b9ca1e0 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -11,6 +11,8 @@ M월 d일 공지사항을 불러올 수 없습니다.\n네트워크 연결 상태를 확인해주세요! + 아직 등록된 즐겨찾기가 없습니다.\n공지사항에서 즐겨찾기를 추가해보세요! + 검색어를 입력해주세요 전체 From 3b07c8c41f1a933f98910e68e91c6914247b58de Mon Sep 17 00:00:00 2001 From: yjyoon-dev Date: Mon, 25 Jul 2022 11:13:16 +0900 Subject: [PATCH 03/10] =?UTF-8?q?version:=20=EB=B2=84=EC=A0=84=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 327e4c1..357302a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -14,8 +14,8 @@ android { applicationId = "dev.yjyoon.kwnotice" minSdk = 24 targetSdk = 32 - versionCode = 5 - versionName = "2.0.0" + versionCode = 6 + versionName = "2.0.1" } buildTypes { From 18ebf535276b2e998f27133ec41eca38ed59d87a Mon Sep 17 00:00:00 2001 From: Yeojun Yoon Date: Tue, 26 Jul 2022 23:55:05 +0900 Subject: [PATCH 04/10] =?UTF-8?q?docs:=20README=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b02f084..85fc5d9 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ https://play.google.com/store/apps/details?id=dev.yjyoon.kwnotice # Architectures - MVVM + Clean Architecture -- Mutli Modules +- Multi Modules - app - domain - data From 8a5072d08211dd5373d2e550fadd55635b703dba Mon Sep 17 00:00:00 2001 From: yjyoon-dev Date: Mon, 1 Aug 2022 15:33:54 +0900 Subject: [PATCH 05/10] =?UTF-8?q?add:=20=EC=9B=B9=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=97=B4=EA=B8=B0=20=EA=B4=80=EB=A0=A8=20=EC=95=84=EC=9D=B4?= =?UTF-8?q?=EC=BD=98=20=EB=B0=8F=20=EB=AC=B8=EC=9E=90=EC=97=B4=20=EB=A6=AC?= =?UTF-8?q?=EC=86=8C=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- presentation/src/main/res/drawable/ic_browser.xml | 9 +++++++++ presentation/src/main/res/values/strings.xml | 2 ++ 2 files changed, 11 insertions(+) create mode 100644 presentation/src/main/res/drawable/ic_browser.xml diff --git a/presentation/src/main/res/drawable/ic_browser.xml b/presentation/src/main/res/drawable/ic_browser.xml new file mode 100644 index 0000000..a520ece --- /dev/null +++ b/presentation/src/main/res/drawable/ic_browser.xml @@ -0,0 +1,9 @@ + + + diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index b9ca1e0..c693ed3 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -21,6 +21,8 @@ 전체 날짜 + 웹으로 열기 + 새로운 공지사항 등록 알림 기존 공지사항 수정 알림 앱 정보 From 27b54b6fade2d095ea825f03b6468d0abe2ccba1 Mon Sep 17 00:00:00 2001 From: yjyoon-dev Date: Mon, 1 Aug 2022 15:34:10 +0900 Subject: [PATCH 06/10] =?UTF-8?q?feat:=20=EA=B3=B5=EC=A7=80=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EC=9B=B9=EC=9C=BC=EB=A1=9C=20=EC=97=B4=EA=B8=B0=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/ui/webview/WebViewScreen.kt | 79 ++++++++++++++----- 1 file changed, 61 insertions(+), 18 deletions(-) diff --git a/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/webview/WebViewScreen.kt b/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/webview/WebViewScreen.kt index 08f4ec5..c2f9f5e 100644 --- a/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/webview/WebViewScreen.kt +++ b/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/webview/WebViewScreen.kt @@ -4,13 +4,24 @@ import android.annotation.SuppressLint import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.ExtendedFloatingActionButton +import androidx.compose.material3.Icon import androidx.compose.material3.LinearProgressIndicator +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalUriHandler +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp import com.google.accompanist.web.LoadingState import com.google.accompanist.web.WebView import com.google.accompanist.web.rememberWebViewNavigator import com.google.accompanist.web.rememberWebViewState +import dev.yjyoon.kwnotice.presentation.R @SuppressLint("SetJavaScriptEnabled") @Composable @@ -18,25 +29,57 @@ fun WebViewScreen(url: String) { val state = rememberWebViewState(url = url) val navigator = rememberWebViewNavigator() val loadingState = state.loadingState + val uriHandler = LocalUriHandler.current - Column( - modifier = Modifier.fillMaxSize() - ) { - if (loadingState is LoadingState.Loading) { - LinearProgressIndicator( - progress = loadingState.progress, - modifier = Modifier.fillMaxWidth() + Scaffold( + floatingActionButton = { + WebViewFloatingActionButton( + onClick = { uriHandler.openUri(url) } ) - } - WebView( - state = state, - modifier = Modifier.weight(1f), - navigator = navigator, - onCreated = { - it.settings.javaScriptEnabled = true - it.settings.builtInZoomControls = true - it.settings.setSupportZoom(true) + }, + ) { innerPadding -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(innerPadding) + ) { + if (loadingState is LoadingState.Loading) { + LinearProgressIndicator( + progress = loadingState.progress, + modifier = Modifier.fillMaxWidth() + ) } - ) + WebView( + state = state, + modifier = Modifier.weight(1f), + navigator = navigator, + onCreated = { + it.settings.javaScriptEnabled = true + it.settings.builtInZoomControls = true + it.settings.setSupportZoom(true) + } + ) + } } -} \ No newline at end of file +} + +@Composable +fun WebViewFloatingActionButton( + onClick: () -> Unit +) { + ExtendedFloatingActionButton( + text = { + Text( + text = stringResource(id = R.string.open_in_browser) + ) + }, + icon = { + Icon( + painter = painterResource(id = R.drawable.ic_browser), + contentDescription = null, + modifier = Modifier.size(28.dp) + ) + }, + onClick = onClick + ) +} From 0efa6cc08bd3497c040a5bc97e2af07d04d7375a Mon Sep 17 00:00:00 2001 From: yjyoon-dev Date: Mon, 1 Aug 2022 16:35:40 +0900 Subject: [PATCH 07/10] =?UTF-8?q?feat:=20FavoriteViewModel=EC=97=90=20?= =?UTF-8?q?=EC=A6=90=EA=B2=A8=EC=B0=BE=EA=B8=B0=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kwnotice/presentation/ui/favorite/FavoriteViewModel.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteViewModel.kt b/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteViewModel.kt index bb280ec..ffec77e 100644 --- a/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteViewModel.kt +++ b/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteViewModel.kt @@ -3,6 +3,7 @@ package dev.yjyoon.kwnotice.presentation.ui.favorite import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import dev.yjyoon.kwnotice.domain.model.Favorite +import dev.yjyoon.kwnotice.domain.usecase.favorite.AddFavoriteUseCase import dev.yjyoon.kwnotice.domain.usecase.favorite.DeleteFavoriteUseCase import dev.yjyoon.kwnotice.domain.usecase.favorite.GetAllFavoriteListUseCase import dev.yjyoon.kwnotice.presentation.ui.base.BaseViewModel @@ -18,6 +19,7 @@ import javax.inject.Inject @HiltViewModel class FavoriteViewModel @Inject constructor( getAllFavoriteListUseCase: GetAllFavoriteListUseCase, + private val addFavoriteUseCase: AddFavoriteUseCase, private val deleteFavoriteUseCase: DeleteFavoriteUseCase ) : BaseViewModel() { @@ -41,6 +43,11 @@ class FavoriteViewModel @Inject constructor( private val _filterState = MutableStateFlow(FavoriteFilterState.Unspecified) val filterState: StateFlow = _filterState.asStateFlow() + fun addToFavorite(favorite: Favorite) { + launch { + addFavoriteUseCase(favorite).getOrThrow() + } + } fun deleteFromFavorite(favorite: Favorite) { launch { From 9df4316433aa9e7509047578a9f677c3e7ba9de8 Mon Sep 17 00:00:00 2001 From: yjyoon-dev Date: Mon, 1 Aug 2022 16:36:04 +0900 Subject: [PATCH 08/10] =?UTF-8?q?fix:=20NotcieViewModel=EC=9D=98=20Result?= =?UTF-8?q?=EC=97=90=20=EA=B4=80=ED=95=9C=20Throw=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yjyoon/kwnotice/presentation/ui/notice/NoticeViewModel.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/notice/NoticeViewModel.kt b/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/notice/NoticeViewModel.kt index 8162579..277c0e4 100644 --- a/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/notice/NoticeViewModel.kt +++ b/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/notice/NoticeViewModel.kt @@ -70,13 +70,13 @@ class NoticeViewModel @Inject constructor( fun addFavorite(notice: Notice) { launch { - addFavoriteUseCase(notice.toFavorite()) + addFavoriteUseCase(notice.toFavorite()).getOrThrow() } } fun deleteFavorite(notice: Notice) { launch { - deleteFavoriteUseCase(notice.toFavorite()) + deleteFavoriteUseCase(notice.toFavorite()).getOrThrow() } } From f75e260dc965143374e632fae0364d3e3ac48f7b Mon Sep 17 00:00:00 2001 From: yjyoon-dev Date: Mon, 1 Aug 2022 16:36:23 +0900 Subject: [PATCH 09/10] =?UTF-8?q?feat:=20=EC=A6=90=EA=B2=A8=EC=B0=BE?= =?UTF-8?q?=EA=B8=B0=20=EC=B7=A8=EC=86=8C=20Snackbar=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/ui/favorite/FavoriteCard.kt | 10 +- .../ui/favorite/FavoriteContent.kt | 6 +- .../ui/favorite/FavoriteScreen.kt | 138 +++++++++++++----- 3 files changed, 116 insertions(+), 38 deletions(-) diff --git a/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteCard.kt b/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteCard.kt index d72969a..5bcb1a1 100644 --- a/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteCard.kt +++ b/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteCard.kt @@ -33,7 +33,8 @@ import java.time.format.DateTimeFormatter fun FavoriteCard( favorite: Favorite, onClickFavorite: (String) -> Unit, - onUnbookmark: (Favorite) -> Unit + onUnbookmark: (Favorite) -> Unit, + showUndoSnackbar: (Favorite) -> Unit ) { ElevatedCard( onClick = { onClickFavorite(favorite.url) }, @@ -61,7 +62,12 @@ fun FavoriteCard( } FilledIconToggleButton( checked = true, - onCheckedChange = { onUnbookmark(favorite) }, + onCheckedChange = { + favorite.let { + onUnbookmark(it) + showUndoSnackbar(it) + } + }, modifier = Modifier.padding(end = 12.dp) ) { Icon( diff --git a/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteContent.kt b/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteContent.kt index f766209..725353b 100644 --- a/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteContent.kt +++ b/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteContent.kt @@ -25,7 +25,8 @@ fun FavoriteContent( onClickFavorite: (String) -> Unit, onUnbookmark: (Favorite) -> Unit, onTypeFilterChange: (String?) -> Unit, - onMonthFilterChange: (String?) -> Unit + onMonthFilterChange: (String?) -> Unit, + showUndoSnackbar: (Favorite) -> Unit ) { Column(Modifier.fillMaxSize()) { Row( @@ -56,7 +57,8 @@ fun FavoriteContent( FavoriteCard( favorite = it, onClickFavorite = onClickFavorite, - onUnbookmark = onUnbookmark + onUnbookmark = onUnbookmark, + showUndoSnackbar = showUndoSnackbar ) } } diff --git a/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteScreen.kt b/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteScreen.kt index ded044d..b2db156 100644 --- a/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteScreen.kt +++ b/presentation/src/main/java/dev/yjyoon/kwnotice/presentation/ui/favorite/FavoriteScreen.kt @@ -6,15 +6,28 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Favorite +import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Snackbar +import androidx.compose.material3.SnackbarData +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.SnackbarResult import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource @@ -27,6 +40,8 @@ import dev.yjyoon.kwnotice.presentation.R import dev.yjyoon.kwnotice.presentation.ui.component.KwNoticeLoading import dev.yjyoon.kwnotice.presentation.ui.component.KwNoticeSearchTopAppBar import dev.yjyoon.kwnotice.presentation.ui.theme.KwNoticeTheme +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch @Composable fun FavoriteScreen( @@ -44,7 +59,8 @@ fun FavoriteScreen( onUnbookmark = viewModel::deleteFromFavorite, onTypeFilterChange = viewModel::setTypeFilter, onMonthFilterChange = viewModel::setMonthFilter, - onInitFilter = viewModel::initFilter + onInitFilter = viewModel::initFilter, + addToFavorite = viewModel::addToFavorite ) } @@ -57,45 +73,98 @@ fun FavoriteScreen( onUnbookmark: (Favorite) -> Unit, onTypeFilterChange: (String?) -> Unit, onMonthFilterChange: (String?) -> Unit, - onInitFilter: () -> Unit + onInitFilter: () -> Unit, + addToFavorite: (Favorite) -> Unit ) { - Column( - Modifier.fillMaxSize() - ) { - KwNoticeSearchTopAppBar( - titleText = stringResource(id = R.string.navigation_favorite), - onSearch = onSearch, - onCloseSearh = onInitFilter - ) - Box( - Modifier.weight(1f) + val scope = rememberCoroutineScope() + var job: Job? by remember { mutableStateOf(null) } + val snackbarHostState = remember { SnackbarHostState() } + + val showUndoSnackbar: (Favorite) -> Unit = { favorite -> + job?.cancel() + job = scope.launch { + val snackbarResult = snackbarHostState.showSnackbar( + message = "즐겨찾기에서 삭제했습니다", + actionLabel = "되돌리기" + ) + when (snackbarResult) { + SnackbarResult.ActionPerformed -> { + addToFavorite(favorite) + } + SnackbarResult.Dismissed -> {} + } + } + } + + Scaffold( + snackbarHost = { + SnackbarHost(hostState = snackbarHostState) { data -> + FavoriteSnackbar(data) + } + } + ) { innerPadding -> + Column( + Modifier + .fillMaxSize() + .padding(innerPadding) ) { - when (uiState) { - is FavoriteUiState.Success -> { - FavoriteContent( - uiState = uiState, - filterState = filterState, - onClickFavorite = onClickFavorite, - onUnbookmark = onUnbookmark, - onTypeFilterChange = onTypeFilterChange, - onMonthFilterChange = onMonthFilterChange - ) + KwNoticeSearchTopAppBar( + titleText = stringResource(id = R.string.navigation_favorite), + onSearch = onSearch, + onCloseSearh = onInitFilter + ) + Box( + Modifier.weight(1f) + ) { + when (uiState) { + is FavoriteUiState.Success -> { + FavoriteContent( + uiState = uiState, + filterState = filterState, + onClickFavorite = onClickFavorite, + onUnbookmark = onUnbookmark, + onTypeFilterChange = onTypeFilterChange, + onMonthFilterChange = onMonthFilterChange, + showUndoSnackbar = showUndoSnackbar + ) + } + FavoriteUiState.Empty -> { + FavoriteEmpty( + Modifier + .align(Alignment.Center) + .fillMaxWidth() + ) + } + FavoriteUiState.Loading -> { + KwNoticeLoading() + } + FavoriteUiState.Failure -> { + // no-op + } } - FavoriteUiState.Empty -> { - FavoriteEmpty( - Modifier - .align(Alignment.Center) - .fillMaxWidth() + } + } + } +} + +@Composable +fun FavoriteSnackbar(data: SnackbarData) { + Snackbar( + Modifier.padding(18.dp), + action = { + data.visuals.actionLabel?.let { + TextButton( + onClick = { data.performAction() }, + colors = ButtonDefaults.textButtonColors( + contentColor = MaterialTheme.colorScheme.inversePrimary ) - } - FavoriteUiState.Loading -> { - KwNoticeLoading() - } - FavoriteUiState.Failure -> { - // no-op + ) { + Text(it) } } } + ) { + Text(data.visuals.message) } } @@ -132,7 +201,8 @@ private fun FavoriteScreenPreview() { onMonthFilterChange = {}, onTypeFilterChange = {}, onUnbookmark = {}, - onClickFavorite = {} + onClickFavorite = {}, + addToFavorite = {} ) } } From 15915d36535186f8ef28e0464f67873afb08bcb8 Mon Sep 17 00:00:00 2001 From: yjyoon-dev Date: Mon, 1 Aug 2022 16:42:38 +0900 Subject: [PATCH 10/10] version: update to 2.1.0 --- app/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 357302a..4e26235 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -14,8 +14,8 @@ android { applicationId = "dev.yjyoon.kwnotice" minSdk = 24 targetSdk = 32 - versionCode = 6 - versionName = "2.0.1" + versionCode = 7 + versionName = "2.1.0" } buildTypes {