diff --git a/core/src/main/java/in/koreatech/koin/core/abtest/Experiment.kt b/core/src/main/java/in/koreatech/koin/core/abtest/Experiment.kt
index f906f97d2..965a32171 100644
--- a/core/src/main/java/in/koreatech/koin/core/abtest/Experiment.kt
+++ b/core/src/main/java/in/koreatech/koin/core/abtest/Experiment.kt
@@ -8,7 +8,8 @@ enum class Experiment(
BENEFIT_STORE("Benefit", ExperimentGroup.A, ExperimentGroup.B),
DINING_SHARE("campus_share_v1", ExperimentGroup.SHARE_ORIGINAL, ExperimentGroup.SHARE_NEW),
MAIN_DINING_SEE_MORE("c_main_dining_v1", ExperimentGroup.MAIN_DINING_ORIGINAL, ExperimentGroup.MAIN_DINING_NEW),
- MAIN_ARTICLE_KEYWORD_BANNER("c_keyword_ banner_v1", ExperimentGroup.MAIN_BANNER_ORIGINAL, ExperimentGroup.MAIN_BANNER_NEW);
+ MAIN_ARTICLE_KEYWORD_BANNER("c_keyword_ banner_v1", ExperimentGroup.MAIN_BANNER_ORIGINAL, ExperimentGroup.MAIN_BANNER_NEW),
+ BUSINESS_CALL("business_call", ExperimentGroup.CALL_NUMBER, ExperimentGroup.CALL_FLOATING);
init {
require(experimentGroups.isNotEmpty()) { "Experiment should have at least one group" }
@@ -27,4 +28,7 @@ object ExperimentGroup {
const val MAIN_BANNER_ORIGINAL = "banner_original"
const val MAIN_BANNER_NEW = "banner_new"
-}
\ No newline at end of file
+
+ const val CALL_NUMBER = "call_number"
+ const val CALL_FLOATING = "call_floating"
+}
diff --git a/core/src/main/java/in/koreatech/koin/core/analytics/EventLogger.kt b/core/src/main/java/in/koreatech/koin/core/analytics/EventLogger.kt
index d6f781c40..454e51d07 100644
--- a/core/src/main/java/in/koreatech/koin/core/analytics/EventLogger.kt
+++ b/core/src/main/java/in/koreatech/koin/core/analytics/EventLogger.kt
@@ -24,6 +24,8 @@ object EventLogger {
logEvent(action, EventCategory.CLICK, label, value, *extras)
}
+
+
/**
* 스크롤 이벤트 로깅
* @param action: 이벤트 발생 도메인(BUSINESS, CAMPUS, USER)
@@ -71,6 +73,8 @@ object EventLogger {
param(EVENT_LABEL, "$label (debug)")
param(VALUE, value)
}
+ println("EventLoggerCustom: ${action}, ${category}, $label, $value, ")
+
} else {
Firebase.analytics.logEvent(action) {
param(EVENT_CATEGORY, category)
@@ -96,6 +100,7 @@ object EventLogger {
param("${it.key}_debug", it.value)
}
}
+ println("EventLogger: ${action.value}, ${category.value}, $label, $value, ${extras.joinToString { ", ${it.key}: ${it.value}" }}")
} else {
Firebase.analytics.logEvent(action.value) {
param(EVENT_CATEGORY, category.value)
@@ -112,14 +117,14 @@ object EventLogger {
enum class EventAction(val value: String) {
BUSINESS("BUSINESS"),
CAMPUS("CAMPUS"),
- USER("USER")
+ USER("USER"),
}
enum class EventCategory(val value: String) {
CLICK("click"),
SCROLL("scroll"),
SWIPE("swipe"), // 하단 뒤로가기(아이폰의 swipe 뒤로가기와 대응)
- NOTIFICATION("notification")
+ NOTIFICATION("notification"),
}
-data class EventExtra(val key: String, val value: String)
\ No newline at end of file
+data class EventExtra(val key: String, val value: String)
diff --git a/core/src/main/java/in/koreatech/koin/core/constant/AnalyticsConstant.kt b/core/src/main/java/in/koreatech/koin/core/constant/AnalyticsConstant.kt
index 2e6df476d..544706cd7 100644
--- a/core/src/main/java/in/koreatech/koin/core/constant/AnalyticsConstant.kt
+++ b/core/src/main/java/in/koreatech/koin/core/constant/AnalyticsConstant.kt
@@ -101,9 +101,12 @@ object AnalyticsConstant {
const val CAMPUS_NOTICE_1 = "CAMPUS_notice_1"
const val POPULAR_NOTICE_BANNER = "popular_notice_banner"
const val TO_MANAGE_KEYWORD = "to_manage_keyword"
+
+ const val BUSINESS_CALL_NUMBER = " BUSINESS_call_1"
+ const val BUSINESS_CALL_FLOATING = "BUSINESS_call_1"
}
const val PREVIOUS_PAGE = "previous_page"
const val CURRENT_PAGE = "current_page"
const val DURATION_TIME = "duration_time"
-}
\ No newline at end of file
+}
diff --git a/core/src/main/res/drawable/ic_benefit_icon.png b/core/src/main/res/drawable/ic_benefit_icon.png
new file mode 100644
index 000000000..4e471e513
Binary files /dev/null and b/core/src/main/res/drawable/ic_benefit_icon.png differ
diff --git a/core/src/main/res/drawable/rounded_corners_black.xml b/core/src/main/res/drawable/rounded_corners_black.xml
index 8897a9943..cf98b013c 100644
--- a/core/src/main/res/drawable/rounded_corners_black.xml
+++ b/core/src/main/res/drawable/rounded_corners_black.xml
@@ -2,5 +2,5 @@
-
+
\ No newline at end of file
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 98dd28ee2..5b4c00ca6 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
@@ -63,7 +63,9 @@ fun StoreItemResponse.toStore(): Store = Store(
closeTime = it.closeTime ?: ""
)
}.orEmpty().getOrElse(0) { Store.OpenData(localDayOfWeekName, false, "00:00", "00:00") },
- categoryIds = categoryIds
+ categoryIds = categoryIds,
+ benefitDetails = benefitDetails ?: benefitDetail?.toStringArray() ?: emptyList(),
+
)
fun StoreEventItemReponse.toStoreEvent(): StoreEvent = StoreEvent(
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 3d260182c..890968a2f 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
@@ -14,7 +14,9 @@ data class StoreItemResponse(
@SerializedName("is_event") val isEvent: Boolean?,
@SerializedName("is_open") val isOpen: Boolean?,
@SerializedName("average_rate") val averageRate : Double,
- @SerializedName("review_count") val reviewCount : Int
+ @SerializedName("review_count") val reviewCount : Int,
+ @SerializedName("benefit_details") val benefitDetails: List?,
+ @SerializedName("benefit_detail") val benefitDetail: String?,
) {
data class OpenResponseDTO(
@SerializedName("day_of_week")
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 b143d6326..31fc51925 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,8 @@ data class Store(
val averageRate : Double,
val reviewCount : Int,
val open: OpenData,
- val categoryIds: List
+ val categoryIds: List,
+ val benefitDetails: List,
) {
data class OpenData(
val dayOfWeek: String,
@@ -44,4 +45,4 @@ data class Store(
}
}
}
-}
\ No newline at end of file
+}
diff --git a/domain/src/main/java/in/koreatech/koin/domain/model/store/StoreCategories.kt b/domain/src/main/java/in/koreatech/koin/domain/model/store/StoreCategories.kt
index d81426529..6f9a8d0fd 100644
--- a/domain/src/main/java/in/koreatech/koin/domain/model/store/StoreCategories.kt
+++ b/domain/src/main/java/in/koreatech/koin/domain/model/store/StoreCategories.kt
@@ -2,6 +2,6 @@ package `in`.koreatech.koin.domain.model.store
data class StoreCategories(
val id: Int,
- val imageUrl: String,
+ val imageUrl: Any,
val name: String
)
\ No newline at end of file
diff --git a/koin/src/main/java/in/koreatech/koin/ui/main/activity/MainActivity.kt b/koin/src/main/java/in/koreatech/koin/ui/main/activity/MainActivity.kt
index e985648ae..2adb2339e 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/main/activity/MainActivity.kt
+++ b/koin/src/main/java/in/koreatech/koin/ui/main/activity/MainActivity.kt
@@ -13,6 +13,7 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
+import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
@@ -48,6 +49,7 @@ import `in`.koreatech.koin.databinding.ActivityMainBinding
import `in`.koreatech.koin.domain.model.bus.BusType
import `in`.koreatech.koin.domain.model.bus.timer.BusArrivalInfo
import `in`.koreatech.koin.domain.model.dining.DiningPlace
+import `in`.koreatech.koin.domain.model.store.StoreCategories
import `in`.koreatech.koin.ui.article.ArticleActivity
import `in`.koreatech.koin.ui.bus.BusActivity
import `in`.koreatech.koin.ui.dining.DiningActivity
@@ -147,15 +149,28 @@ class MainActivity : KoinNavigationDrawerTimeActivity() {
private val storeCategoriesRecyclerAdapter = StoreCategoriesRecyclerAdapter().apply {
setOnItemClickListener { id, name ->
- EventLogger.logClickEvent(
- EventAction.BUSINESS,
- AnalyticsConstant.Label.MAIN_SHOP_CATEGORIES,
- name,
- EventExtra(AnalyticsConstant.PREVIOUS_PAGE, "메인"),
- EventExtra(AnalyticsConstant.CURRENT_PAGE, name),
- EventExtra(AnalyticsConstant.DURATION_TIME, getElapsedTimeAndReset().toString())
- )
- gotoStoreActivity(id + 1)
+ if(id == 0){
+ startActivity(Intent(this@MainActivity, CallBenefitStoreActivity::class.java))
+ EventLogger.logClickEvent(
+ EventAction.BUSINESS,
+ AnalyticsConstant.Label.MAIN_SHOP_BENEFIT,
+ name,
+ EventExtra(AnalyticsConstant.PREVIOUS_PAGE, "메인"),
+ EventExtra(AnalyticsConstant.CURRENT_PAGE, "benefit"),
+ EventExtra(AnalyticsConstant.DURATION_TIME, getElapsedTimeAndReset().toString())
+ )
+ }
+ else{
+ EventLogger.logClickEvent(
+ EventAction.BUSINESS,
+ AnalyticsConstant.Label.MAIN_SHOP_CATEGORIES,
+ name,
+ EventExtra(AnalyticsConstant.PREVIOUS_PAGE, "메인"),
+ EventExtra(AnalyticsConstant.CURRENT_PAGE, name),
+ EventExtra(AnalyticsConstant.DURATION_TIME, getElapsedTimeAndReset().toString())
+ )
+ gotoStoreActivity(id)
+ }
}
}
@@ -199,6 +214,7 @@ class MainActivity : KoinNavigationDrawerTimeActivity() {
scrollPercentage = 100.0f * offset / (range - extent)
}
viewModel.postABTestAssign(Experiment.BENEFIT_STORE.experimentTitle)
+
storeListButton.setOnClickListener {
gotoStoreActivity(0)
}
@@ -265,8 +281,7 @@ class MainActivity : KoinNavigationDrawerTimeActivity() {
}
recyclerViewStoreCategory.apply {
- layoutManager =
- LinearLayoutManager(this@MainActivity, RecyclerView.HORIZONTAL, false)
+ layoutManager = GridLayoutManager(this@MainActivity, 6)
adapter = storeCategoriesRecyclerAdapter
}
@@ -303,6 +318,44 @@ class MainActivity : KoinNavigationDrawerTimeActivity() {
}
private fun initViewModel() = with(viewModel) {
+ getStoreCategories(StoreCategories(-1, R.drawable.ic_benefit_icon, "혜택"))
+
+ observeLiveData(variableName) {
+ when (viewModel.variableName.value) {
+ ExperimentGroup.A -> {
+ EventLogger.logCustomEvent(
+ action = "AB_TEST",
+ category = "a/b test 로깅(3차 스프린트, 혜택페이지)",
+ label = "BUSINESS_benefit_1",
+ value = "혜택X"
+ )
+ binding.storeButtonLayout.visibility = View.GONE
+ binding.recyclerViewStoreCategory.visibility = View.VISIBLE
+ }
+
+ ExperimentGroup.B -> {
+ EventLogger.logCustomEvent(
+ action = "AB_TEST",
+ category = "a/b test 로깅(3차 스프린트, 혜택페이지)",
+ label = "BUSINESS_benefit_1",
+ value = "혜택O"
+ )
+ binding.storeButtonLayout.visibility = View.VISIBLE
+ binding.recyclerViewStoreCategory.visibility = View.GONE
+ }
+
+ else -> {
+ EventLogger.logCustomEvent(
+ action = "AB_TEST",
+ category = "a/b test 로깅(3차 스프린트, 혜택페이지)",
+ label = "BUSINESS_benefit_1",
+ value = "혜택X"
+ )
+ binding.storeButtonLayout.visibility = View.GONE
+ binding.recyclerViewStoreCategory.visibility = View.VISIBLE
+ }
+ }
+ }
observeLiveData(isLoading) {
binding.mainSwipeRefreshLayout.isRefreshing = it
}
@@ -319,7 +372,7 @@ class MainActivity : KoinNavigationDrawerTimeActivity() {
}
}
observeLiveData(storeCategories) {
- storeCategoriesRecyclerAdapter.submitList(it.drop(1))
+ storeCategoriesRecyclerAdapter.submitList(it)
}
binding.recyclerViewStoreCategory.visibility = View.GONE
binding.storeButtonLayout.visibility = View.VISIBLE
diff --git a/koin/src/main/java/in/koreatech/koin/ui/main/adapter/StoreCategoriesRecyclerAdapter.kt b/koin/src/main/java/in/koreatech/koin/ui/main/adapter/StoreCategoriesRecyclerAdapter.kt
index 4faebb901..691659b30 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/main/adapter/StoreCategoriesRecyclerAdapter.kt
+++ b/koin/src/main/java/in/koreatech/koin/ui/main/adapter/StoreCategoriesRecyclerAdapter.kt
@@ -9,6 +9,7 @@ import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.RequestOptions
import `in`.koreatech.koin.databinding.MainItemStoreBinding
+import `in`.koreatech.koin.databinding.StoreCategoryItemBinding
import `in`.koreatech.koin.domain.model.store.StoreCategories
class StoreCategoriesRecyclerAdapter(): ListAdapter(
@@ -16,7 +17,7 @@ diffCallback
){
var onItemClickListener: OnItemClickListener? = null
- inner class StoreCategoriesViewHolder(val binding: MainItemStoreBinding) : RecyclerView.ViewHolder(binding.root){
+ inner class StoreCategoriesViewHolder(val binding: StoreCategoryItemBinding) : RecyclerView.ViewHolder(binding.root){
val container = binding.container
val storeCategoryImage = binding.imageViewStoreCategory
val storeCategoryName = binding.textViewStoreCategory
@@ -24,7 +25,7 @@ diffCallback
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StoreCategoriesRecyclerAdapter.StoreCategoriesViewHolder {
val inflater = LayoutInflater.from(parent.context)
- val binding = MainItemStoreBinding.inflate(inflater, parent, false)
+ val binding = StoreCategoryItemBinding.inflate(inflater, parent, false)
return StoreCategoriesViewHolder(binding)
}
diff --git a/koin/src/main/java/in/koreatech/koin/ui/main/viewmodel/MainActivityViewModel.kt b/koin/src/main/java/in/koreatech/koin/ui/main/viewmodel/MainActivityViewModel.kt
index aa56b5048..8721ac408 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/main/viewmodel/MainActivityViewModel.kt
+++ b/koin/src/main/java/in/koreatech/koin/ui/main/viewmodel/MainActivityViewModel.kt
@@ -166,7 +166,6 @@ class MainActivityViewModel @Inject constructor(
init {
updateDining()
- getStoreCategories()
}
fun postABTestAssign(title: String) = viewModelScope.launchWithLoading {
@@ -234,9 +233,11 @@ class MainActivityViewModel @Inject constructor(
}
}
- fun getStoreCategories() {
+ fun getStoreCategories(storeCategory: StoreCategories) {
viewModelScope.launchWithLoading {
- _storeCategories.value = getStoreCategoriesUseCase()
+ val categoryList = getStoreCategoriesUseCase().drop(1).toMutableList()
+ categoryList.add(0, storeCategory)
+ _storeCategories.value = categoryList
}
}
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 0abc1b060..d79e69ab4 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
@@ -1,6 +1,7 @@
package `in`.koreatech.koin.ui.store.activity
import android.annotation.SuppressLint
+import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Looper
@@ -35,6 +36,7 @@ import `in`.koreatech.koin.core.viewpager.HorizontalMarginItemDecoration
import `in`.koreatech.koin.databinding.StoreActivityMainBinding
import `in`.koreatech.koin.domain.model.store.StoreEvent
import `in`.koreatech.koin.domain.model.store.StoreSorter
+import `in`.koreatech.koin.ui.businesssignup.BusinessSignUpCheckActivity
import `in`.koreatech.koin.ui.navigation.KoinNavigationDrawerTimeActivity
import `in`.koreatech.koin.ui.navigation.state.MenuState
import `in`.koreatech.koin.ui.store.adapter.StoreCategoriesRecyclerAdapter
@@ -100,18 +102,6 @@ class StoreActivity : KoinNavigationDrawerTimeActivity() {
EventExtra(AnalyticsConstant.DURATION_TIME, getElapsedTimeAndReset().toString())
)
}
-
- EventLogger.logClickEvent(
- EventAction.BUSINESS,
- AnalyticsConstant.Label.SHOP_CLICK,
- it.name,
- EventExtra(
- AnalyticsConstant.PREVIOUS_PAGE,
- viewModel.category.value?.name ?: "Unknown"
- ),
- EventExtra(AnalyticsConstant.CURRENT_PAGE, it.name),
- EventExtra(AnalyticsConstant.DURATION_TIME, getElapsedTimeAndReset().toString())
- )
}
}
@@ -389,7 +379,6 @@ class StoreActivity : KoinNavigationDrawerTimeActivity() {
with(binding) {
storeManyReviewCheckbox.setOnClickListener {
-
if (storeManyReviewCheckbox.isChecked) {
EventLogger.logClickEvent(
EventAction.BUSINESS,
@@ -490,6 +479,10 @@ class StoreActivity : KoinNavigationDrawerTimeActivity() {
viewModel.filterStoreIsDelivery(storeIsDeliveryCheckbox.isChecked)
}
+
+ goToBenefitActivityButton.setOnClickListener {
+ startActivity(Intent(this@StoreActivity, CallBenefitStoreActivity::class.java))
+ }
}
}
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 253df1844..1e9755005 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,21 +4,25 @@ import android.Manifest
import android.annotation.SuppressLint
import android.content.ClipData
import android.content.ClipboardManager
-import android.content.Intent
+import android.content.SharedPreferences
import android.os.Bundle
import android.view.MotionEvent
+import android.view.View
import android.widget.TextView
-import androidx.activity.OnBackPressedCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
+import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import `in`.koreatech.koin.R
+import `in`.koreatech.koin.core.abtest.Experiment
+import `in`.koreatech.koin.core.abtest.ExperimentGroup
import `in`.koreatech.koin.core.analytics.EventAction
import `in`.koreatech.koin.core.analytics.EventExtra
import `in`.koreatech.koin.core.analytics.EventLogger
@@ -97,6 +101,10 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() {
setContentView(binding.root)
initViewModel()
+ if (!isABTestAssigned) {
+ viewModel.postABTestAssign(Experiment.BUSINESS_CALL.experimentTitle)
+ isABTestAssigned = true
+ }
binding.koinBaseAppbar.storeDetailClickListener {
when (it.id) {
@@ -107,46 +115,7 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() {
}
AppBarBase.getRightButtonId() -> {
- dialogElapsedTime = System.currentTimeMillis() - dialogCurrentTime
- reviewElapsedTime = System.currentTimeMillis() - reviewCurrentTime
-
- showCallDialog()
- EventLogger.logClickEvent(
- EventAction.BUSINESS,
- AnalyticsConstant.Label.SHOP_CALL,
- viewModel.store.value?.name ?: "Unknown",
- EventExtra(AnalyticsConstant.DURATION_TIME, (dialogElapsedTime / 1000.0 ).toString())
- )
-
- if(intent.extras?.getBoolean(StoreDetailActivityContract.IS_BENEFIT) == true){
- EventLogger.logClickEvent(
- EventAction.BUSINESS,
- AnalyticsConstant.Label.BENEFIT_SHOP_CALL,
- viewModel.store.value?.name ?: "Unknown",
- EventExtra(AnalyticsConstant.DURATION_TIME, (dialogElapsedTime / 1000.0 ).toString())
- )
- }
- else{
- EventLogger.logClickEvent(
- EventAction.BUSINESS,
- AnalyticsConstant.Label.SHOP_CALL,
- (viewModel.store.value?.name
- ?: "Unknown") ,
- EventExtra(AnalyticsConstant.DURATION_TIME, (dialogElapsedTime / 1000.0 ).toString())
-
- )
- }
- if (currentTab == 2) {// 리뷰탭에서 전화누르기까지 시간
-
- EventLogger.logClickEvent(
- EventAction.BUSINESS,
- AnalyticsConstant.Label.SHOP_DETAIL_VIEW_REVIEW_BACK,
- viewModel.store.value?.name ?: "Unknown",
- EventExtra(AnalyticsConstant.PREVIOUS_PAGE, "리뷰"),
- EventExtra(AnalyticsConstant.CURRENT_PAGE, currentPage),
- EventExtra(AnalyticsConstant.DURATION_TIME, (reviewElapsedTime / 1000.0 ).toString())
- )
- }
+ toggleNavigationDrawer()
}
}
}
@@ -197,7 +166,10 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() {
viewModel.store.value?.name ?: "Unknown",
EventExtra(AnalyticsConstant.PREVIOUS_PAGE, "리뷰"),
EventExtra(AnalyticsConstant.CURRENT_PAGE, currentPage),
- EventExtra(AnalyticsConstant.DURATION_TIME, (reviewElapsedTime / 1000.0 ).toString())
+ EventExtra(
+ AnalyticsConstant.DURATION_TIME,
+ (reviewElapsedTime / 1000.0).toString()
+ )
)
}
}
@@ -218,7 +190,10 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() {
viewModel.store.value?.name ?: "Unknown",
EventExtra(AnalyticsConstant.PREVIOUS_PAGE, "리뷰"),
EventExtra(AnalyticsConstant.CURRENT_PAGE, currentPage),
- EventExtra(AnalyticsConstant.DURATION_TIME, (reviewElapsedTime / 1000.0 ).toString())
+ EventExtra(
+ AnalyticsConstant.DURATION_TIME,
+ (reviewElapsedTime / 1000.0).toString()
+ )
)
}
}
@@ -261,11 +236,30 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() {
.makeShort(getString(R.string.store_detail_wrong_store_id_message))
finish()
}
+
+ when (abtestName) {
+ ExperimentGroup.CALL_NUMBER -> {
+ binding.callFloatingButton.visibility = View.GONE
+ binding.storeDetailPhoneTextview.setTextColor(
+ ContextCompat.getColor(
+ this@StoreDetailActivity,
+ R.color.colorPrimary
+ )
+ )
+ }
+
+ ExperimentGroup.CALL_FLOATING -> {
+ binding.scrollUpButton.visibility = View.GONE
+ binding.storeDetailPhoneImage.visibility = View.GONE
+ }
+ }
+
viewModel.getStoreWithMenu(storeId!!)
viewModel.getShopMenus(storeId)
viewModel.getShopEvents(storeId)
viewModel.getShopReviews(storeId)
+ initCallFunction()
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
@@ -284,10 +278,77 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() {
super.onBackPressed()
}
+ private fun initCallFunction() {
+ binding.storeDetailPhoneImage.setOnClickListener {
+ callingLogic()
+ }
+
+ binding.storeDetailPhoneTextview.setOnClickListener {
+ callingLogic()
+ }
+
+ binding.callFloatingButton.setOnClickListener {
+ callingLogic()
+ }
+ }
+
+ private fun callingLogic() {
+ dialogElapsedTime = System.currentTimeMillis() - dialogCurrentTime
+
+ showCallDialog()
+ if (intent.extras?.getBoolean(StoreDetailActivityContract.IS_BENEFIT) == true) {
+ EventLogger.logClickEvent(
+ EventAction.BUSINESS,
+ AnalyticsConstant.Label.BENEFIT_SHOP_CALL,
+ viewModel.store.value?.name ?: "Unknown",
+ EventExtra(AnalyticsConstant.DURATION_TIME, (dialogElapsedTime / 1000.0).toString())
+ )
+ } else {
+ EventLogger.logClickEvent(
+ EventAction.BUSINESS,
+ AnalyticsConstant.Label.SHOP_CALL,
+ viewModel.store.value?.name ?: "Unknown",
+ EventExtra(AnalyticsConstant.DURATION_TIME, (dialogElapsedTime / 1000.0).toString())
+ )
+ }
+ }
+
private fun initViewModel() {
withLoading(this@StoreDetailActivity, viewModel)
+ observeLiveData(viewModel.variableName) {
+ abtestName = it
+ when (viewModel.variableName.value) {
+ ExperimentGroup.CALL_NUMBER -> {
+ EventLogger.logCustomEvent(
+ action = "AB_TEST",
+ category = "a/b test 로깅(전화하기)",
+ label = AnalyticsConstant.Label.BUSINESS_CALL_NUMBER,
+ value = "number"
+ )
+ binding.callFloatingButton.visibility = View.GONE
+ binding.storeDetailPhoneTextview.setTextColor(
+ ContextCompat.getColor(
+ this@StoreDetailActivity,
+ R.color.colorPrimary
+ )
+ )
+ }
+
+ ExperimentGroup.CALL_FLOATING -> {
+ binding.scrollUpButton.visibility = View.GONE
+ binding.storeDetailPhoneImage.visibility = View.GONE
+ EventLogger.logCustomEvent(
+ action = "AB_TEST",
+ category = "a/b test 로깅(전화하기)",
+ label = AnalyticsConstant.Label.BUSINESS_CALL_FLOATING,
+ value = "floating"
+ )
+ }
+ }
+ }
+
observeLiveData(viewModel.storeReview) {
binding.storeDetailTabLayout.getTabAt(2)?.text =
getString(R.string.review, it.totalCount.toString())
@@ -363,8 +424,8 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() {
binding.storeDetailImageview.apply {
adapter = StoreDetailImageViewpagerAdapter(it.imageUrls) {
ImageZoomableDialog(context, it)
- .also {
- zoomableDialog -> zoomableDialog.show()
+ .also { zoomableDialog ->
+ zoomableDialog.show()
}
EventLogger.logClickEvent(
EventAction.BUSINESS,
@@ -376,6 +437,7 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() {
}
}
+
}
override fun onRestart() {
@@ -390,35 +452,36 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() {
val category = intent.extras?.getString(StoreDetailActivityContract.CATEGORY)
storeElapsedTime = System.currentTimeMillis() - storeCurrentTime
currentPage = "카테고리($category)"
- if ( isSwipeGesture) {
+ if (isSwipeGesture) {
EventLogger.logSwipeEvent(
EventAction.BUSINESS,
AnalyticsConstant.Label.SHOP_DETAIL_VIEW_BACK,
- viewModel.store.value?.name ?: "Unknown" ,
+ viewModel.store.value?.name ?: "Unknown",
EventExtra(AnalyticsConstant.CURRENT_PAGE, category ?: "Unknown"),
- EventExtra(AnalyticsConstant.DURATION_TIME, (storeElapsedTime / 1000.0 ).toString()),
+ EventExtra(AnalyticsConstant.DURATION_TIME, (storeElapsedTime / 1000.0).toString()),
)
- }
- else{
+ } else {
EventLogger.logSwipeEvent(
EventAction.BUSINESS,
AnalyticsConstant.Label.SHOP_DETAIL_VIEW_BACK,
- viewModel.store.value?.name ?: "Unknown" ,
+ viewModel.store.value?.name ?: "Unknown",
EventExtra(AnalyticsConstant.CURRENT_PAGE, category ?: "Unknown"),
- EventExtra(AnalyticsConstant.DURATION_TIME, (storeElapsedTime / 1000.0 ).toString()),
+ EventExtra(AnalyticsConstant.DURATION_TIME, (storeElapsedTime / 1000.0).toString()),
)
}
- if(currentTab == 2){
+ if (currentTab == 2) {
reviewElapsedTime = System.currentTimeMillis() - reviewCurrentTime
+
+
EventLogger.logClickEvent(
EventAction.BUSINESS,
AnalyticsConstant.Label.SHOP_DETAIL_VIEW_REVIEW_BACK,
viewModel.store.value?.name ?: "Unknown",
EventExtra(AnalyticsConstant.PREVIOUS_PAGE, "리뷰"),
EventExtra(AnalyticsConstant.CURRENT_PAGE, currentPage),
- EventExtra(AnalyticsConstant.DURATION_TIME, (reviewElapsedTime / 1000.0 ).toString())
+ EventExtra(AnalyticsConstant.DURATION_TIME, (reviewElapsedTime / 1000.0).toString())
)
}
@@ -496,5 +559,7 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() {
const val ELAPSED_TIME = "elapsedTime"
const val STORE_NAME = "storeName"
const val BACK_ACTION = "back_action"
+ var isABTestAssigned = false
+ var abtestName = ""
}
-}
\ No newline at end of file
+}
diff --git a/koin/src/main/java/in/koreatech/koin/ui/store/adapter/StoreRecyclerAdapter.kt b/koin/src/main/java/in/koreatech/koin/ui/store/adapter/StoreRecyclerAdapter.kt
index b1e8135fd..17ca5d50a 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/store/adapter/StoreRecyclerAdapter.kt
+++ b/koin/src/main/java/in/koreatech/koin/ui/store/adapter/StoreRecyclerAdapter.kt
@@ -42,25 +42,28 @@ class StoreRecyclerAdapter : ListAdapter
fun bind(store: Store) {
binding.storeNameTextview.text = store.name
binding.storeNameTextview.setStoreNameState(store.isOpen)
- binding.storeRatingScoreTextview.text = String.format("%.1f", store.averageRate)
+ binding.storeRatingScoreTextview.text = String.format("%.1f", store.averageRate)
binding.isRatingImageview.setImageResource(
- if(store.reviewCount > 0)
+ if (store.reviewCount > 0)
R.drawable.ic_rating
else
R.drawable.ic_no_rating
)
binding.storeReviewTextview.text = (
- if(store.reviewCount == 0) itemView.context.getString(R.string.store_no_review)
+ if (store.reviewCount == 0) itemView.context.getString(R.string.store_no_review)
else if (store.reviewCount > 10) itemView.context.getString(R.string.store_many_review)
- else itemView.context.getString(R.string.store_review_count, store.reviewCount.toString())
+ else itemView.context.getString(
+ R.string.store_review_count,
+ store.reviewCount.toString()
+ )
).toString()
- if(!store.isOpen){
+ if (!store.isOpen) {
binding.readyStoreFrameLayout.isVisible = true
- if(store.name.hasJongSungAtLastChar()){
+ if (store.name.hasJongSungAtLastChar()) {
val fullText = itemView.context.getString(R.string.store_eun, store.name)
val spannableString = SpannableString(fullText)
@@ -99,9 +102,37 @@ class StoreRecyclerAdapter : ListAdapter
binding.storeDoesNotOpenTextView.text = spannableString
}
- }
- else{
+ } else {
binding.readyStoreFrameLayout.isInvisible = true
+ if (store.benefitDetails.isEmpty()) {
+ binding.viewFlipper.isInvisible = true
+ } else {
+ binding.viewFlipper.isInvisible = false
+ binding.viewFlipper.removeAllViews()
+ }
+
+ }
+
+ for (text in store.benefitDetails) {
+ val newTextView = TextView(binding.root.context)
+ newTextView.text = text
+ newTextView.setTextColor(
+ ContextCompat.getColor(
+ binding.root.context,
+ R.color.blue_alpha20
+ )
+ )
+ newTextView.layoutParams = ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+
+ binding.viewFlipper.addView(newTextView)
+ }
+
+ binding.viewFlipper.post {
+ binding.viewFlipper.startFlipping()
+ binding.viewFlipper.flipInterval = 2500
}
binding.eventImageView.isVisible = store.isEvent
@@ -156,4 +187,4 @@ class StoreRecyclerAdapter : ListAdapter
}
}
}
-}
\ No newline at end of file
+}
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 d5b4c564a..86555af0f 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,6 +1,5 @@
package `in`.koreatech.koin.ui.store.viewmodel
-import android.Manifest
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
@@ -25,6 +24,7 @@ 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.ABTestUseCase
import `in`.koreatech.koin.domain.usecase.user.GetUserInfoUseCase
import `in`.koreatech.koin.domain.util.onFailure
import `in`.koreatech.koin.domain.util.onSuccess
@@ -43,7 +43,10 @@ class StoreDetailViewModel @Inject constructor(
private val getUserInfoUseCase: GetUserInfoUseCase,
private val reviewPromptUscCase: ReviewPromptUscCase,
private val isTokenSavedInDeviceUseCase: IsTokenSavedInDeviceUseCase,
+ private val abTestUseCase: ABTestUseCase,
) : BaseViewModel() {
+
+
val store: LiveData get() = _store
private val _store = MutableLiveData()
val categories: LiveData get() = _categories
@@ -70,6 +73,15 @@ class StoreDetailViewModel @Inject constructor(
private val _tokenState = SingleLiveEvent()
val tokenState: LiveData get() = _tokenState
+ private val _variableName = MutableLiveData()
+ val variableName: LiveData get() = _variableName
+
+ fun postABTestAssign(title: String) = viewModelScope.launchWithLoading {
+ abTestUseCase(title).onSuccess {
+ _variableName.value = it
+ }
+ }
+
fun getStoreWithMenu(storeId: Int) = viewModelScope.launchWithLoading {
getStoreWithMenuUseCase(storeId).also { store ->
_store.value = store
@@ -77,7 +89,7 @@ class StoreDetailViewModel @Inject constructor(
}
}
- fun postReviewPromptNotification(storeId: Int){
+ fun postReviewPromptNotification(storeId: Int) {
viewModelScope.launch {
reviewPromptUscCase(storeId)
.onFailure {
@@ -176,4 +188,4 @@ class StoreDetailViewModel @Inject constructor(
}
}
}
-}
\ No newline at end of file
+}
diff --git a/koin/src/main/res/layout/activity_call_benefit_store_main.xml b/koin/src/main/res/layout/activity_call_benefit_store_main.xml
index ffe37cda3..a64b36414 100644
--- a/koin/src/main/res/layout/activity_call_benefit_store_main.xml
+++ b/koin/src/main/res/layout/activity_call_benefit_store_main.xml
@@ -66,7 +66,8 @@
-
\ No newline at end of file
+
diff --git a/koin/src/main/res/layout/activity_main.xml b/koin/src/main/res/layout/activity_main.xml
index 5e34dd36e..13aab2db2 100644
--- a/koin/src/main/res/layout/activity_main.xml
+++ b/koin/src/main/res/layout/activity_main.xml
@@ -258,14 +258,17 @@
+
+ android:layout_height="match_parent"
+ android:layout_marginVertical="12dp"
+ android:paddingHorizontal="20dp"
+ android:background="@color/white"
+ app:layoutManager="GridLayoutManager"
+ app:spanCount="6"
+ tools:listitem="@layout/store_category_item" />
-
\ No newline at end of file
+
diff --git a/koin/src/main/res/layout/store_activity_detail.xml b/koin/src/main/res/layout/store_activity_detail.xml
index 9faf455b7..236f80a5a 100644
--- a/koin/src/main/res/layout/store_activity_detail.xml
+++ b/koin/src/main/res/layout/store_activity_detail.xml
@@ -27,7 +27,7 @@
app:leftButtonBackground="@drawable/ic_back_arrow"
app:leftButtonHeight="14dp"
app:leftButtonWidth="14dp"
- app:rightButtonBackground="@drawable/ic_call"
+ app:rightButtonBackground="@drawable/ic_hamburger_button"
app:rightButtonHeight="24dp"
app:rightButtonWidth="24dp"
app:titleText="@string/nearby_store" />
@@ -108,20 +108,32 @@
android:textAppearance="@style/TextAppearance.Koin.Regular.15"
android:textColor="@color/gray9"
app:layout_constraintStart_toStartOf="@+id/guideline_start"
- app:layout_constraintTop_toBottomOf="@+id/store_detail_title_textview" />
+ app:layout_constraintTop_toBottomOf="@+id/store_detail_title_textview"/>
+
+
+
+
-
\ No newline at end of file
+
diff --git a/koin/src/main/res/layout/store_activity_main.xml b/koin/src/main/res/layout/store_activity_main.xml
index a15efd3b0..b12ababc0 100644
--- a/koin/src/main/res/layout/store_activity_main.xml
+++ b/koin/src/main/res/layout/store_activity_main.xml
@@ -190,7 +190,6 @@
app:layoutManager="LinearLayoutManager"
tools:itemCount="4"
tools:listitem="@layout/item_store_search" />
-
+
+
+
+
+
+
+
+ app:layout_constraintTop_toBottomOf="@+id/go_to_benefit_activity_button">
-
-
diff --git a/koin/src/main/res/layout/store_list_item.xml b/koin/src/main/res/layout/store_list_item.xml
index 917913e7a..2bb44efea 100644
--- a/koin/src/main/res/layout/store_list_item.xml
+++ b/koin/src/main/res/layout/store_list_item.xml
@@ -1,8 +1,9 @@
-
-
+
+
@@ -16,14 +17,14 @@
android:layout_marginTop="11dp"
android:layout_marginEnd="1dp"
android:layout_marginBottom="4dp"
+ android:stateListAnimator="@null"
app:cardBackgroundColor="@color/white"
app:cardCornerRadius="8dp"
app:cardElevation="1dp"
- android:stateListAnimator="@null"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toBottomOf="parent">
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
+ android:layout_height="match_parent">
+ app:layout_constraintTop_toTopOf="parent" />
+
+
+
+
+
+
+
+
+
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/store_name_textview" />
+ app:layout_constraintStart_toEndOf="@id/is_rating_imageview"
+ app:layout_constraintTop_toTopOf="@id/is_rating_imageview" />
+ app:layout_constraintStart_toEndOf="@id/store_rating_score_textview"
+ app:layout_constraintTop_toTopOf="@id/is_rating_imageview" />
+ android:layout_gravity="right"
+ android:visibility="invisible">
+ app:layout_constraintTop_toTopOf="parent" />