From d93922bc217c7b246cd54be08c75d184796107fc Mon Sep 17 00:00:00 2001 From: ksw4015 Date: Thu, 31 Oct 2024 17:17:10 +0900 Subject: [PATCH 1/5] feat: add Item Action to SearchScreen --- .../mapper/ToPresentationModelMapper.kt | 4 +- .../domain/usecase/model/CommonCardModel.kt | 4 +- .../detail/screen/DetailScreen.kt | 6 --- .../search/screen/SearchScreen.kt | 37 ++++++++++++++++-- .../search/viewmodel/SearchActions.kt | 3 ++ .../search/viewmodel/SearchUiEffect.kt | 7 ++++ .../search/viewmodel/SearchViewModel.kt | 38 ++++++++++++------- 7 files changed, 73 insertions(+), 26 deletions(-) create mode 100644 app/src/main/java/kr/ksw/visitkorea/presentation/search/viewmodel/SearchUiEffect.kt diff --git a/app/src/main/java/kr/ksw/visitkorea/domain/usecase/mapper/ToPresentationModelMapper.kt b/app/src/main/java/kr/ksw/visitkorea/domain/usecase/mapper/ToPresentationModelMapper.kt index e54ea3a..abafb97 100644 --- a/app/src/main/java/kr/ksw/visitkorea/domain/usecase/mapper/ToPresentationModelMapper.kt +++ b/app/src/main/java/kr/ksw/visitkorea/domain/usecase/mapper/ToPresentationModelMapper.kt @@ -27,7 +27,9 @@ fun LocationBasedDTO.toCommonCardModel(): CommonCardModel = CommonCardModel( address, firstImage.toImageUrl(), title, - contentId + dist, + contentId, + contentTypeId ) fun SearchFestivalDTO.toFestival(): Festival = Festival( diff --git a/app/src/main/java/kr/ksw/visitkorea/domain/usecase/model/CommonCardModel.kt b/app/src/main/java/kr/ksw/visitkorea/domain/usecase/model/CommonCardModel.kt index 68623fd..7de5b8f 100644 --- a/app/src/main/java/kr/ksw/visitkorea/domain/usecase/model/CommonCardModel.kt +++ b/app/src/main/java/kr/ksw/visitkorea/domain/usecase/model/CommonCardModel.kt @@ -4,5 +4,7 @@ data class CommonCardModel( val address: String = "", val firstImage: String = "", val title: String = "", + val dist: String? = null, val contentId: String = "", -) + val contentTypeId: String = "", +) \ No newline at end of file diff --git a/app/src/main/java/kr/ksw/visitkorea/presentation/detail/screen/DetailScreen.kt b/app/src/main/java/kr/ksw/visitkorea/presentation/detail/screen/DetailScreen.kt index f5bfed7..464461a 100644 --- a/app/src/main/java/kr/ksw/visitkorea/presentation/detail/screen/DetailScreen.kt +++ b/app/src/main/java/kr/ksw/visitkorea/presentation/detail/screen/DetailScreen.kt @@ -99,12 +99,6 @@ private fun DetailScreen( .data(detailState.firstImage) .size(Size.ORIGINAL) .build(), - colorFilter = if(detailState.firstImage.isNotEmpty()) { - ColorFilter.tint(Color.LightGray, blendMode = BlendMode.Darken) - } - else { - null - }, contentDescription = "Detail Image", contentScale = ContentScale.Crop, ) diff --git a/app/src/main/java/kr/ksw/visitkorea/presentation/search/screen/SearchScreen.kt b/app/src/main/java/kr/ksw/visitkorea/presentation/search/screen/SearchScreen.kt index ceb33fb..2d19e70 100644 --- a/app/src/main/java/kr/ksw/visitkorea/presentation/search/screen/SearchScreen.kt +++ b/app/src/main/java/kr/ksw/visitkorea/presentation/search/screen/SearchScreen.kt @@ -1,5 +1,6 @@ package kr.ksw.visitkorea.presentation.search.screen +import android.content.Intent import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -22,10 +23,12 @@ import androidx.compose.material3.SearchBarDefaults import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview @@ -33,9 +36,13 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel import androidx.paging.compose.collectAsLazyPagingItems +import kotlinx.coroutines.flow.collectLatest +import kr.ksw.visitkorea.presentation.common.DetailParcel +import kr.ksw.visitkorea.presentation.detail.DetailActivity import kr.ksw.visitkorea.presentation.home.component.CultureCard import kr.ksw.visitkorea.presentation.search.viewmodel.SearchActions import kr.ksw.visitkorea.presentation.search.viewmodel.SearchState +import kr.ksw.visitkorea.presentation.search.viewmodel.SearchUiEffect import kr.ksw.visitkorea.presentation.search.viewmodel.SearchViewModel import kr.ksw.visitkorea.presentation.ui.theme.VisitKoreaTheme @@ -44,6 +51,22 @@ fun SearchScreen( viewModel: SearchViewModel = hiltViewModel(), ) { val searchState by viewModel.searchState.collectAsState() + val context = LocalContext.current + LaunchedEffect(viewModel.searchUiEffect) { + viewModel.searchUiEffect.collectLatest { effect -> + when(effect) { + is SearchUiEffect.StartDetailActivity -> { + context.startActivity(Intent( + context, + DetailActivity::class.java + ).apply { + putExtra("detail", effect.data) + }) + } + } + } + } + SearchScreen( searchState, viewModel::onAction @@ -133,14 +156,20 @@ fun SearchScreen( val model = searchCardModels[index] model?.run { CultureCard( - modifier = Modifier.clickable { - // Go to DetailActivity - }, title = title, address = address, image = firstImage ) { - + onAction(SearchActions.ClickCardItem( + DetailParcel( + title = title, + firstImage = firstImage, + address = address, + dist = dist, + contentId = contentId, + contentTypeId = contentTypeId + ) + )) } } } diff --git a/app/src/main/java/kr/ksw/visitkorea/presentation/search/viewmodel/SearchActions.kt b/app/src/main/java/kr/ksw/visitkorea/presentation/search/viewmodel/SearchActions.kt index 5b54945..ed4f9d6 100644 --- a/app/src/main/java/kr/ksw/visitkorea/presentation/search/viewmodel/SearchActions.kt +++ b/app/src/main/java/kr/ksw/visitkorea/presentation/search/viewmodel/SearchActions.kt @@ -1,6 +1,9 @@ package kr.ksw.visitkorea.presentation.search.viewmodel +import kr.ksw.visitkorea.presentation.common.DetailParcel + sealed interface SearchActions { data object SubmitSearchKeyword : SearchActions data class UpdateSearchKeyword(val newKeyword: String) : SearchActions + data class ClickCardItem(val data: DetailParcel) : SearchActions } \ No newline at end of file diff --git a/app/src/main/java/kr/ksw/visitkorea/presentation/search/viewmodel/SearchUiEffect.kt b/app/src/main/java/kr/ksw/visitkorea/presentation/search/viewmodel/SearchUiEffect.kt new file mode 100644 index 0000000..a9b6cdb --- /dev/null +++ b/app/src/main/java/kr/ksw/visitkorea/presentation/search/viewmodel/SearchUiEffect.kt @@ -0,0 +1,7 @@ +package kr.ksw.visitkorea.presentation.search.viewmodel + +import kr.ksw.visitkorea.presentation.common.DetailParcel + +sealed class SearchUiEffect { + data class StartDetailActivity(val data: DetailParcel) : SearchUiEffect() +} \ No newline at end of file diff --git a/app/src/main/java/kr/ksw/visitkorea/presentation/search/viewmodel/SearchViewModel.kt b/app/src/main/java/kr/ksw/visitkorea/presentation/search/viewmodel/SearchViewModel.kt index 23a1e16..8dfea3a 100644 --- a/app/src/main/java/kr/ksw/visitkorea/presentation/search/viewmodel/SearchViewModel.kt +++ b/app/src/main/java/kr/ksw/visitkorea/presentation/search/viewmodel/SearchViewModel.kt @@ -7,15 +7,21 @@ import androidx.paging.filter import androidx.paging.map import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kr.ksw.visitkorea.domain.usecase.mapper.toCommonCardModel import kr.ksw.visitkorea.domain.usecase.search.GetListByKeywordUseCase import kr.ksw.visitkorea.presentation.common.ContentType +import kr.ksw.visitkorea.presentation.common.DetailParcel +import kr.ksw.visitkorea.presentation.home.viewmodel.HomeUiEffect import javax.inject.Inject @HiltViewModel @@ -26,6 +32,10 @@ class SearchViewModel @Inject constructor( val searchState: StateFlow get() = _searchState.asStateFlow() + private val _searchUiEffect = MutableSharedFlow(replay = 0) + val searchUiEffect: SharedFlow + get() = _searchUiEffect.asSharedFlow() + fun onAction(action: SearchActions) { when(action) { is SearchActions.UpdateSearchKeyword -> { @@ -38,6 +48,9 @@ class SearchViewModel @Inject constructor( is SearchActions.SubmitSearchKeyword -> { getListByKeyword() } + is SearchActions.ClickCardItem -> { + startDetailActivity(action.data) + } } } @@ -50,33 +63,30 @@ class SearchViewModel @Inject constructor( } val searchListFlow = getListByKeywordUseCase( searchState.value.searchKeyword - ).getOrNull() - delay(300) - - if(searchListFlow == null) { - _searchState.update { - it.copy( - isLoadingImages = false - ) - } - return@launch - } - val searchCardModelFlow = searchListFlow.map { pagingData -> + ).getOrNull()?.map { pagingData -> pagingData.filter { contentTypeFilter(it.contentTypeId) }.map { it.toCommonCardModel() } - }.cachedIn(viewModelScope) + }?.cachedIn(viewModelScope) ?: emptyFlow() + + delay(500) _searchState.update { it.copy( - searchCardModelFlow = searchCardModelFlow, + searchCardModelFlow = searchListFlow, isLoadingImages = false ) } } } + private fun startDetailActivity(data: DetailParcel) { + viewModelScope.launch { + _searchUiEffect.emit(SearchUiEffect.StartDetailActivity(data)) + } + } + private fun contentTypeFilter(contentType: String) = when(contentType) { ContentType.CULTURE.contentTypeId, ContentType.LEiSURE.contentTypeId, From dc53f6ab989bc3119dc61903fdc26bd4de86488a Mon Sep 17 00:00:00 2001 From: ksw4015 Date: Thu, 10 Oct 2024 19:41:19 +0900 Subject: [PATCH 2/5] fix: add catch exception to interceptor (cherry picked from commit 893c0e66afe7934ad967135ace83c72346901e39) --- .../data/remote/api/RetrofitInterceptor.kt | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/kr/ksw/visitkorea/data/remote/api/RetrofitInterceptor.kt b/app/src/main/java/kr/ksw/visitkorea/data/remote/api/RetrofitInterceptor.kt index ffb9353..8f0c02c 100644 --- a/app/src/main/java/kr/ksw/visitkorea/data/remote/api/RetrofitInterceptor.kt +++ b/app/src/main/java/kr/ksw/visitkorea/data/remote/api/RetrofitInterceptor.kt @@ -1,13 +1,21 @@ package kr.ksw.visitkorea.data.remote.api +import android.util.Log import kr.ksw.visitkorea.BuildConfig import okhttp3.Interceptor +import okhttp3.Protocol import okhttp3.Response +import okhttp3.ResponseBody.Companion.toResponseBody +import okhttp3.internal.http2.ConnectionShutdownException +import java.io.IOException +import java.net.SocketTimeoutException +import java.net.UnknownHostException import javax.inject.Inject - - +import kotlin.jvm.Throws class RetrofitInterceptor @Inject constructor() : Interceptor { + + @Throws(Exception::class) override fun intercept(chain: Interceptor.Chain): Response { val request = chain.request() val requestUrl = request.url @@ -18,12 +26,33 @@ class RetrofitInterceptor @Inject constructor() : Interceptor { } } .build() + Log.d("RetrofitInterceptor", requestUrl.toString()) - return chain.proceed(request + val newRequest = request .newBuilder() .url(requestUrl) .build() - ) + + try { + return chain.proceed(newRequest) + } catch (e: Exception) { + e.printStackTrace() + val msg = when (e) { + is SocketTimeoutException -> "Timeout - Please check your internet connection" + is UnknownHostException -> "Unable to make a connection. Please check your internet" + is ConnectionShutdownException -> "Connection shutdown. Please check your internet" + is IOException -> "Server is unreachable, please try again later." + is IllegalStateException -> "${e.message}" + else -> "${e.message}" + } + return Response.Builder() + .request(newRequest) + .protocol(Protocol.HTTP_1_1) + .code(999) + .message(msg) + .body("{${e}}".toResponseBody(null)) + .build() + } } companion object { From 7c231dcb93b6b0e8b184581c0961cb0c4348d8e7 Mon Sep 17 00:00:00 2001 From: ksw4015 Date: Sat, 12 Oct 2024 14:03:55 +0900 Subject: [PATCH 3/5] refactor: remove unnecessary params (cherry picked from commit a1065846885a72188950c2239e919d4ba81cf891) --- .../kr/ksw/visitkorea/data/remote/api/DetailApi.kt | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/kr/ksw/visitkorea/data/remote/api/DetailApi.kt b/app/src/main/java/kr/ksw/visitkorea/data/remote/api/DetailApi.kt index f5d1709..2a6dbfb 100644 --- a/app/src/main/java/kr/ksw/visitkorea/data/remote/api/DetailApi.kt +++ b/app/src/main/java/kr/ksw/visitkorea/data/remote/api/DetailApi.kt @@ -10,8 +10,6 @@ import retrofit2.http.Query interface DetailApi { @GET("detailCommon1") suspend fun getDetailCommon( - @Query("numOfRows") numOfRows: Int = 10, - @Query("pageNo") pageNo: Int = 1, @Query("defaultYN") defaultYN: String = "Y", @Query("overviewYN") overviewYN: String = "Y", @Query("contentId") contentId: String @@ -19,24 +17,18 @@ interface DetailApi { @GET("detailIntro1") suspend fun getDetailIntro( - @Query("numOfRows") numOfRows: Int = 10, - @Query("pageNo") pageNo: Int = 1, @Query("contentId") contentId: String, @Query("contentTypeId") contentTypeId: String ): ApiResponse -/* + @GET("detailInfo1") suspend fun getDetailInfo( - @Query("numOfRows") numOfRows: Int = 10, - @Query("pageNo") pageNo: Int = 1, @Query("contentId") contentId: Int, @Query("contentTypeId") contentTypeId: Int ) -*/ + @GET("detailImage1") suspend fun getDetailImage( - @Query("numOfRows") numOfRows: Int = 10, - @Query("pageNo") pageNo: Int = 1, @Query("subImageYN") subImageYN: String = "Y", @Query("imageYN") imageYN: String = "Y", @Query("contentId") contentId: String, From 45b0aeae38fa28d8766f891bc9c1323b5ed55fcb Mon Sep 17 00:00:00 2001 From: ksw4015 Date: Mon, 4 Nov 2024 20:13:52 +0900 Subject: [PATCH 4/5] feat: add BaseViewModel to core --- .../presentation/core/BaseViewModel.kt | 20 ++++++++++++++++++ .../search/screen/SearchScreen.kt | 4 ++-- .../search/viewmodel/SearchViewModel.kt | 21 +++---------------- 3 files changed, 25 insertions(+), 20 deletions(-) create mode 100644 app/src/main/java/kr/ksw/visitkorea/presentation/core/BaseViewModel.kt diff --git a/app/src/main/java/kr/ksw/visitkorea/presentation/core/BaseViewModel.kt b/app/src/main/java/kr/ksw/visitkorea/presentation/core/BaseViewModel.kt new file mode 100644 index 0000000..78f88d7 --- /dev/null +++ b/app/src/main/java/kr/ksw/visitkorea/presentation/core/BaseViewModel.kt @@ -0,0 +1,20 @@ +package kr.ksw.visitkorea.presentation.core + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.launch + +open class BaseViewModel : ViewModel() { + private val _uiEffect = MutableSharedFlow(replay = 0) + val uiEffect: SharedFlow + get() = _uiEffect.asSharedFlow() + + protected fun startDetailActivity(effect: EFFECT) { + viewModelScope.launch { + _uiEffect.emit(effect) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/kr/ksw/visitkorea/presentation/search/screen/SearchScreen.kt b/app/src/main/java/kr/ksw/visitkorea/presentation/search/screen/SearchScreen.kt index 2d19e70..c766e72 100644 --- a/app/src/main/java/kr/ksw/visitkorea/presentation/search/screen/SearchScreen.kt +++ b/app/src/main/java/kr/ksw/visitkorea/presentation/search/screen/SearchScreen.kt @@ -52,8 +52,8 @@ fun SearchScreen( ) { val searchState by viewModel.searchState.collectAsState() val context = LocalContext.current - LaunchedEffect(viewModel.searchUiEffect) { - viewModel.searchUiEffect.collectLatest { effect -> + LaunchedEffect(viewModel.uiEffect) { + viewModel.uiEffect.collectLatest { effect -> when(effect) { is SearchUiEffect.StartDetailActivity -> { context.startActivity(Intent( diff --git a/app/src/main/java/kr/ksw/visitkorea/presentation/search/viewmodel/SearchViewModel.kt b/app/src/main/java/kr/ksw/visitkorea/presentation/search/viewmodel/SearchViewModel.kt index 8dfea3a..8146c2e 100644 --- a/app/src/main/java/kr/ksw/visitkorea/presentation/search/viewmodel/SearchViewModel.kt +++ b/app/src/main/java/kr/ksw/visitkorea/presentation/search/viewmodel/SearchViewModel.kt @@ -1,17 +1,13 @@ package kr.ksw.visitkorea.presentation.search.viewmodel -import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.paging.cachedIn import androidx.paging.filter import androidx.paging.map import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.map @@ -20,22 +16,17 @@ import kotlinx.coroutines.launch import kr.ksw.visitkorea.domain.usecase.mapper.toCommonCardModel import kr.ksw.visitkorea.domain.usecase.search.GetListByKeywordUseCase import kr.ksw.visitkorea.presentation.common.ContentType -import kr.ksw.visitkorea.presentation.common.DetailParcel -import kr.ksw.visitkorea.presentation.home.viewmodel.HomeUiEffect +import kr.ksw.visitkorea.presentation.core.BaseViewModel import javax.inject.Inject @HiltViewModel class SearchViewModel @Inject constructor( private val getListByKeywordUseCase: GetListByKeywordUseCase -): ViewModel() { +): BaseViewModel() { private val _searchState: MutableStateFlow = MutableStateFlow(SearchState()) val searchState: StateFlow get() = _searchState.asStateFlow() - private val _searchUiEffect = MutableSharedFlow(replay = 0) - val searchUiEffect: SharedFlow - get() = _searchUiEffect.asSharedFlow() - fun onAction(action: SearchActions) { when(action) { is SearchActions.UpdateSearchKeyword -> { @@ -49,7 +40,7 @@ class SearchViewModel @Inject constructor( getListByKeyword() } is SearchActions.ClickCardItem -> { - startDetailActivity(action.data) + startDetailActivity(SearchUiEffect.StartDetailActivity(action.data)) } } } @@ -81,12 +72,6 @@ class SearchViewModel @Inject constructor( } } - private fun startDetailActivity(data: DetailParcel) { - viewModelScope.launch { - _searchUiEffect.emit(SearchUiEffect.StartDetailActivity(data)) - } - } - private fun contentTypeFilter(contentType: String) = when(contentType) { ContentType.CULTURE.contentTypeId, ContentType.LEiSURE.contentTypeId, From dd7ea38f0864ebaa38de33a1817778b33a7e4606 Mon Sep 17 00:00:00 2001 From: ksw4015 Date: Mon, 4 Nov 2024 20:22:17 +0900 Subject: [PATCH 5/5] refactor: apply BaseViewModel --- .../presentation/core/BaseViewModel.kt | 2 +- .../festival/screen/FestivalScreen.kt | 4 +-- .../festival/viewmodel/FestivalViewModel.kt | 21 ++---------- .../presentation/home/screen/HomeScreen.kt | 4 +-- .../home/viewmodel/HomeViewModel.kt | 34 +++++-------------- .../presentation/more/screen/MoreScreen.kt | 4 +-- .../more/viewmodel/MoreViewModel.kt | 22 +++--------- .../search/viewmodel/SearchViewModel.kt | 2 +- 8 files changed, 24 insertions(+), 69 deletions(-) diff --git a/app/src/main/java/kr/ksw/visitkorea/presentation/core/BaseViewModel.kt b/app/src/main/java/kr/ksw/visitkorea/presentation/core/BaseViewModel.kt index 78f88d7..4f4f06e 100644 --- a/app/src/main/java/kr/ksw/visitkorea/presentation/core/BaseViewModel.kt +++ b/app/src/main/java/kr/ksw/visitkorea/presentation/core/BaseViewModel.kt @@ -12,7 +12,7 @@ open class BaseViewModel : ViewModel() { val uiEffect: SharedFlow get() = _uiEffect.asSharedFlow() - protected fun startDetailActivity(effect: EFFECT) { + protected fun postUIEffect(effect: EFFECT) { viewModelScope.launch { _uiEffect.emit(effect) } diff --git a/app/src/main/java/kr/ksw/visitkorea/presentation/festival/screen/FestivalScreen.kt b/app/src/main/java/kr/ksw/visitkorea/presentation/festival/screen/FestivalScreen.kt index ec73a4a..6a20e26 100644 --- a/app/src/main/java/kr/ksw/visitkorea/presentation/festival/screen/FestivalScreen.kt +++ b/app/src/main/java/kr/ksw/visitkorea/presentation/festival/screen/FestivalScreen.kt @@ -49,8 +49,8 @@ fun FestivalScreen( val context = LocalContext.current val hotelState by viewModel.festivalState.collectAsState() val lazyItem = hotelState.festivalModelFlow.collectAsLazyPagingItems() - LaunchedEffect(viewModel.festivalUiEffect) { - viewModel.festivalUiEffect.collectLatest { effect -> + LaunchedEffect(viewModel.uiEffect) { + viewModel.uiEffect.collectLatest { effect -> when(effect) { is FestivalUiEffect.StartDetailActivity -> { context.startActivity( diff --git a/app/src/main/java/kr/ksw/visitkorea/presentation/festival/viewmodel/FestivalViewModel.kt b/app/src/main/java/kr/ksw/visitkorea/presentation/festival/viewmodel/FestivalViewModel.kt index fd39e91..d910808 100644 --- a/app/src/main/java/kr/ksw/visitkorea/presentation/festival/viewmodel/FestivalViewModel.kt +++ b/app/src/main/java/kr/ksw/visitkorea/presentation/festival/viewmodel/FestivalViewModel.kt @@ -1,37 +1,28 @@ package kr.ksw.visitkorea.presentation.festival.viewmodel -import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.paging.cachedIn import androidx.paging.map import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kr.ksw.visitkorea.domain.usecase.festival.GetFestivalListUseCase import kr.ksw.visitkorea.domain.usecase.mapper.toFestival -import kr.ksw.visitkorea.presentation.common.DetailParcel -import kr.ksw.visitkorea.presentation.home.viewmodel.HomeUiEffect +import kr.ksw.visitkorea.presentation.core.BaseViewModel import javax.inject.Inject @HiltViewModel class FestivalViewModel @Inject constructor( private val getFestivalListUseCase: GetFestivalListUseCase -) : ViewModel() { +) : BaseViewModel() { private val _festivalState = MutableStateFlow(FestivalState()) val festivalState: StateFlow get() = _festivalState.asStateFlow() - private val _festivalUiEffect = MutableSharedFlow(replay = 0) - val festivalUiEffect: SharedFlow - get() = _festivalUiEffect.asSharedFlow() - init { getFestivalList() } @@ -39,7 +30,7 @@ class FestivalViewModel @Inject constructor( fun onAction(action: FestivalActions) { when(action) { is FestivalActions.ClickFestivalCardItem -> { - startDetailActivity(action.data) + postUIEffect(FestivalUiEffect.StartDetailActivity(action.data)) } } } @@ -67,10 +58,4 @@ class FestivalViewModel @Inject constructor( } } } - - private fun startDetailActivity(data: DetailParcel) { - viewModelScope.launch { - _festivalUiEffect.emit(FestivalUiEffect.StartDetailActivity(data)) - } - } } \ No newline at end of file diff --git a/app/src/main/java/kr/ksw/visitkorea/presentation/home/screen/HomeScreen.kt b/app/src/main/java/kr/ksw/visitkorea/presentation/home/screen/HomeScreen.kt index 6c81fc3..874ced6 100644 --- a/app/src/main/java/kr/ksw/visitkorea/presentation/home/screen/HomeScreen.kt +++ b/app/src/main/java/kr/ksw/visitkorea/presentation/home/screen/HomeScreen.kt @@ -66,8 +66,8 @@ fun HomeScreen( ) { val homeState by homeViewModel.homeState.collectAsState() val context = LocalContext.current - LaunchedEffect(homeViewModel.homeUiEffect) { - homeViewModel.homeUiEffect.collectLatest { effect -> + LaunchedEffect(homeViewModel.uiEffect) { + homeViewModel.uiEffect.collectLatest { effect -> when(effect) { is HomeUiEffect.StartMoreActivity -> { context.startActivity(Intent( diff --git a/app/src/main/java/kr/ksw/visitkorea/presentation/home/viewmodel/HomeViewModel.kt b/app/src/main/java/kr/ksw/visitkorea/presentation/home/viewmodel/HomeViewModel.kt index 3f9ea84..2707a96 100644 --- a/app/src/main/java/kr/ksw/visitkorea/presentation/home/viewmodel/HomeViewModel.kt +++ b/app/src/main/java/kr/ksw/visitkorea/presentation/home/viewmodel/HomeViewModel.kt @@ -1,18 +1,13 @@ package kr.ksw.visitkorea.presentation.home.viewmodel import android.annotation.SuppressLint -import android.util.Log -import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.google.android.gms.location.FusedLocationProviderClient import com.google.android.gms.location.Priority import com.google.android.gms.tasks.CancellationTokenSource import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch @@ -20,8 +15,7 @@ import kr.ksw.visitkorea.domain.usecase.home.GetCultureCenterForHomeUseCase import kr.ksw.visitkorea.domain.usecase.home.GetLeisureSportsForHomeUseCase import kr.ksw.visitkorea.domain.usecase.home.GetRestaurantForHomeUseCase import kr.ksw.visitkorea.domain.usecase.home.GetTouristSpotForHomeUseCase -import kr.ksw.visitkorea.presentation.common.ContentType -import kr.ksw.visitkorea.presentation.common.DetailParcel +import kr.ksw.visitkorea.presentation.core.BaseViewModel import javax.inject.Inject @SuppressLint("MissingPermission") @@ -32,15 +26,11 @@ class HomeViewModel @Inject constructor( private val getLeisureSportsForHomeUseCase: GetLeisureSportsForHomeUseCase, private val getRestaurantForHomeUseCase: GetRestaurantForHomeUseCase, private val fusedLocationProviderClient: FusedLocationProviderClient -): ViewModel() { +): BaseViewModel() { private val _homeState = MutableStateFlow(HomeState()) val homeState: StateFlow get() = _homeState.asStateFlow() - private val _homeUiEffect = MutableSharedFlow(replay = 0) - val homeUiEffect: SharedFlow - get() = _homeUiEffect.asSharedFlow() - init { fusedLocationProviderClient.getCurrentLocation( Priority.PRIORITY_HIGH_ACCURACY, @@ -58,10 +48,14 @@ class HomeViewModel @Inject constructor( fun onAction(action: HomeActions) { when(action) { is HomeActions.ClickMoreButton -> { - startMoreActivity(action.contentType) + postUIEffect( + HomeUiEffect.StartMoreActivity(action.contentType) + ) } is HomeActions.ClickCardItem -> { - startDetailActivity(action.data) + postUIEffect( + HomeUiEffect.StartDetailActivity(action.data) + ) } } } @@ -142,16 +136,4 @@ class HomeViewModel @Inject constructor( } } } - - private fun startMoreActivity(contentType: ContentType) { - viewModelScope.launch { - _homeUiEffect.emit(HomeUiEffect.StartMoreActivity(contentType)) - } - } - - private fun startDetailActivity(data: DetailParcel) { - viewModelScope.launch { - _homeUiEffect.emit(HomeUiEffect.StartDetailActivity(data)) - } - } } \ No newline at end of file diff --git a/app/src/main/java/kr/ksw/visitkorea/presentation/more/screen/MoreScreen.kt b/app/src/main/java/kr/ksw/visitkorea/presentation/more/screen/MoreScreen.kt index 1ef7ab5..8604527 100644 --- a/app/src/main/java/kr/ksw/visitkorea/presentation/more/screen/MoreScreen.kt +++ b/app/src/main/java/kr/ksw/visitkorea/presentation/more/screen/MoreScreen.kt @@ -56,8 +56,8 @@ fun MoreScreen( val state = rememberPullToRefreshState() val context = LocalContext.current - LaunchedEffect(viewModel.moreUiEffect) { - viewModel.moreUiEffect.collectLatest { effect -> + LaunchedEffect(viewModel.uiEffect) { + viewModel.uiEffect.collectLatest { effect -> when(effect) { is MoreUiEffect.StartDetailActivity -> { context.startActivity(Intent( diff --git a/app/src/main/java/kr/ksw/visitkorea/presentation/more/viewmodel/MoreViewModel.kt b/app/src/main/java/kr/ksw/visitkorea/presentation/more/viewmodel/MoreViewModel.kt index 86fde1f..532d492 100644 --- a/app/src/main/java/kr/ksw/visitkorea/presentation/more/viewmodel/MoreViewModel.kt +++ b/app/src/main/java/kr/ksw/visitkorea/presentation/more/viewmodel/MoreViewModel.kt @@ -1,7 +1,6 @@ package kr.ksw.visitkorea.presentation.more.viewmodel import android.annotation.SuppressLint -import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.paging.cachedIn import androidx.paging.map @@ -10,11 +9,8 @@ import com.google.android.gms.location.Priority import com.google.android.gms.tasks.CancellationTokenSource import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.map @@ -22,9 +18,9 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kr.ksw.visitkorea.domain.usecase.mapper.toMoreCardModel import kr.ksw.visitkorea.domain.usecase.more.GetMoreListUseCase -import kr.ksw.visitkorea.presentation.common.DetailParcel import kr.ksw.visitkorea.presentation.common.latitudeToStringOrDefault import kr.ksw.visitkorea.presentation.common.longitudeToStringOrDefault +import kr.ksw.visitkorea.presentation.core.BaseViewModel import javax.inject.Inject @SuppressLint("MissingPermission") @@ -32,19 +28,17 @@ import javax.inject.Inject class MoreViewModel @Inject constructor( private val getMoreListUseCase: GetMoreListUseCase, private val fusedLocationProviderClient: FusedLocationProviderClient, -): ViewModel() { +): BaseViewModel() { private val _moreState = MutableStateFlow(MoreState()) val moreState: StateFlow get() = _moreState.asStateFlow() - private val _moreUiEffect = MutableSharedFlow(replay = 0) - val moreUiEffect: SharedFlow - get() = _moreUiEffect.asSharedFlow() - fun onAction(action: MoreActions) { when(action) { is MoreActions.ClickCardItem -> { - startDetailActivity(action.data) + postUIEffect( + MoreUiEffect.StartDetailActivity(action.data) + ) } } } @@ -99,10 +93,4 @@ class MoreViewModel @Inject constructor( } } } - - private fun startDetailActivity(data: DetailParcel) { - viewModelScope.launch { - _moreUiEffect.emit(MoreUiEffect.StartDetailActivity(data)) - } - } } \ No newline at end of file diff --git a/app/src/main/java/kr/ksw/visitkorea/presentation/search/viewmodel/SearchViewModel.kt b/app/src/main/java/kr/ksw/visitkorea/presentation/search/viewmodel/SearchViewModel.kt index 8146c2e..39b40be 100644 --- a/app/src/main/java/kr/ksw/visitkorea/presentation/search/viewmodel/SearchViewModel.kt +++ b/app/src/main/java/kr/ksw/visitkorea/presentation/search/viewmodel/SearchViewModel.kt @@ -40,7 +40,7 @@ class SearchViewModel @Inject constructor( getListByKeyword() } is SearchActions.ClickCardItem -> { - startDetailActivity(SearchUiEffect.StartDetailActivity(action.data)) + postUIEffect(SearchUiEffect.StartDetailActivity(action.data)) } } }