From 9407448e61efeb8f1f12324f1c1158144fe57e99 Mon Sep 17 00:00:00 2001 From: hsgo2430 Date: Wed, 11 Dec 2024 16:53:58 +0900 Subject: [PATCH 1/9] =?UTF-8?q?feature:=20=EC=A0=84=ED=99=94=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EB=B2=84=ED=8A=BC=20=EC=9C=84=EC=B9=98=20A/B?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koreatech/koin/core/abtest/Experiment.kt | 6 +- .../koin/core/constant/AnalyticsConstant.kt | 3 + .../ui/store/activity/StoreDetailActivity.kt | 62 ++++++++++++++++++- .../store/viewmodel/StoreDetailViewModel.kt | 39 ++++++++++++ .../main/res/layout/store_activity_detail.xml | 32 +++++++++- 5 files changed, 138 insertions(+), 4 deletions(-) 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..ed1c1b3fe 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" + + const val CALL_NUMBER = "call_number" + const val CALL_FLOATING = "call_floating" } \ No newline at end of file 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..ae67afb93 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,6 +101,9 @@ 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_number" + const val BUSINESS_CALL_FLOATING = "BUSINESS_call_floating" } const val PREVIOUS_PAGE = "previous_page" 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..ba0f3fd38 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 @@ -7,6 +7,7 @@ import android.content.ClipboardManager import android.content.Intent 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 @@ -14,11 +15,14 @@ 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.ExperimentGroup import `in`.koreatech.koin.core.analytics.EventAction import `in`.koreatech.koin.core.analytics.EventExtra import `in`.koreatech.koin.core.analytics.EventLogger @@ -137,7 +141,6 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() { ) } if (currentTab == 2) {// 리뷰탭에서 전화누르기까지 시간 - EventLogger.logClickEvent( EventAction.BUSINESS, AnalyticsConstant.Label.SHOP_DETAIL_VIEW_REVIEW_BACK, @@ -266,6 +269,7 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() { viewModel.getShopEvents(storeId) viewModel.getShopReviews(storeId) + initCallFunction() } override fun onTouchEvent(event: MotionEvent?): Boolean { @@ -284,6 +288,45 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() { super.onBackPressed() } + private fun initCallFunction(){ + + binding.storeDetailPhoneImage.setOnClickListener { + dialogElapsedTime = System.currentTimeMillis() - dialogCurrentTime + + showCallDialog() + EventLogger.logClickEvent( + EventAction.BUSINESS, + AnalyticsConstant.Label.SHOP_CALL, + viewModel.store.value?.name ?: "Unknown", + EventExtra(AnalyticsConstant.DURATION_TIME, (dialogElapsedTime / 1000.0 ).toString()) + ) + } + + binding.storeDetailPhoneTextview.setOnClickListener{ + dialogElapsedTime = System.currentTimeMillis() - dialogCurrentTime + + showCallDialog() + EventLogger.logClickEvent( + EventAction.BUSINESS, + AnalyticsConstant.Label.SHOP_CALL, + viewModel.store.value?.name ?: "Unknown", + EventExtra(AnalyticsConstant.DURATION_TIME, (dialogElapsedTime / 1000.0 ).toString()) + ) + } + + binding.callFloatingButton.setOnClickListener { + dialogElapsedTime = System.currentTimeMillis() - dialogCurrentTime + + showCallDialog() + 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) @@ -376,6 +419,23 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() { } } + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.callABTestExperimentGroup.collect { + when (it) { + ExperimentGroup.CALL_NUMBER-> { + binding.callFloatingButton.visibility = View.GONE + binding.storeDetailPhoneTextview.setTextColor(getResources().getColor(R.color.colorPrimary)) + } + ExperimentGroup.CALL_FLOATING -> { + binding.scrollUpButton.visibility = View.GONE + binding.storeDetailPhoneImage.visibility = View.GONE + } + } + } + } + } + } override fun onRestart() { 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..d5b0158b0 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 @@ -5,6 +5,11 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel +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.EventLogger +import `in`.koreatech.koin.core.constant.AnalyticsConstant import `in`.koreatech.koin.core.toast.ToastUtil import `in`.koreatech.koin.core.viewmodel.BaseViewModel import `in`.koreatech.koin.core.viewmodel.SingleLiveEvent @@ -25,10 +30,14 @@ 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 import `in`.koreatech.koin.ui.splash.state.TokenState +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import javax.inject.Inject @@ -43,6 +52,7 @@ 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() @@ -70,6 +80,35 @@ class StoreDetailViewModel @Inject constructor( private val _tokenState = SingleLiveEvent() val tokenState: LiveData get() = _tokenState + val callABTestExperimentGroup = flow { + abTestUseCase(Experiment.BUSINESS_CALL.experimentTitle).onSuccess { + emit(it) + when (it) { + ExperimentGroup.CALL_NUMBER -> { + EventLogger.logClickEvent( + EventAction.BUSINESS, + AnalyticsConstant.Label.BUSINESS_CALL_NUMBER, + "전화하기버튼 우측위치" + ) + } + + ExperimentGroup.CALL_NUMBER -> { + EventLogger.logClickEvent( + EventAction.BUSINESS, + AnalyticsConstant.Label.BUSINESS_CALL_FLOATING, + "전화하기버튼 플로팅" + ) + } + } + }.onFailure { + emit(Experiment.BUSINESS_CALL.experimentGroups.first()) + } + }.stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5_000), + initialValue = Experiment.BUSINESS_CALL.experimentGroups.first() + ) + fun getStoreWithMenu(storeId: Int) = viewModelScope.launchWithLoading { getStoreWithMenuUseCase(storeId).also { store -> _store.value = store diff --git a/koin/src/main/res/layout/store_activity_detail.xml b/koin/src/main/res/layout/store_activity_detail.xml index 9faf455b7..8a2933665 100644 --- a/koin/src/main/res/layout/store_activity_detail.xml +++ b/koin/src/main/res/layout/store_activity_detail.xml @@ -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"/> + + + + From 23c48531c247ad2f0a244fd774a397151faa8642 Mon Sep 17 00:00:00 2001 From: hsgo2430 Date: Wed, 11 Dec 2024 18:28:59 +0900 Subject: [PATCH 2/9] =?UTF-8?q?feature:=20=EC=83=81=EC=A0=90=20=EC=95=A1?= =?UTF-8?q?=ED=8B=B0=EB=B9=84=ED=8B=B0=EC=97=90=EC=84=9C=20=ED=98=9C?= =?UTF-8?q?=ED=83=9D=20=EC=95=A1=ED=8B=B0=EB=B9=84=ED=8B=B0=EB=A1=9C=20?= =?UTF-8?q?=EB=84=98=EC=96=B4=EA=B0=80=EB=8A=94=20=EB=B2=84=ED=8A=BC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../res/drawable/rounded_corners_black.xml | 2 +- .../koin/ui/store/activity/StoreActivity.kt | 7 +++- .../main/res/layout/store_activity_main.xml | 39 +++++++++++++++++-- 3 files changed, 42 insertions(+), 6 deletions(-) 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/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..d07a1edec 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 @@ -389,7 +391,6 @@ class StoreActivity : KoinNavigationDrawerTimeActivity() { with(binding) { storeManyReviewCheckbox.setOnClickListener { - if (storeManyReviewCheckbox.isChecked) { EventLogger.logClickEvent( EventAction.BUSINESS, @@ -490,6 +491,10 @@ class StoreActivity : KoinNavigationDrawerTimeActivity() { viewModel.filterStoreIsDelivery(storeIsDeliveryCheckbox.isChecked) } + + goToBenefitActivityButton.setOnClickListener { + startActivity(Intent(this@StoreActivity, CallBenefitStoreActivity::class.java)) + } } } 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"> - - From ea928437b9c51d0824d4cd508cd5b3ee911fde4c Mon Sep 17 00:00:00 2001 From: hsgo2430 Date: Wed, 11 Dec 2024 20:26:48 +0900 Subject: [PATCH 3/9] =?UTF-8?q?feature:=20=EB=A9=94=EC=9D=B8=EC=95=A1?= =?UTF-8?q?=ED=8B=B0=EB=B9=84=ED=8B=B0=EC=97=90=EC=84=9C=20=ED=98=9C?= =?UTF-8?q?=ED=83=9D=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=A7=84=EC=9E=85?= =?UTF-8?q?=EC=A0=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/res/drawable/ic_benefit_icon.png | Bin 0 -> 2438 bytes .../domain/model/store/StoreCategories.kt | 2 +- .../koin/ui/main/activity/MainActivity.kt | 32 +++++++++++------- .../adapter/StoreCategoriesRecyclerAdapter.kt | 5 +-- .../main/viewmodel/MainActivityViewModel.kt | 7 ++-- koin/src/main/res/layout/activity_main.xml | 14 ++++---- 6 files changed, 36 insertions(+), 24 deletions(-) create mode 100644 core/src/main/res/drawable/ic_benefit_icon.png 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 0000000000000000000000000000000000000000..4e471e51346376b2dba9beff4ef528818b39b4f3 GIT binary patch literal 2438 zcmV;133>L3P)${CFHJ4(?4n#=_jUY~{lD5JMRIRE$Ah`;C2@fHaN`;V$ky&xD}-kqJD>3?P~-kF_Qd$;71 z&d%96bIyF{JOBTm%W(KVFg-n8>vp>bDLcsXd?#IZQL4=(h9D&$yDEw@N!Rg6Br@LJ z-5o@k;7|qvfxw{6W;>lnuvA>34*aFQzWxeIL`j4f7Z(qalJ8Qs3r`0=B7TO5f3VpK znrY}SlyR#l@dGE%p0-NMYwOzz&ng9kOG zhlYl7_s*R=r#)*X0BhTb4Cw-!*1bIw4VZ)JVr$lcjPOSj@JAA9LNxqAveSY7ez^L- zi$E}h`U(furoO=4d-q7`eb~1zt#+-*q224&wI$0kQmK^j6+wy~yYr)mj_~sGG9$Yy z|6bPX*YTKAo0c0J{|eV1`i(C^&-M;dPQb$B07Aitu1rcuc&)PvZw)ZyVk`}t-_)O3>&#tYRC z^`xRJ=xzF*mgl2ifM1&eAD@D1r#7peLtN}P+Vmisu(GpaPGM4a8krf4;3z3d7DE8+3YCclATkB*--9yNmZkc*|Jl2ubpw6Kz*f=DrzvI1nXkPft!yHRlx(nBmlJ#khl;Pqbhk5$E$}NVE438FU(YY(xU`yrZ~&5Y zhOR%&krjlWP=~@0Y)_z8{Q>dk??B;YY!-Yi&2n4n(|^bTQ%S1p4`GctXDkjW5(7ML zh|*_9m3L`e$twqS3J9ZGVo=qHrm!skgUsYb>g53n^zZ6>UYSI=W)_T3;ES+8CQV<^kA;{{B|WK zKQjlWa2Da!HHawzn}(2%=VEOYK%o!5C$QC2K_-WjM4CjF!?1a()1*^TeTRuFBmC_8 ztw>?}!cihPOY!mVr1l>vKS%jbX#sOvBdg9d!yVp&%|KNs8ie9H@+lh+cXJ(L;TT+7 zTXRLx5Rk0hp_?d(YZn`z+^nXmuVO9HKoLgCJkUqvZfj(-VE>sD$`s(0#pmFi?|~{O zbV(+=Oj1(VI>Atu3W+QxrW>Ph=4K>`xT~in^M(e^86|lq1kr8m^Rpbq-<5pQY-W>{ z&!~-eDCs8!=5##Yu90R4uN+0q;#Om$_*C7ERk%=z7+&PQ)VJZ_;gCNBw@pmPUmbdh zY#kE!uOQxe0i5VH&U`@uhIIp5kT}JcD0hI8o^aYU)*Vc-t5CNcE+D)ozm8!y#pbZM z^a7m!IR?%f(jo#}9wJJUY~UdxGdH00jKS_|GMlDri+D@hIx(6m!>e|<90Q~3`hOp>#5HXcw2_d=9+TuqMRpN7xM;$#**Ep5$zmwT(VEjoX3$wkI8%vC zK(JXvf#@Q*$RbJtZ-d&{!-DdLkD3sk;Av$vk$=ay`nM#TN|sKRL7@pD^!56GHbTJ# z8tPeavZQ~saMVI94*Osr%u>-^E+e}%gK{7Q=OEX%rbj2b%z|^Sj9;2Ys%eL1T_&zT zKjTF1t&#{cWr?&EIEuGiGHzOys;DDH=L@#$tRo6Dl?<4=#?jWevIPZY*jhN}cx*?@ z_FAS`T?QBS<7t3XWZ1$_z>yQCnzkcV(~>JQ+kKFTby`O$Qhb8EgA(KJ`0D)yO7mEi zQrOdM$I+cmR0?Gs%W2@_VM-CG)s0Bie+#NZAI6xnk|Y_ceN2n^L)u$2hkKvomu5Gf z*Qfj#yYZE-W}}P8@Ap=tvBKhPfs_+y*p*6;NvWz$6e-UZsDfx(-%MRHk;818WV%Jl zf~ox5YY%XLA!OR{(LNW3x}630h0r|Y?(dLtRVWn}>gu;hnI61te2Vq7QnXpMjrac@ z!+Vpf@UN|Vx-H^|QrA{CS$42u1Uuo(=5vHIyV7xE13&zB1B&7LYyzilhc(h#bP%0I zLsKy@GcY*?n#eznE}?hn-DTc=M$$G*&sR-UEM3!7u+A#Dlp2AC1m9<;RI=*`IFz2dAGd1p5V|S^xk507*qoM6N<$ Ef-_>7xc~qF literal 0 HcmV?d00001 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..8d5a0909d 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,20 @@ 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)) + } + 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) + } } } @@ -265,8 +272,7 @@ class MainActivity : KoinNavigationDrawerTimeActivity() { } recyclerViewStoreCategory.apply { - layoutManager = - LinearLayoutManager(this@MainActivity, RecyclerView.HORIZONTAL, false) + layoutManager = GridLayoutManager(this@MainActivity, 6) adapter = storeCategoriesRecyclerAdapter } @@ -303,6 +309,8 @@ class MainActivity : KoinNavigationDrawerTimeActivity() { } private fun initViewModel() = with(viewModel) { + getStoreCategories(StoreCategories(-1, R.drawable.ic_benefit_icon, "혜택")) + observeLiveData(isLoading) { binding.mainSwipeRefreshLayout.isRefreshing = it } @@ -319,7 +327,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/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" /> Date: Thu, 12 Dec 2024 02:39:21 +0900 Subject: [PATCH 4/9] =?UTF-8?q?Add:=20=EC=83=81=EC=A0=90=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=EC=A0=95=EB=B3=B4=20=ED=95=84=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koreatech/koin/data/mapper/StoreMapper.kt | 4 +- .../data/response/store/StoreItemResponse.kt | 4 +- .../koin/domain/model/store/Store.kt | 5 +- .../ui/store/adapter/StoreRecyclerAdapter.kt | 49 +++++++++--- .../activity_call_benefit_store_main.xml | 5 +- .../main/res/layout/item_store_benefit.xml | 7 +- koin/src/main/res/layout/store_list_item.xml | 80 ++++++++++++------- 7 files changed, 106 insertions(+), 48 deletions(-) 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/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/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/item_store_benefit.xml b/koin/src/main/res/layout/item_store_benefit.xml index 6e518622e..f2a1f15b4 100644 --- a/koin/src/main/res/layout/item_store_benefit.xml +++ b/koin/src/main/res/layout/item_store_benefit.xml @@ -3,13 +3,14 @@ xmlns:tools="http://schemas.android.com/tools"> - \ No newline at end of file + 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" /> From a7160b46dcc3820b79dfe59da314be10ec45c53e Mon Sep 17 00:00:00 2001 From: hsgo2430 Date: Thu, 12 Dec 2024 13:21:27 +0900 Subject: [PATCH 5/9] =?UTF-8?q?fix:=20=ED=94=BC=EB=93=9C=EB=B0=B1=20?= =?UTF-8?q?=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/store/activity/StoreDetailActivity.kt | 45 +++++++------------ .../store/viewmodel/StoreDetailViewModel.kt | 4 +- 2 files changed, 19 insertions(+), 30 deletions(-) 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 ba0f3fd38..12d78b39b 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 @@ -289,44 +289,31 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() { } private fun initCallFunction(){ - binding.storeDetailPhoneImage.setOnClickListener { - dialogElapsedTime = System.currentTimeMillis() - dialogCurrentTime - - showCallDialog() - EventLogger.logClickEvent( - EventAction.BUSINESS, - AnalyticsConstant.Label.SHOP_CALL, - viewModel.store.value?.name ?: "Unknown", - EventExtra(AnalyticsConstant.DURATION_TIME, (dialogElapsedTime / 1000.0 ).toString()) - ) + callingLogic() } binding.storeDetailPhoneTextview.setOnClickListener{ - dialogElapsedTime = System.currentTimeMillis() - dialogCurrentTime - - showCallDialog() - EventLogger.logClickEvent( - EventAction.BUSINESS, - AnalyticsConstant.Label.SHOP_CALL, - viewModel.store.value?.name ?: "Unknown", - EventExtra(AnalyticsConstant.DURATION_TIME, (dialogElapsedTime / 1000.0 ).toString()) - ) + callingLogic() } binding.callFloatingButton.setOnClickListener { - dialogElapsedTime = System.currentTimeMillis() - dialogCurrentTime - - showCallDialog() - EventLogger.logClickEvent( - EventAction.BUSINESS, - AnalyticsConstant.Label.SHOP_CALL, - viewModel.store.value?.name ?: "Unknown", - EventExtra(AnalyticsConstant.DURATION_TIME, (dialogElapsedTime / 1000.0 ).toString()) - ) + callingLogic() } } + private fun callingLogic(){ + dialogElapsedTime = System.currentTimeMillis() - dialogCurrentTime + + showCallDialog() + 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) @@ -425,7 +412,7 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() { when (it) { ExperimentGroup.CALL_NUMBER-> { binding.callFloatingButton.visibility = View.GONE - binding.storeDetailPhoneTextview.setTextColor(getResources().getColor(R.color.colorPrimary)) + binding.storeDetailPhoneTextview.setTextColor(ContextCompat.getColor(this@StoreDetailActivity, R.color.colorPrimary)) } ExperimentGroup.CALL_FLOATING -> { binding.scrollUpButton.visibility = View.GONE 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 d5b0158b0..b7e38ddff 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 @@ -39,6 +39,7 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import timber.log.Timber import javax.inject.Inject @HiltViewModel @@ -92,7 +93,7 @@ class StoreDetailViewModel @Inject constructor( ) } - ExperimentGroup.CALL_NUMBER -> { + ExperimentGroup.CALL_FLOATING -> { EventLogger.logClickEvent( EventAction.BUSINESS, AnalyticsConstant.Label.BUSINESS_CALL_FLOATING, @@ -102,6 +103,7 @@ class StoreDetailViewModel @Inject constructor( } }.onFailure { emit(Experiment.BUSINESS_CALL.experimentGroups.first()) + Timber.d("Fail to get A/b Test Data") } }.stateIn( scope = viewModelScope, From 6cbabb29562add4a3faf088db06303e93af62b3c Mon Sep 17 00:00:00 2001 From: nazero Date: Fri, 13 Dec 2024 20:13:51 +0900 Subject: [PATCH 6/9] test --- .../java/in/koreatech/koin/core/analytics/EventLogger.kt | 3 ++- .../koin/ui/store/viewmodel/StoreDetailViewModel.kt | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) 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..296391122 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 @@ -96,6 +96,7 @@ object EventLogger { param("${it.key}_debug", it.value) } } + println("EventLogger: ${action.value}_debug, ${category.value}_debug, $label (debug), $value") } else { Firebase.analytics.logEvent(action.value) { param(EVENT_CATEGORY, category.value) @@ -122,4 +123,4 @@ enum class EventCategory(val value: String) { 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/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 b7e38ddff..60bd80aa4 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 @@ -89,7 +89,7 @@ class StoreDetailViewModel @Inject constructor( EventLogger.logClickEvent( EventAction.BUSINESS, AnalyticsConstant.Label.BUSINESS_CALL_NUMBER, - "전화하기버튼 우측위치" + "number" ) } @@ -97,7 +97,7 @@ class StoreDetailViewModel @Inject constructor( EventLogger.logClickEvent( EventAction.BUSINESS, AnalyticsConstant.Label.BUSINESS_CALL_FLOATING, - "전화하기버튼 플로팅" + "floating" ) } } @@ -217,4 +217,4 @@ class StoreDetailViewModel @Inject constructor( } } } -} \ No newline at end of file +} From 0b93a0ac68c944e7c7ec0c5a75c65d5564d6fe8c Mon Sep 17 00:00:00 2001 From: nazero Date: Sat, 14 Dec 2024 00:05:48 +0900 Subject: [PATCH 7/9] Add: logging --- .../koin/core/analytics/EventLogger.kt | 14 ++++++++--- .../koin/core/constant/AnalyticsConstant.kt | 6 ++--- .../koin/ui/main/activity/MainActivity.kt | 8 +++++++ .../koin/ui/store/activity/StoreActivity.kt | 12 ---------- .../ui/store/activity/StoreDetailActivity.kt | 24 +++++++++++++------ .../store/viewmodel/StoreDetailViewModel.kt | 8 +++---- 6 files changed, 43 insertions(+), 29 deletions(-) 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 296391122..b38a6cab7 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,13 @@ object EventLogger { logEvent(action, EventCategory.CLICK, label, value, *extras) } + fun logClickABTestEvent(action: EventAction, label: String, value: String, vararg extras: EventExtra) { + logEvent(action, EventCategory.ABTEST, label, value, *extras) + } + + + + /** * 스크롤 이벤트 로깅 * @param action: 이벤트 발생 도메인(BUSINESS, CAMPUS, USER) @@ -96,7 +103,7 @@ object EventLogger { param("${it.key}_debug", it.value) } } - println("EventLogger: ${action.value}_debug, ${category.value}_debug, $label (debug), $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) @@ -113,14 +120,15 @@ 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"), + ABTEST("a/b test 로깅(전화하기)") } 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 ae67afb93..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 @@ -102,11 +102,11 @@ object AnalyticsConstant { const val POPULAR_NOTICE_BANNER = "popular_notice_banner" const val TO_MANAGE_KEYWORD = "to_manage_keyword" - const val BUSINESS_CALL_NUMBER = " BUSINESS_call_number" - const val BUSINESS_CALL_FLOATING = "BUSINESS_call_floating" + 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/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 8d5a0909d..33aa09fdf 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 @@ -151,6 +151,14 @@ class MainActivity : KoinNavigationDrawerTimeActivity() { setOnItemClickListener { id, name -> 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( 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 d07a1edec..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 @@ -102,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()) - ) } } 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 12d78b39b..03ab722cb 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 @@ -306,12 +306,22 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() { dialogElapsedTime = System.currentTimeMillis() - dialogCurrentTime 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()) + ) + } } @@ -544,4 +554,4 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() { const val STORE_NAME = "storeName" const val BACK_ACTION = "back_action" } -} \ 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 60bd80aa4..178097a36 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 @@ -86,16 +86,16 @@ class StoreDetailViewModel @Inject constructor( emit(it) when (it) { ExperimentGroup.CALL_NUMBER -> { - EventLogger.logClickEvent( - EventAction.BUSINESS, + EventLogger.logClickABTestEvent( + EventAction.ABTEST, AnalyticsConstant.Label.BUSINESS_CALL_NUMBER, "number" ) } ExperimentGroup.CALL_FLOATING -> { - EventLogger.logClickEvent( - EventAction.BUSINESS, + EventLogger.logClickABTestEvent( + EventAction.ABTEST, AnalyticsConstant.Label.BUSINESS_CALL_FLOATING, "floating" ) From 6ad88ff4d87091271e2df8a053d97d09eafd3580 Mon Sep 17 00:00:00 2001 From: nazero Date: Sat, 14 Dec 2024 00:06:03 +0900 Subject: [PATCH 8/9] =?UTF-8?q?fix:=20=EC=83=81=EC=A0=90=20=EB=A1=9C?= =?UTF-8?q?=EA=B9=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koreatech/koin/core/abtest/Experiment.kt | 2 +- .../koin/core/analytics/EventLogger.kt | 8 +- .../koin/ui/main/activity/MainActivity.kt | 37 +++++ .../ui/store/activity/StoreDetailActivity.kt | 126 +++++++++++------- .../store/viewmodel/StoreDetailViewModel.kt | 51 ++----- 5 files changed, 127 insertions(+), 97 deletions(-) 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 ed1c1b3fe..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 @@ -31,4 +31,4 @@ object ExperimentGroup { const val CALL_NUMBER = "call_number" const val CALL_FLOATING = "call_floating" -} \ No newline at end of file +} 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 b38a6cab7..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,11 +24,6 @@ object EventLogger { logEvent(action, EventCategory.CLICK, label, value, *extras) } - fun logClickABTestEvent(action: EventAction, label: String, value: String, vararg extras: EventExtra) { - logEvent(action, EventCategory.ABTEST, label, value, *extras) - } - - /** @@ -78,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) @@ -128,7 +125,6 @@ enum class EventCategory(val value: String) { SCROLL("scroll"), SWIPE("swipe"), // 하단 뒤로가기(아이폰의 swipe 뒤로가기와 대응) NOTIFICATION("notification"), - ABTEST("a/b test 로깅(전화하기)") } data class EventExtra(val key: String, val value: String) 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 33aa09fdf..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 @@ -214,6 +214,7 @@ class MainActivity : KoinNavigationDrawerTimeActivity() { scrollPercentage = 100.0f * offset / (range - extent) } viewModel.postABTestAssign(Experiment.BENEFIT_STORE.experimentTitle) + storeListButton.setOnClickListener { gotoStoreActivity(0) } @@ -319,6 +320,42 @@ 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 } 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 03ab722cb..48efdb8c3 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,12 +4,11 @@ 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 @@ -22,6 +21,7 @@ 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 @@ -101,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) { @@ -115,28 +119,27 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() { 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){ + 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()) + EventExtra( + AnalyticsConstant.DURATION_TIME, + (dialogElapsedTime / 1000.0).toString() + ) ) - } - else{ + } else { EventLogger.logClickEvent( EventAction.BUSINESS, AnalyticsConstant.Label.SHOP_CALL, (viewModel.store.value?.name - ?: "Unknown") , - EventExtra(AnalyticsConstant.DURATION_TIME, (dialogElapsedTime / 1000.0 ).toString()) + ?: "Unknown"), + EventExtra( + AnalyticsConstant.DURATION_TIME, + (dialogElapsedTime / 1000.0).toString() + ) ) } @@ -147,7 +150,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() + ) ) } } @@ -200,7 +206,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() + ) ) } } @@ -221,7 +230,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() + ) ) } } @@ -288,12 +300,12 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() { super.onBackPressed() } - private fun initCallFunction(){ + private fun initCallFunction() { binding.storeDetailPhoneImage.setOnClickListener { callingLogic() } - binding.storeDetailPhoneTextview.setOnClickListener{ + binding.storeDetailPhoneTextview.setOnClickListener { callingLogic() } @@ -302,19 +314,18 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() { } } - private fun callingLogic(){ + private fun callingLogic() { dialogElapsedTime = System.currentTimeMillis() - dialogCurrentTime showCallDialog() - if(intent.extras?.getBoolean(StoreDetailActivityContract.IS_BENEFIT) == true){ + 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()) + EventExtra(AnalyticsConstant.DURATION_TIME, (dialogElapsedTime / 1000.0).toString()) ) - } - else { + } else { EventLogger.logClickEvent( EventAction.BUSINESS, AnalyticsConstant.Label.SHOP_CALL, @@ -328,6 +339,35 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() { private fun initViewModel() { withLoading(this@StoreDetailActivity, viewModel) + observeLiveData(viewModel.variableName) { + 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 -> { + 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()) @@ -403,8 +443,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, @@ -416,22 +456,6 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() { } } - lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.STARTED) { - viewModel.callABTestExperimentGroup.collect { - when (it) { - 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 - } - } - } - } - } } @@ -447,27 +471,26 @@ 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, @@ -475,7 +498,7 @@ 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()) ) } @@ -553,5 +576,6 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() { const val ELAPSED_TIME = "elapsedTime" const val STORE_NAME = "storeName" const val BACK_ACTION = "back_action" + var isABTestAssigned = false } } 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 178097a36..bb45dd80c 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,15 +1,9 @@ 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.abtest.Experiment -import `in`.koreatech.koin.core.abtest.ExperimentGroup -import `in`.koreatech.koin.core.analytics.EventAction -import `in`.koreatech.koin.core.analytics.EventLogger -import `in`.koreatech.koin.core.constant.AnalyticsConstant import `in`.koreatech.koin.core.toast.ToastUtil import `in`.koreatech.koin.core.viewmodel.BaseViewModel import `in`.koreatech.koin.core.viewmodel.SingleLiveEvent @@ -35,11 +29,7 @@ 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.flow.SharingStarted -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch -import timber.log.Timber import javax.inject.Inject @HiltViewModel @@ -53,8 +43,10 @@ class StoreDetailViewModel @Inject constructor( private val getUserInfoUseCase: GetUserInfoUseCase, private val reviewPromptUscCase: ReviewPromptUscCase, private val isTokenSavedInDeviceUseCase: IsTokenSavedInDeviceUseCase, - private val abTestUseCase: ABTestUseCase + private val abTestUseCase: ABTestUseCase, ) : BaseViewModel() { + + val store: LiveData get() = _store private val _store = MutableLiveData() val categories: LiveData get() = _categories @@ -81,35 +73,16 @@ class StoreDetailViewModel @Inject constructor( private val _tokenState = SingleLiveEvent() val tokenState: LiveData get() = _tokenState - val callABTestExperimentGroup = flow { - abTestUseCase(Experiment.BUSINESS_CALL.experimentTitle).onSuccess { - emit(it) - when (it) { - ExperimentGroup.CALL_NUMBER -> { - EventLogger.logClickABTestEvent( - EventAction.ABTEST, - AnalyticsConstant.Label.BUSINESS_CALL_NUMBER, - "number" - ) - } + private val _variableName = MutableLiveData() + val variableName: LiveData get() = _variableName - ExperimentGroup.CALL_FLOATING -> { - EventLogger.logClickABTestEvent( - EventAction.ABTEST, - AnalyticsConstant.Label.BUSINESS_CALL_FLOATING, - "floating" - ) - } - } - }.onFailure { - emit(Experiment.BUSINESS_CALL.experimentGroups.first()) - Timber.d("Fail to get A/b Test Data") + + fun postABTestAssign(title: String) = viewModelScope.launchWithLoading { + abTestUseCase(title).onSuccess { + _variableName.value = it } - }.stateIn( - scope = viewModelScope, - started = SharingStarted.WhileSubscribed(5_000), - initialValue = Experiment.BUSINESS_CALL.experimentGroups.first() - ) + } + fun getStoreWithMenu(storeId: Int) = viewModelScope.launchWithLoading { getStoreWithMenuUseCase(storeId).also { store -> @@ -118,7 +91,7 @@ class StoreDetailViewModel @Inject constructor( } } - fun postReviewPromptNotification(storeId: Int){ + fun postReviewPromptNotification(storeId: Int) { viewModelScope.launch { reviewPromptUscCase(storeId) .onFailure { From 538a377372d07cce7c1ba0fec9ca7dd22878f448 Mon Sep 17 00:00:00 2001 From: nazero Date: Sat, 14 Dec 2024 22:30:59 +0900 Subject: [PATCH 9/9] =?UTF-8?q?Fix:=20=EC=95=B1=20=EB=B0=94=20=EC=98=A4?= =?UTF-8?q?=EB=A5=B8=EC=AA=BD=20=EB=B2=84=ED=8A=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/store/activity/StoreDetailActivity.kt | 66 +++++++------------ .../store/viewmodel/StoreDetailViewModel.kt | 2 - .../main/res/layout/store_activity_detail.xml | 4 +- 3 files changed, 27 insertions(+), 45 deletions(-) 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 48efdb8c3..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 @@ -115,47 +115,7 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() { } AppBarBase.getRightButtonId() -> { - dialogElapsedTime = System.currentTimeMillis() - dialogCurrentTime - reviewElapsedTime = System.currentTimeMillis() - reviewCurrentTime - - 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() - ) - - ) - } - 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() } } } @@ -276,6 +236,24 @@ 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) @@ -340,6 +318,7 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() { withLoading(this@StoreDetailActivity, viewModel) observeLiveData(viewModel.variableName) { + abtestName = it when (viewModel.variableName.value) { ExperimentGroup.CALL_NUMBER -> { EventLogger.logCustomEvent( @@ -358,6 +337,8 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() { } ExperimentGroup.CALL_FLOATING -> { + binding.scrollUpButton.visibility = View.GONE + binding.storeDetailPhoneImage.visibility = View.GONE EventLogger.logCustomEvent( action = "AB_TEST", category = "a/b test 로깅(전화하기)", @@ -492,6 +473,8 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() { if (currentTab == 2) { reviewElapsedTime = System.currentTimeMillis() - reviewCurrentTime + + EventLogger.logClickEvent( EventAction.BUSINESS, AnalyticsConstant.Label.SHOP_DETAIL_VIEW_REVIEW_BACK, @@ -577,5 +560,6 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() { const val STORE_NAME = "storeName" const val BACK_ACTION = "back_action" var isABTestAssigned = false + var abtestName = "" } } 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 bb45dd80c..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 @@ -76,14 +76,12 @@ class StoreDetailViewModel @Inject constructor( 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 diff --git a/koin/src/main/res/layout/store_activity_detail.xml b/koin/src/main/res/layout/store_activity_detail.xml index 8a2933665..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" /> @@ -453,4 +453,4 @@ - \ No newline at end of file +