diff --git a/core/onboarding/src/main/java/in/koreatech/koin/core/onboarding/OnboardingType.kt b/core/onboarding/src/main/java/in/koreatech/koin/core/onboarding/OnboardingType.kt index 0dad8b6e7..cfec80243 100644 --- a/core/onboarding/src/main/java/in/koreatech/koin/core/onboarding/OnboardingType.kt +++ b/core/onboarding/src/main/java/in/koreatech/koin/core/onboarding/OnboardingType.kt @@ -12,5 +12,6 @@ enum class OnboardingType( DINING_IMAGE(R.string.dining_image_tooltip), DINING_NOTIFICATION(0), DINING_SHARE(0), - ARTICLE_KEYWORD(R.string.article_keyword_tooltip) + ARTICLE_KEYWORD(R.string.article_keyword_tooltip), + REVIEW_SORTING(R.string.store_review_sorting_tooltip) } \ No newline at end of file diff --git a/core/onboarding/src/main/res/values/strings.xml b/core/onboarding/src/main/res/values/strings.xml index d7ce2a42c..c082b1f58 100644 --- a/core/onboarding/src/main/res/values/strings.xml +++ b/core/onboarding/src/main/res/values/strings.xml @@ -3,4 +3,5 @@ 식단 사진을 확인해보세요! 식단이 마음에 들었다면 공유하기! 키워드를 추가하고 맞춤 알림을 받아보세요! + 지금 리뷰가 가장 많은 상점을 확인해보세요! \ No newline at end of file diff --git a/core/src/main/res/drawable/default_event_image.png b/core/src/main/res/drawable/default_event_image.png new file mode 100644 index 000000000..e7077b176 Binary files /dev/null and b/core/src/main/res/drawable/default_event_image.png differ diff --git a/core/src/main/res/drawable/left_event_arrow.xml b/core/src/main/res/drawable/left_event_arrow.xml new file mode 100644 index 000000000..3cf3327c1 --- /dev/null +++ b/core/src/main/res/drawable/left_event_arrow.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/core/src/main/res/drawable/right_event_arrow.xml b/core/src/main/res/drawable/right_event_arrow.xml new file mode 100644 index 000000000..e97247d85 --- /dev/null +++ b/core/src/main/res/drawable/right_event_arrow.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/core/src/main/res/drawable/rounded_corners_black.xml b/core/src/main/res/drawable/rounded_corners_black.xml new file mode 100644 index 000000000..8897a9943 --- /dev/null +++ b/core/src/main/res/drawable/rounded_corners_black.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/data/src/main/java/in/koreatech/koin/data/api/auth/UserAuthApi.kt b/data/src/main/java/in/koreatech/koin/data/api/auth/UserAuthApi.kt index 8d7947976..81bc3578c 100644 --- a/data/src/main/java/in/koreatech/koin/data/api/auth/UserAuthApi.kt +++ b/data/src/main/java/in/koreatech/koin/data/api/auth/UserAuthApi.kt @@ -92,4 +92,8 @@ interface UserAuthApi { @POST("abtest/assign") suspend fun postABTestAssign(@Body abTestRequest: ABTestRequest): ABTestResponse + + @POST(URLConstant.SHOPS.SHOPS + "/{storeId}/call-notification") + suspend fun postReviewPromptNotification(@Path("storeId") storeId: Int) + } \ No newline at end of file diff --git a/data/src/main/java/in/koreatech/koin/data/mapper/NotificationMapper.kt b/data/src/main/java/in/koreatech/koin/data/mapper/NotificationMapper.kt index 1cda10d55..fdf26a8c2 100644 --- a/data/src/main/java/in/koreatech/koin/data/mapper/NotificationMapper.kt +++ b/data/src/main/java/in/koreatech/koin/data/mapper/NotificationMapper.kt @@ -30,6 +30,7 @@ fun String.toSubscribesType(): SubscribesType = when (this) { Subscribes.DINING_SOLD_OUT -> SubscribesType.DINING_SOLD_OUT Subscribes.DINING_IMAGE_UPLOAD -> SubscribesType.DINING_IMAGE_UPLOAD Subscribes.ARTICLE_KEYWORD -> SubscribesType.ARTICLE_KEYWORD + Subscribes.REVIEW_PROMPT -> SubscribesType.REVIEW_PROMPT else -> SubscribesType.NOTHING } diff --git a/data/src/main/java/in/koreatech/koin/data/mapper/StoreMapper.kt b/data/src/main/java/in/koreatech/koin/data/mapper/StoreMapper.kt index 88f039e3a..602016fa5 100644 --- a/data/src/main/java/in/koreatech/koin/data/mapper/StoreMapper.kt +++ b/data/src/main/java/in/koreatech/koin/data/mapper/StoreMapper.kt @@ -39,7 +39,6 @@ import `in`.koreatech.koin.domain.model.store.StoreReview import `in`.koreatech.koin.domain.model.store.StoreReviewContent import `in`.koreatech.koin.domain.model.store.StoreReviewStatistics import `in`.koreatech.koin.domain.model.store.StoreWithMenu -import `in`.koreatech.koin.domain.model.store.toStoreCategory import `in`.koreatech.koin.domain.util.ext.localDayOfWeekName fun StoreItemResponse.toStore(): Store = Store( @@ -61,7 +60,7 @@ fun StoreItemResponse.toStore(): Store = Store( closeTime = it.closeTime ?: "" ) }.orEmpty().getOrElse(0) { Store.OpenData(localDayOfWeekName, false, "00:00", "00:00") }, - categoryIds = categoryIds?.map { it.toStoreCategory() }.orEmpty() + categoryIds = categoryIds ) fun StoreEventItemReponse.toStoreEvent(): StoreEvent = StoreEvent( diff --git a/data/src/main/java/in/koreatech/koin/data/repository/NotificationRepositoryImpl.kt b/data/src/main/java/in/koreatech/koin/data/repository/NotificationRepositoryImpl.kt index a865174a5..3ef1cc490 100644 --- a/data/src/main/java/in/koreatech/koin/data/repository/NotificationRepositoryImpl.kt +++ b/data/src/main/java/in/koreatech/koin/data/repository/NotificationRepositoryImpl.kt @@ -15,6 +15,10 @@ class NotificationRepositoryImpl @Inject constructor( return notificationRemoteDataSource.getPermissionInfo().toNotificationPermissionInfo() } + override suspend fun postReviewPromptNotification(storeId: Int) { + notificationRemoteDataSource.postReviewPromptNotification(storeId) + } + override suspend fun updateSubscription(type: SubscribesType) { notificationRemoteDataSource.updateSubscription(type.toString()) } diff --git a/data/src/main/java/in/koreatech/koin/data/response/store/StoreItemResponse.kt b/data/src/main/java/in/koreatech/koin/data/response/store/StoreItemResponse.kt index 3c6056858..3d260182c 100644 --- a/data/src/main/java/in/koreatech/koin/data/response/store/StoreItemResponse.kt +++ b/data/src/main/java/in/koreatech/koin/data/response/store/StoreItemResponse.kt @@ -10,7 +10,7 @@ data class StoreItemResponse( @SerializedName("pay_card") val isCardOk: Boolean?, @SerializedName("pay_bank") val isBankOk: Boolean?, @SerializedName("open") val open: List?, - @SerializedName("category_ids") val categoryIds: List?, + @SerializedName("category_ids") val categoryIds: List, @SerializedName("is_event") val isEvent: Boolean?, @SerializedName("is_open") val isOpen: Boolean?, @SerializedName("average_rate") val averageRate : Double, diff --git a/data/src/main/java/in/koreatech/koin/data/source/remote/NotificationRemoteDataSource.kt b/data/src/main/java/in/koreatech/koin/data/source/remote/NotificationRemoteDataSource.kt index 951a55399..7612e3063 100644 --- a/data/src/main/java/in/koreatech/koin/data/source/remote/NotificationRemoteDataSource.kt +++ b/data/src/main/java/in/koreatech/koin/data/source/remote/NotificationRemoteDataSource.kt @@ -10,6 +10,10 @@ class NotificationRemoteDataSource @Inject constructor( suspend fun getPermissionInfo(): NotificationPermissionInfoResponse = userAuthApi.getNotificationPermissionInfo() + suspend fun postReviewPromptNotification(storeId: Int) { + userAuthApi.postReviewPromptNotification(storeId) + } + suspend fun updateSubscription(type: String) { userAuthApi.updateSubscription(type) } diff --git a/domain/src/main/java/in/koreatech/koin/domain/model/notification/NotificationPermissionInfo.kt b/domain/src/main/java/in/koreatech/koin/domain/model/notification/NotificationPermissionInfo.kt index f8d40d365..3471d63b2 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/model/notification/NotificationPermissionInfo.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/model/notification/NotificationPermissionInfo.kt @@ -15,6 +15,7 @@ data class Subscribes( const val DINING_SOLD_OUT = "DINING_SOLD_OUT" const val DINING_IMAGE_UPLOAD = "DINING_IMAGE_UPLOAD" const val ARTICLE_KEYWORD = "ARTICLE_KEYWORD" + const val REVIEW_PROMPT = "REVIEW_PROMPT" } } @@ -30,7 +31,7 @@ data class SubscribesDetail( } enum class SubscribesType { - SHOP_EVENT, DINING_SOLD_OUT, DINING_IMAGE_UPLOAD, NOTHING, ARTICLE_KEYWORD + SHOP_EVENT, DINING_SOLD_OUT, DINING_IMAGE_UPLOAD, NOTHING, ARTICLE_KEYWORD, REVIEW_PROMPT } enum class SubscribesDetailType { diff --git a/domain/src/main/java/in/koreatech/koin/domain/model/store/Store.kt b/domain/src/main/java/in/koreatech/koin/domain/model/store/Store.kt index a78ac95d3..b143d6326 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/model/store/Store.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/model/store/Store.kt @@ -18,7 +18,7 @@ data class Store( val averageRate : Double, val reviewCount : Int, val open: OpenData, - val categoryIds: List + val categoryIds: List ) { data class OpenData( val dayOfWeek: String, diff --git a/domain/src/main/java/in/koreatech/koin/domain/model/store/StoreCategory.kt b/domain/src/main/java/in/koreatech/koin/domain/model/store/StoreCategory.kt index 97d1c3dcf..455e94aa3 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/model/store/StoreCategory.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/model/store/StoreCategory.kt @@ -13,17 +13,3 @@ sealed class StoreCategory(val code: Int) { object BeautySalon : StoreCategory(9) object Etc : StoreCategory(10) } - -fun Int.toStoreCategory() = when (this) { - 1 -> StoreCategory.All - 2 -> StoreCategory.Chicken - 3 -> StoreCategory.Pizza - 4 -> StoreCategory.DOSIRAK - 5 -> StoreCategory.PorkFeet - 6 -> StoreCategory.Chinese - 7 -> StoreCategory.NormalFood - 8 -> StoreCategory.Cafe - 9 -> StoreCategory.BeautySalon - 10 -> StoreCategory.Etc - else -> null -} \ No newline at end of file diff --git a/domain/src/main/java/in/koreatech/koin/domain/repository/NotificationRepository.kt b/domain/src/main/java/in/koreatech/koin/domain/repository/NotificationRepository.kt index c034ec60c..5dc3593c0 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/repository/NotificationRepository.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/repository/NotificationRepository.kt @@ -6,6 +6,7 @@ import `in`.koreatech.koin.domain.model.notification.SubscribesType interface NotificationRepository { suspend fun getPermissionInfo(): NotificationPermissionInfo + suspend fun postReviewPromptNotification(storeId: Int) suspend fun updateSubscription(type: SubscribesType) suspend fun updateSubscriptionDetail(type: SubscribesDetailType) suspend fun deleteSubscription(type: SubscribesType) diff --git a/domain/src/main/java/in/koreatech/koin/domain/usecase/business/SearchStoresUsecase.kt b/domain/src/main/java/in/koreatech/koin/domain/usecase/business/SearchStoresUsecase.kt index 75dfd7516..e8e2f1227 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/usecase/business/SearchStoresUsecase.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/usecase/business/SearchStoresUsecase.kt @@ -1,7 +1,6 @@ package `in`.koreatech.koin.domain.usecase.business import `in`.koreatech.koin.domain.model.store.Store -import `in`.koreatech.koin.domain.model.store.StoreCategory import `in`.koreatech.koin.domain.repository.StoreRepository import `in`.koreatech.koin.domain.util.ext.sortedOpenStore import `in`.koreatech.koin.domain.util.match diff --git a/domain/src/main/java/in/koreatech/koin/domain/usecase/store/GetRecommendStoresUseCase.kt b/domain/src/main/java/in/koreatech/koin/domain/usecase/store/GetRecommendStoresUseCase.kt index 1850f9fa3..f08a1ebdd 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/usecase/store/GetRecommendStoresUseCase.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/usecase/store/GetRecommendStoresUseCase.kt @@ -2,7 +2,6 @@ package `in`.koreatech.koin.domain.usecase.store import `in`.koreatech.koin.domain.constant.STORE_RECOMMEND_STORES import `in`.koreatech.koin.domain.model.store.Store -import `in`.koreatech.koin.domain.model.store.StoreCategory import `in`.koreatech.koin.domain.model.store.StoreWithMenu import `in`.koreatech.koin.domain.repository.StoreRepository import `in`.koreatech.koin.domain.util.ext.sortedOpenStore @@ -17,11 +16,11 @@ class GetRecommendStoresUseCase @Inject constructor( return storeRepository.getStores() .filter { val shopRandomCategoryId = - store.shopCategories?.filter { it.id != StoreCategory.All.code } + store.shopCategories?.filter { it.id != 0 } ?.randomOrNull()?.id it.categoryIds.find { - it?.code == shopRandomCategoryId - }?.code == shopRandomCategoryId && !it.open.closed && it.uid != store.uid + it == shopRandomCategoryId + } == shopRandomCategoryId && !it.open.closed && it.uid != store.uid } .shuffled() .take(STORE_RECOMMEND_STORES) diff --git a/domain/src/main/java/in/koreatech/koin/domain/usecase/store/GetStoresUseCase.kt b/domain/src/main/java/in/koreatech/koin/domain/usecase/store/GetStoresUseCase.kt index 72a4607c9..8280cf81b 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/usecase/store/GetStoresUseCase.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/usecase/store/GetStoresUseCase.kt @@ -1,18 +1,16 @@ package `in`.koreatech.koin.domain.usecase.store import `in`.koreatech.koin.domain.model.store.Store -import `in`.koreatech.koin.domain.model.store.StoreCategory +import `in`.koreatech.koin.domain.model.store.StoreCategories import `in`.koreatech.koin.domain.model.store.StoreSorter import `in`.koreatech.koin.domain.repository.StoreRepository -import `in`.koreatech.koin.domain.util.ext.sortedOpenStore -import `in`.koreatech.koin.domain.util.match import javax.inject.Inject class GetStoresUseCase @Inject constructor( private val storeRepository: StoreRepository, ) { suspend operator fun invoke( - category: StoreCategory? = null, + category: StoreCategories? = null, storeSorter: StoreSorter? = StoreSorter.NONE, isOperating: Boolean? = null, isDelivery: Boolean? = null @@ -23,7 +21,7 @@ class GetStoresUseCase @Inject constructor( isDelivery = isDelivery ) .filter { - category in it.categoryIds + category?.id in it.categoryIds } } } diff --git a/domain/src/main/java/in/koreatech/koin/domain/usecase/store/ReviewPromptUscCase.kt b/domain/src/main/java/in/koreatech/koin/domain/usecase/store/ReviewPromptUscCase.kt new file mode 100644 index 000000000..0c490376e --- /dev/null +++ b/domain/src/main/java/in/koreatech/koin/domain/usecase/store/ReviewPromptUscCase.kt @@ -0,0 +1,20 @@ +package `in`.koreatech.koin.domain.usecase.store + +import `in`.koreatech.koin.domain.error.user.UserErrorHandler +import `in`.koreatech.koin.domain.model.error.ErrorHandler +import `in`.koreatech.koin.domain.repository.NotificationRepository +import javax.inject.Inject + +class ReviewPromptUscCase @Inject constructor( + private val notificationRepository: NotificationRepository, + private val userErrorHandler: UserErrorHandler, +) { + suspend operator fun invoke(storeId: Int): Pair { + return try { + notificationRepository.postReviewPromptNotification(storeId) + Unit to null + } catch (e: Exception) { + null to userErrorHandler.handleUserError(e) + } + } +} \ No newline at end of file diff --git a/domain/src/main/java/in/koreatech/koin/domain/usecase/store/SearchStoreUseCase.kt b/domain/src/main/java/in/koreatech/koin/domain/usecase/store/SearchStoreUseCase.kt index 09dd42676..856cbf9ed 100644 --- a/domain/src/main/java/in/koreatech/koin/domain/usecase/store/SearchStoreUseCase.kt +++ b/domain/src/main/java/in/koreatech/koin/domain/usecase/store/SearchStoreUseCase.kt @@ -1,7 +1,7 @@ package `in`.koreatech.koin.domain.usecase.store import `in`.koreatech.koin.domain.model.store.Store -import `in`.koreatech.koin.domain.model.store.StoreCategory +import `in`.koreatech.koin.domain.model.store.StoreCategories import `in`.koreatech.koin.domain.model.store.StoreSorter import `in`.koreatech.koin.domain.repository.StoreRepository import kotlinx.coroutines.CoroutineDispatcher @@ -13,7 +13,7 @@ class SearchStoreUseCase constructor( ) { suspend operator fun invoke( search: String = "", - category: StoreCategory? = null, + category: StoreCategories? = null, storeSorter: StoreSorter? = null, isOperating: Boolean? = null, isDelivery: Boolean? = null @@ -26,7 +26,7 @@ class SearchStoreUseCase constructor( isDelivery = isDelivery ) .filter { - if (search == "") category in it.categoryIds else it.name.contains(search) + if (search == "") category?.id in it.categoryIds else it.name.contains(search) } } } diff --git a/koin/src/main/java/in/koreatech/koin/ui/notification/NotificationActivity.kt b/koin/src/main/java/in/koreatech/koin/ui/notification/NotificationActivity.kt index 813c42ff8..f61c3b1fe 100644 --- a/koin/src/main/java/in/koreatech/koin/ui/notification/NotificationActivity.kt +++ b/koin/src/main/java/in/koreatech/koin/ui/notification/NotificationActivity.kt @@ -71,6 +71,7 @@ class NotificationActivity : ActivityBase() { textViewNotificationSetting.isVisible = false notificationDiningSoldOut.isEnabled = true notificationShopEvent.isEnabled = true + notificationReviewPrompt.isEnabled = true notificationDiningImageUpload.isEnabled = true } } @@ -81,6 +82,7 @@ class NotificationActivity : ActivityBase() { textViewNotificationSetting.isVisible = true notificationDiningSoldOut.disableAll() notificationShopEvent.disableAll() + notificationReviewPrompt.disableAll() notificationDiningImageUpload.disableAll() } } @@ -115,6 +117,13 @@ class NotificationActivity : ActivityBase() { } } + SubscribesType.REVIEW_PROMPT -> with(binding.notificationReviewPrompt) { + if (isChecked != it.isPermit) { + fakeChecked = it.isPermit + isChecked = it.isPermit + } + } + SubscribesType.NOTHING -> Unit else -> Unit } @@ -176,6 +185,11 @@ class NotificationActivity : ActivityBase() { binding.notificationShopEvent.setOnSwitchClickListener { isChecked -> handleSubscription(isChecked, SubscribesType.SHOP_EVENT) } + + binding.notificationReviewPrompt.setOnSwitchClickListener { isChecked -> + handleSubscription(isChecked, SubscribesType.REVIEW_PROMPT) + } + binding.notificationDiningImageUpload.setOnSwitchClickListener { isChecked -> EventLogger.logClickEvent( EventAction.CAMPUS, diff --git a/koin/src/main/java/in/koreatech/koin/ui/notification/viewmodel/NotificationViewModel.kt b/koin/src/main/java/in/koreatech/koin/ui/notification/viewmodel/NotificationViewModel.kt index 5631245b6..1fc357260 100644 --- a/koin/src/main/java/in/koreatech/koin/ui/notification/viewmodel/NotificationViewModel.kt +++ b/koin/src/main/java/in/koreatech/koin/ui/notification/viewmodel/NotificationViewModel.kt @@ -70,8 +70,7 @@ class NotificationViewModel @Inject constructor( } sealed class NotificationUiState { - data class Success(val notificationPermissionInfo: NotificationPermissionInfo) : - NotificationUiState() + data class Success(val notificationPermissionInfo: NotificationPermissionInfo) : NotificationUiState() data object Failed : NotificationUiState() data object Nothing : NotificationUiState() diff --git a/koin/src/main/java/in/koreatech/koin/ui/store/activity/CallBenefitStoreActivity.kt b/koin/src/main/java/in/koreatech/koin/ui/store/activity/CallBenefitStoreActivity.kt index 7151bd546..5efa509ca 100644 --- a/koin/src/main/java/in/koreatech/koin/ui/store/activity/CallBenefitStoreActivity.kt +++ b/koin/src/main/java/in/koreatech/koin/ui/store/activity/CallBenefitStoreActivity.kt @@ -9,23 +9,18 @@ import androidx.activity.viewModels import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle -import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager import dagger.hilt.android.AndroidEntryPoint import `in`.koreatech.koin.R -import `in`.koreatech.koin.core.activity.ActivityBase import `in`.koreatech.koin.core.analytics.EventAction import `in`.koreatech.koin.core.analytics.EventExtra import `in`.koreatech.koin.core.analytics.EventLogger import `in`.koreatech.koin.core.appbar.AppBarBase import `in`.koreatech.koin.core.constant.AnalyticsConstant import `in`.koreatech.koin.core.util.dataBinding -import `in`.koreatech.koin.core.viewpager.HorizontalMarginItemDecoration import `in`.koreatech.koin.databinding.ActivityCallBenefitStoreMainBinding -import `in`.koreatech.koin.domain.model.store.StoreCategory import `in`.koreatech.koin.domain.model.store.StoreSorter import `in`.koreatech.koin.ui.navigation.KoinNavigationDrawerTimeActivity -import `in`.koreatech.koin.ui.navigation.KoinNavigationDrawerActivity import `in`.koreatech.koin.ui.navigation.state.MenuState import `in`.koreatech.koin.ui.store.adapter.StoreBenefitRecyclerAdapter import `in`.koreatech.koin.ui.store.adapter.StoreEventPagerAdapter @@ -62,7 +57,7 @@ class CallBenefitStoreActivity : KoinNavigationDrawerTimeActivity() { EventExtra(AnalyticsConstant.CURRENT_PAGE, it.name), EventExtra(AnalyticsConstant.DURATION_TIME, getElapsedTimeAndReset().toString()) ) - storeDetailContract.launch(Triple(it.uid, getStoreCategoryName(StoreCategory.All), true)) + storeDetailContract.launch(Triple(it.uid, viewModel.category.value?.name, true)) } } private val storeEventPagerAdapter = StoreEventPagerAdapter().apply { @@ -75,7 +70,7 @@ class CallBenefitStoreActivity : KoinNavigationDrawerTimeActivity() { storeDetailContract.launch( Triple( it.shopId, - getStoreCategoryName(viewModel.category.value), + viewModel.category.value?.name, false ) ) @@ -198,21 +193,6 @@ class CallBenefitStoreActivity : KoinNavigationDrawerTimeActivity() { viewModel.settingStoreSorter(StoreSorter.NONE) } - private fun getStoreCategoryName(category: StoreCategory?): String { - return when (category) { - StoreCategory.Chicken -> getString(R.string.chicken) - StoreCategory.Pizza -> getString(R.string.pizza) - StoreCategory.DOSIRAK -> getString(R.string.dorisak) - StoreCategory.PorkFeet -> getString(R.string.pork_feet) - StoreCategory.Chinese -> getString(R.string.chinese) - StoreCategory.NormalFood -> getString(R.string.normal_food) - StoreCategory.Cafe -> getString(R.string.cafe) - StoreCategory.BeautySalon -> getString(R.string.beauty_salon) - StoreCategory.Etc -> getString(R.string.etc) - StoreCategory.All, null -> getString(R.string.see_all) - } - } - private fun initOnRefreshDiningList() { binding.storeSwiperefreshlayout.setOnRefreshListener { viewModel.refreshStores() diff --git a/koin/src/main/java/in/koreatech/koin/ui/store/activity/StoreActivity.kt b/koin/src/main/java/in/koreatech/koin/ui/store/activity/StoreActivity.kt index 95d631857..f4d2e57b8 100644 --- a/koin/src/main/java/in/koreatech/koin/ui/store/activity/StoreActivity.kt +++ b/koin/src/main/java/in/koreatech/koin/ui/store/activity/StoreActivity.kt @@ -3,6 +3,7 @@ package `in`.koreatech.koin.ui.store.activity import android.os.Bundle import android.os.Handler import android.os.Looper +import android.util.Log import android.view.MotionEvent import androidx.activity.viewModels import androidx.core.content.ContextCompat @@ -14,7 +15,6 @@ import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager -import androidx.viewpager.widget.ViewPager import androidx.viewpager2.widget.ViewPager2 import dagger.hilt.android.AndroidEntryPoint import `in`.koreatech.koin.R @@ -24,12 +24,14 @@ import `in`.koreatech.koin.core.analytics.EventLogger import `in`.koreatech.koin.core.analytics.EventUtils import `in`.koreatech.koin.core.appbar.AppBarBase import `in`.koreatech.koin.core.constant.AnalyticsConstant +import `in`.koreatech.koin.core.onboarding.ArrowDirection +import `in`.koreatech.koin.core.onboarding.OnboardingManager +import `in`.koreatech.koin.core.onboarding.OnboardingType import `in`.koreatech.koin.core.util.dataBinding import `in`.koreatech.koin.core.viewpager.HorizontalMarginItemDecoration import `in`.koreatech.koin.databinding.StoreActivityMainBinding -import `in`.koreatech.koin.domain.model.store.StoreCategory +import `in`.koreatech.koin.domain.model.store.StoreEvent import `in`.koreatech.koin.domain.model.store.StoreSorter -import `in`.koreatech.koin.domain.model.store.toStoreCategory import `in`.koreatech.koin.ui.navigation.KoinNavigationDrawerTimeActivity import `in`.koreatech.koin.ui.navigation.state.MenuState import `in`.koreatech.koin.ui.store.adapter.StoreCategoriesRecyclerAdapter @@ -44,6 +46,7 @@ import `in`.koreatech.koin.util.ext.observeLiveData import `in`.koreatech.koin.util.ext.showSoftKeyboard import `in`.koreatech.koin.util.ext.statusBarHeight import kotlinx.coroutines.launch +import javax.inject.Inject import kotlin.properties.Delegates @AndroidEntryPoint @@ -57,31 +60,40 @@ class StoreActivity : KoinNavigationDrawerTimeActivity() { override val screenTitle = "상점" private val viewModel by viewModels() + @Inject + lateinit var onboardingManager: OnboardingManager + + private var eventListSize by Delegates.notNull() + fun interface StoreCategoryFactory { fun getCurrentCategory(): String } private val storeDetailContract = registerForActivityResult(StoreDetailActivityContract { - viewModel.category.value?.let { getStoreCategoryName(it) } ?: "Unknown" + viewModel.category.value?.let { viewModel.category.value?.name } ?: "Unknown" }) { } private val viewPagerHandler = Handler(Looper.getMainLooper()) - private val viewPagerDelayTime = 10000L + private val viewPagerDelayTime = 4000L private val storeAdapter = StoreRecyclerAdapter().apply { setOnItemClickListener { storeElapsedTime = System.currentTimeMillis() - currentTime - storeDetailContract.launch(Triple(it.uid, getStoreCategoryName(viewModel.category.value), false)) - EventLogger.logClickEvent( - EventAction.BUSINESS, - AnalyticsConstant.Label.SHOP_CLICK, - it.name, - EventExtra(AnalyticsConstant.PREVIOUS_PAGE, getStoreCategoryName(viewModel.category.value)), - EventExtra(AnalyticsConstant.CURRENT_PAGE, it.name), - EventExtra(AnalyticsConstant.DURATION_TIME, getElapsedTimeAndReset().toString()) - ) + storeDetailContract.launch(Triple(it.uid, viewModel.category.value?.name, false)) + val categoryName = viewModel.category.value?.name + + if(categoryName != null){ + EventLogger.logClickEvent( + EventAction.BUSINESS, + AnalyticsConstant.Label.SHOP_CLICK, + it.name, + EventExtra(AnalyticsConstant.PREVIOUS_PAGE, categoryName), + EventExtra(AnalyticsConstant.CURRENT_PAGE, it.name), + EventExtra(AnalyticsConstant.DURATION_TIME, getElapsedTimeAndReset().toString()) + ) + } } } @@ -92,27 +104,29 @@ class StoreActivity : KoinNavigationDrawerTimeActivity() { AnalyticsConstant.Label.SHOP_CATEGORIES_EVENT, it.shopName ) - storeDetailContract.launch(Triple(it.shopId, getStoreCategoryName(viewModel.category.value), false)) + storeDetailContract.launch(Triple(it.shopId, viewModel.category.value?.name, false)) } } private val storeCategoriesAdapter = StoreCategoriesRecyclerAdapter().apply { setOnItemClickListener { - val previous = getStoreCategoryName(viewModel.category.value) + val previous = viewModel.category.value?.name - viewModel.setCategory(it.toStoreCategory()) + viewModel.setCategory(it) binding.searchEditText.text.clear() - val current = getStoreCategoryName(viewModel.category.value) + val current = viewModel.category.value?.name - EventLogger.logClickEvent( - EventAction.BUSINESS, - AnalyticsConstant.Label.SHOP_CATEGORIES, - current, - EventExtra(AnalyticsConstant.PREVIOUS_PAGE, previous), - EventExtra(AnalyticsConstant.CURRENT_PAGE, current), - EventExtra(AnalyticsConstant.DURATION_TIME, getElapsedTimeAndReset().toString()) - ) - preCategories = it.toStoreCategory() + if (current != null && previous != null) { + EventLogger.logClickEvent( + EventAction.BUSINESS, + AnalyticsConstant.Label.SHOP_CATEGORIES, + current, + EventExtra(AnalyticsConstant.PREVIOUS_PAGE, previous), + EventExtra(AnalyticsConstant.CURRENT_PAGE, current), + EventExtra(AnalyticsConstant.DURATION_TIME, getElapsedTimeAndReset().toString()) + ) + } + preCategories = it currentTime = System.currentTimeMillis() } } @@ -155,9 +169,10 @@ class StoreActivity : KoinNavigationDrawerTimeActivity() { initViewModel() initView() + initSortingTooltip() val initStoreCategory = - intent.extras?.getInt(StoreActivityContract.STORE_CATEGORY)?.toStoreCategory() + intent.extras?.getInt(StoreActivityContract.STORE_CATEGORY) storeCategoriesAdapter.selectPosition = intent.extras?.getInt(StoreActivityContract.STORE_CATEGORY)?.minus(2) viewModel.setCategory(initStoreCategory) @@ -184,7 +199,7 @@ class StoreActivity : KoinNavigationDrawerTimeActivity() { binding.categoriesRecyclerview.apply { - layoutManager = GridLayoutManager(this@StoreActivity, 5) + layoutManager = GridLayoutManager(this@StoreActivity, 6) adapter = storeCategoriesAdapter } @@ -199,12 +214,25 @@ class StoreActivity : KoinNavigationDrawerTimeActivity() { EventLogger.logClickEvent( EventAction.BUSINESS, AnalyticsConstant.Label.SHOP_CATEGORIES_SEARCH, - "search in " + getStoreCategoryName(viewModel.category.value) + "search in " + viewModel.category.value?.name ) } v.performClick() } + binding.leftEventArrow.setOnClickListener { + val currentPosition = binding.eventViewPager.currentItem + val previousPosition = if (currentPosition - 1 >= 1 ) currentPosition - 1 else eventListSize - 2 + binding.eventViewPager.setCurrentItem(previousPosition, true) + startAutoScroll() + } + + binding.rightEventArrow.setOnClickListener { + val currentPosition = binding.eventViewPager.currentItem + val nextPosition = if(currentPosition + 1 <= eventListSize - 2) currentPosition + 1 else 1 + binding.eventViewPager.setCurrentItem(nextPosition, true) + startAutoScroll() + } binding.storeRecyclerview.apply { layoutManager = LinearLayoutManager(this@StoreActivity) @@ -221,8 +249,6 @@ class StoreActivity : KoinNavigationDrawerTimeActivity() { binding.eventViewPager.apply { - - currentItem = Int.MAX_VALUE / 2 adapter = storeEventPagerAdapter addItemDecoration( @@ -232,6 +258,7 @@ class StoreActivity : KoinNavigationDrawerTimeActivity() { ) ) registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { + override fun onPageScrolled( position: Int, positionOffset: Float, @@ -244,7 +271,17 @@ class StoreActivity : KoinNavigationDrawerTimeActivity() { } override fun onPageScrollStateChanged(state: Int) { - if (state == ViewPager.SCROLL_STATE_DRAGGING) { + if(state == ViewPager2.SCROLL_STATE_IDLE){ + if(binding.eventViewPager.currentItem == eventListSize - 1){ + binding.eventViewPager.setCurrentItem(1, false) + binding.eventPageCounterTextView.text = "1/${eventListSize - 2}" + } + + if(binding.eventViewPager.currentItem == 0){ + binding.eventViewPager.setCurrentItem(eventListSize - 2, false) + binding.eventPageCounterTextView.text = "${eventListSize - 2}/${eventListSize - 2}" + } + binding.eventPageCounterTextView.text = "${binding.eventViewPager.currentItem}/${eventListSize - 2}" startAutoScroll() } } @@ -265,7 +302,7 @@ class StoreActivity : KoinNavigationDrawerTimeActivity() { EventLogger.logScrollEvent( EventAction.BUSINESS, AnalyticsConstant.Label.SHOP_CATEGORIES, - "scroll in " + getStoreCategoryName(viewModel.category.value) + "scroll in " + viewModel.category.value?.name ) } } @@ -278,7 +315,7 @@ class StoreActivity : KoinNavigationDrawerTimeActivity() { EventLogger.logClickEvent( EventAction.BUSINESS, AnalyticsConstant.Label.SHOP_CAN, - "check_review_"+viewModel.category.value?.let { getStoreCategoryName(it) } + "check_review_"+viewModel.category.value?.let { viewModel.category.value?.name } ) storeManyReviewCheckbox.setTextColor( ContextCompat.getColor( @@ -311,7 +348,7 @@ class StoreActivity : KoinNavigationDrawerTimeActivity() { EventLogger.logClickEvent( EventAction.BUSINESS, AnalyticsConstant.Label.SHOP_CAN, - "check_star_"+viewModel.category.value?.let { getStoreCategoryName(it) } + "check_star_"+viewModel.category.value?.let { viewModel.category.value?.name } ) storeHighRatingCheckbox.setTextColor( ContextCompat.getColor( @@ -345,7 +382,7 @@ class StoreActivity : KoinNavigationDrawerTimeActivity() { EventLogger.logClickEvent( EventAction.BUSINESS, AnalyticsConstant.Label.SHOP_CAN, - "check_open_"+viewModel.category.value?.let { getStoreCategoryName(it) } + "check_open_"+viewModel.category.value?.let { viewModel.category.value?.name } ) ContextCompat.getColor( this@StoreActivity, @@ -363,7 +400,7 @@ class StoreActivity : KoinNavigationDrawerTimeActivity() { EventLogger.logClickEvent( EventAction.BUSINESS, AnalyticsConstant.Label.SHOP_CAN, - "check_delivery_"+viewModel.category.value?.let { getStoreCategoryName(it) } + "check_delivery_"+viewModel.category.value?.let { viewModel.category.value?.name } ) ContextCompat.getColor( this@StoreActivity, @@ -380,9 +417,7 @@ class StoreActivity : KoinNavigationDrawerTimeActivity() { private val runnable = object : Runnable { override fun run() { var currentPosition = binding.eventViewPager.currentItem - val itemCount = binding.eventViewPager.adapter?.itemCount ?: 0 - - currentPosition = if (currentPosition >= itemCount - 1) 0 else currentPosition + 1 + currentPosition = if (currentPosition >= eventListSize - 1) 0 else currentPosition + 1 binding.eventViewPager.setCurrentItem(currentPosition, true) viewPagerHandler.postDelayed(this, viewPagerDelayTime) @@ -402,11 +437,22 @@ class StoreActivity : KoinNavigationDrawerTimeActivity() { } observeLiveData(viewModel.storeEvents) { - storeEventPagerAdapter.submitList(it) + if (!it.isNullOrEmpty()) { + val augmentedList = mutableListOf().apply { + add(it.last()) + addAll(it) + add(it.first()) + } + binding.eventPageCounterTextView.text = "1/${augmentedList.size - 2}" + eventListSize = augmentedList.size + storeEventPagerAdapter.submitList(augmentedList) + + binding.eventViewPager.setCurrentItem(1, false) + } binding.eventViewPager.isGone = it.isNullOrEmpty() } - observeLiveData(viewModel.storeCategories) { + observeLiveData(viewModel.storeCategoryList) { storeCategoriesAdapter.submitList(it.drop(1)) } @@ -419,19 +465,14 @@ class StoreActivity : KoinNavigationDrawerTimeActivity() { } } - - private fun getStoreCategoryName(category: StoreCategory?): String { - return when (category) { - StoreCategory.Chicken -> getString(R.string.chicken) - StoreCategory.Pizza -> getString(R.string.pizza) - StoreCategory.DOSIRAK -> getString(R.string.dorisak) - StoreCategory.PorkFeet -> getString(R.string.pork_feet) - StoreCategory.Chinese -> getString(R.string.chinese) - StoreCategory.NormalFood -> getString(R.string.normal_food) - StoreCategory.Cafe -> getString(R.string.cafe) - StoreCategory.BeautySalon -> getString(R.string.beauty_salon) - StoreCategory.Etc -> getString(R.string.etc) - StoreCategory.All, null -> getString(R.string.see_all) + private fun initSortingTooltip() { + with(onboardingManager) { + showOnboardingTooltipIfNeeded( + type = OnboardingType.REVIEW_SORTING, + view = binding.storeManyReviewCheckbox, + arrowPosition = 0.1f, + arrowDirection = ArrowDirection.BOTTOM + ) } } diff --git a/koin/src/main/java/in/koreatech/koin/ui/store/activity/StoreDetailActivity.kt b/koin/src/main/java/in/koreatech/koin/ui/store/activity/StoreDetailActivity.kt index c94995df7..253df1844 100644 --- a/koin/src/main/java/in/koreatech/koin/ui/store/activity/StoreDetailActivity.kt +++ b/koin/src/main/java/in/koreatech/koin/ui/store/activity/StoreDetailActivity.kt @@ -4,6 +4,7 @@ import android.Manifest import android.annotation.SuppressLint import android.content.ClipData import android.content.ClipboardManager +import android.content.Intent import android.os.Bundle import android.view.MotionEvent import android.widget.TextView @@ -29,6 +30,7 @@ import `in`.koreatech.koin.core.util.dataBinding import `in`.koreatech.koin.databinding.StoreActivityDetailBinding import `in`.koreatech.koin.ui.navigation.KoinNavigationDrawerActivity import `in`.koreatech.koin.ui.navigation.state.MenuState +import `in`.koreatech.koin.ui.splash.state.TokenState import `in`.koreatech.koin.ui.store.adapter.StoreDetailFlyerRecyclerAdapter import `in`.koreatech.koin.ui.store.adapter.StoreDetailImageViewpagerAdapter import `in`.koreatech.koin.ui.store.adapter.StoreDetailMenuRecyclerAdapter @@ -452,11 +454,13 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() { builder.setMessage(message) builder.setPositiveButton(getString(R.string.store_dialog_call)) { _, _ -> + if (viewModel.tokenState.value == TokenState.Valid) { + viewModel.postReviewPromptNotification(viewModel.store.value!!.uid) + } callPermission.launch(Manifest.permission.CALL_PHONE) } builder.setNegativeButton(getString(R.string.store_dialog_call_cancel)) { dialog, _ -> dialog.dismiss() - } builder.setOnDismissListener { diff --git a/koin/src/main/java/in/koreatech/koin/ui/store/adapter/StoreCategoriesRecyclerAdapter.kt b/koin/src/main/java/in/koreatech/koin/ui/store/adapter/StoreCategoriesRecyclerAdapter.kt index ebfae78f1..a3a2433c4 100644 --- a/koin/src/main/java/in/koreatech/koin/ui/store/adapter/StoreCategoriesRecyclerAdapter.kt +++ b/koin/src/main/java/in/koreatech/koin/ui/store/adapter/StoreCategoriesRecyclerAdapter.kt @@ -7,16 +7,12 @@ import androidx.core.content.ContextCompat import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView -import androidx.recyclerview.widget.StaggeredGridLayoutManager import com.bumptech.glide.Glide import com.bumptech.glide.load.resource.bitmap.RoundedCorners import com.bumptech.glide.request.RequestOptions import `in`.koreatech.koin.R -import `in`.koreatech.koin.databinding.MainItemStoreBinding import `in`.koreatech.koin.databinding.StoreCategoryItemBinding import `in`.koreatech.koin.domain.model.store.StoreCategories -import `in`.koreatech.koin.domain.model.store.StoreCategory -import `in`.koreatech.koin.domain.model.store.toStoreCategory class StoreCategoriesRecyclerAdapter(): ListAdapter( diffCallback @@ -25,7 +21,7 @@ class StoreCategoriesRecyclerAdapter(): ListAdapter() { - override fun createIntent(context: Context, input: StoreCategory?): Intent { - return Intent(context, StoreActivity::class.java).apply { - putExtra(STORE_CATEGORY, input?.toString()) - } - } - - override fun parseResult(resultCode: Int, intent: Intent?) { - - } - +class StoreActivityContract() { companion object { const val STORE_CATEGORY = "STORE_CATEGORY" } diff --git a/koin/src/main/java/in/koreatech/koin/ui/store/viewmodel/StoreDetailViewModel.kt b/koin/src/main/java/in/koreatech/koin/ui/store/viewmodel/StoreDetailViewModel.kt index b036d2fe8..d5b4c564a 100644 --- a/koin/src/main/java/in/koreatech/koin/ui/store/viewmodel/StoreDetailViewModel.kt +++ b/koin/src/main/java/in/koreatech/koin/ui/store/viewmodel/StoreDetailViewModel.kt @@ -1,9 +1,11 @@ package `in`.koreatech.koin.ui.store.viewmodel +import android.Manifest import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel +import `in`.koreatech.koin.core.toast.ToastUtil import `in`.koreatech.koin.core.viewmodel.BaseViewModel import `in`.koreatech.koin.core.viewmodel.SingleLiveEvent import `in`.koreatech.koin.domain.model.store.ReviewFilterEnum @@ -21,9 +23,13 @@ import `in`.koreatech.koin.domain.usecase.store.GetShopEventsUseCase import `in`.koreatech.koin.domain.usecase.store.GetShopMenusUseCase import `in`.koreatech.koin.domain.usecase.store.GetStoreReviewUseCase import `in`.koreatech.koin.domain.usecase.store.GetStoreWithMenuUseCase +import `in`.koreatech.koin.domain.usecase.store.ReviewPromptUscCase import `in`.koreatech.koin.domain.usecase.token.IsTokenSavedInDeviceUseCase import `in`.koreatech.koin.domain.usecase.user.GetUserInfoUseCase +import `in`.koreatech.koin.domain.util.onFailure +import `in`.koreatech.koin.domain.util.onSuccess import `in`.koreatech.koin.ui.splash.state.TokenState +import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel @@ -35,6 +41,7 @@ class StoreDetailViewModel @Inject constructor( private val getStoreEventsUseCase: GetShopEventsUseCase, private val deleteReviewUseCase: DeleteReviewUseCase, private val getUserInfoUseCase: GetUserInfoUseCase, + private val reviewPromptUscCase: ReviewPromptUscCase, private val isTokenSavedInDeviceUseCase: IsTokenSavedInDeviceUseCase, ) : BaseViewModel() { val store: LiveData get() = _store @@ -70,6 +77,15 @@ class StoreDetailViewModel @Inject constructor( } } + fun postReviewPromptNotification(storeId: Int){ + viewModelScope.launch { + reviewPromptUscCase(storeId) + .onFailure { + ToastUtil.getInstance().makeShort(it.message) + } + } + } + fun getShopMenus(storeId: Int) = viewModelScope.launchWithLoading { getShopMenusUseCase(storeId).also { shop -> _categories.value = shop diff --git a/koin/src/main/java/in/koreatech/koin/ui/store/viewmodel/StoreViewModel.kt b/koin/src/main/java/in/koreatech/koin/ui/store/viewmodel/StoreViewModel.kt index 10cb6c211..584247058 100644 --- a/koin/src/main/java/in/koreatech/koin/ui/store/viewmodel/StoreViewModel.kt +++ b/koin/src/main/java/in/koreatech/koin/ui/store/viewmodel/StoreViewModel.kt @@ -1,16 +1,13 @@ package `in`.koreatech.koin.ui.store.viewmodel -import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import `in`.koreatech.koin.core.viewmodel.BaseViewModel -import `in`.koreatech.koin.domain.model.dining.Dining import `in`.koreatech.koin.domain.model.store.NeedSignUpStoreInfo import `in`.koreatech.koin.domain.model.store.Store import `in`.koreatech.koin.domain.model.store.StoreCategories -import `in`.koreatech.koin.domain.model.store.StoreCategory import `in`.koreatech.koin.domain.model.store.StoreEvent import `in`.koreatech.koin.domain.model.store.StoreSorter import `in`.koreatech.koin.domain.usecase.store.GetStoreCategoriesUseCase @@ -32,7 +29,7 @@ class StoreViewModel @Inject constructor( ) : BaseViewModel() { private val search = MutableStateFlow("") private val refreshEvent = MutableSharedFlow() - private val _category = MutableStateFlow(null) + private val _category = MutableStateFlow(StoreCategories(0, "", "")) private val _stores = MutableStateFlow>(emptyList()) private val _store = MutableStateFlow(null) private val _needToProceedStoreInfo = MutableSharedFlow() @@ -40,13 +37,13 @@ class StoreViewModel @Inject constructor( private val _storeEvents = MutableLiveData?>(emptyList()) val storeEvents: LiveData?> get() = _storeEvents - val category: StateFlow = _category.asStateFlow() + val category: StateFlow = _category.asStateFlow() val stores: StateFlow> = _stores.asStateFlow() val store: StateFlow = _store.asStateFlow() val needToProceedStoreInfo = _needToProceedStoreInfo.asSharedFlow() - private val _storeCategories = MutableLiveData>(emptyList()) - val storeCategories: LiveData> get() = _storeCategories + private val _storeCategoryList = MutableLiveData>(emptyList()) + val storeCategoryList: LiveData> get() = _storeCategoryList private val _storeSorter = MutableLiveData() val storeSorter: LiveData get() = _storeSorter @@ -58,7 +55,7 @@ class StoreViewModel @Inject constructor( val isDelivery: LiveData get() = _isDelivery init { - _storeSorter.value = StoreSorter.NONE + _storeSorter.value = StoreSorter.COUNT getStoreCategories() getStoreEvents() //changeCategory() @@ -69,11 +66,11 @@ class StoreViewModel @Inject constructor( search.value = query } - fun setCategory(storeCategory: StoreCategory?) { - if(category.value == storeCategory) { - _category.value = StoreCategory.All + fun setCategory(storeCategoryId: Int?) { + if(category.value?.id == storeCategoryId) { + _category.value = _storeCategoryList.value?.get(0) } else { - _category.value = storeCategory + _category.value = storeCategoryId?.let { _storeCategoryList.value?.get(it - 1) } } } @@ -163,6 +160,8 @@ class StoreViewModel @Inject constructor( } } + fun getEventListSize() = storeEvents.value?.size + private fun getStoreEvents(){ viewModelScope.launch { _storeEvents.value = getStoreEventUseCase() @@ -171,7 +170,7 @@ class StoreViewModel @Inject constructor( private fun getStoreCategories(){ viewModelScope.launchWithLoading { - _storeCategories.value = getStoreCategoriesUseCase() + _storeCategoryList.value = getStoreCategoriesUseCase() } } } \ No newline at end of file diff --git a/koin/src/main/res/layout/activity_notification.xml b/koin/src/main/res/layout/activity_notification.xml index f8bf14c74..b9ebed2b9 100644 --- a/koin/src/main/res/layout/activity_notification.xml +++ b/koin/src/main/res/layout/activity_notification.xml @@ -173,12 +173,22 @@ app:layout_constraintTop_toBottomOf="@id/text_view_store" app:text="@string/notification_event" /> + + + app:layout_constraintTop_toBottomOf="@id/notification_review_prompt" /> - + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintBottom_toTopOf="@+id/categories_recyclerview"> + + + + + + + + + + android:textAppearance="@style/TextAppearance.Koin.Medium.16" /> @@ -154,105 +196,68 @@ android:id="@+id/event_view_pager" android:layout_width="match_parent" android:layout_height="72dp" - android:layout_marginTop="4dp" + android:layout_marginTop="12dp" android:clipToPadding="false" app:layout_constraintTop_toBottomOf="@id/category_constraint_layout" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintBottom_toTopOf="@id/search_constraint_layout" + app:layout_constraintBottom_toTopOf="@id/store_filter_constraint_layout" tools:listitem="@layout/store_event_card" /> - - - + - - - - - - - - - + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + android:alpha="0.6" + android:background="@drawable/rounded_corners_black" + /> + + /> - - + app:layout_constraintStart_toEndOf="@id/event_page_counter_text_view" + /> @@ -276,10 +281,11 @@ app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toStartOf="@id/store_high_rating_checkbox" android:paddingHorizontal="14dp" - android:text="# 리뷰순 " - android:textColor="@color/gray15" + android:text="∨ 리뷰순 " + android:textColor="@color/blue_alpha20" android:textSize="13sp" android:gravity="center" + android:checked="true" /> diff --git a/koin/src/main/res/layout/store_category_item.xml b/koin/src/main/res/layout/store_category_item.xml index 913d49ee0..f95f0a229 100644 --- a/koin/src/main/res/layout/store_category_item.xml +++ b/koin/src/main/res/layout/store_category_item.xml @@ -2,10 +2,9 @@ + tools:text="도시락/분식" /> \ No newline at end of file diff --git a/koin/src/main/res/layout/store_event_card.xml b/koin/src/main/res/layout/store_event_card.xml index 6e432f09d..bcfaa1710 100644 --- a/koin/src/main/res/layout/store_event_card.xml +++ b/koin/src/main/res/layout/store_event_card.xml @@ -33,7 +33,7 @@ app:riv_corner_radius="15dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toEndOf="parent" - android:src="@drawable/event_default" + android:src="@drawable/default_event_image" /> - diff --git a/koin/src/main/res/values/dimens.xml b/koin/src/main/res/values/dimens.xml index 23b11d85f..4adcc167a 100644 --- a/koin/src/main/res/values/dimens.xml +++ b/koin/src/main/res/values/dimens.xml @@ -10,7 +10,7 @@ 0dp 24dp - 40dp + 10dp 24dp 145dp diff --git a/koin/src/main/res/values/strings.xml b/koin/src/main/res/values/strings.xml index 24b66e785..cb5a66823 100644 --- a/koin/src/main/res/values/strings.xml +++ b/koin/src/main/res/values/strings.xml @@ -389,6 +389,9 @@ 식단사진 업로드 알림 식단사진이 업로드 될 경우 알림을 받습니다. + 리뷰 작성 요청 알림 + 전화 주문 시 리뷰 작성 요청 알림을 받습니다. + 이벤트 알림 모든 주변상점의 이벤트 알림을 받습니다. 키워드가 포함된 글이 게시될 경우 알림을 받습니다. @@ -539,7 +542,7 @@ #카드가능 #계좌이체가능 메뉴 소개 - 주변 상점 + 주변상점 메인 메뉴 전체보기 메뉴