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
new file mode 100644
index 000000000..8b868881f
--- /dev/null
+++ b/core/src/main/java/in/koreatech/koin/core/analytics/EventLogger.kt
@@ -0,0 +1,48 @@
+package `in`.koreatech.koin.core.analytics
+
+import com.google.firebase.analytics.ktx.analytics
+import com.google.firebase.analytics.ktx.logEvent
+import com.google.firebase.ktx.Firebase
+import `in`.koreatech.koin.core.BuildConfig
+import `in`.koreatech.koin.core.constant.AnalyticsConstant
+
+object EventLogger {
+
+ private const val EVENT_CATEGORY = "event_category"
+ private const val EVENT_LABEL = "event_label"
+ private const val VALUE = "value"
+
+ /**
+ * @param action: 이벤트 발생 도메인(BUSINESS, CAMPUS, USER)
+ * @param label: 이벤트 소분류
+ * @param value: 이벤트 값
+ */
+ fun logClickEvent(action: String, label: String, value: String) {
+ logEvent(action, AnalyticsConstant.Category.CLICK, label, value)
+ }
+
+ /**
+ * @param action: 이벤트 발생 도메인(BUSINESS, CAMPUS, USER)
+ * @param label: 이벤트 소분류
+ * @param value: 이벤트 값
+ */
+ fun logScrollEvent(action: String, label: String, value: String) {
+ logEvent(action, AnalyticsConstant.Category.SCROLL, label, value)
+ }
+
+ /**
+ * @param action: 이벤트 발생 도메인(BUSINESS, CAMPUS, USER)
+ * @param category: 이벤트 종류(click, scroll, ...)
+ * @param label: 이벤트 소분류
+ * @param value: 이벤트 값
+ * @sample logEvent("BUSINESS", "click", "main_shop_categories", "전체보기")
+ */
+ private fun logEvent(action: String, category: String, label: String, value: String) {
+ if (BuildConfig.IS_DEBUG) return
+ Firebase.analytics.logEvent(action) {
+ param(EVENT_CATEGORY, category)
+ param(EVENT_LABEL, label)
+ param(VALUE, value)
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/in/koreatech/koin/core/appbar/AppBarBase.java b/core/src/main/java/in/koreatech/koin/core/appbar/AppBarBase.java
index 9408291f0..206541414 100644
--- a/core/src/main/java/in/koreatech/koin/core/appbar/AppBarBase.java
+++ b/core/src/main/java/in/koreatech/koin/core/appbar/AppBarBase.java
@@ -17,6 +17,8 @@
import in.koreatech.koin.core.R;
+import in.koreatech.koin.core.analytics.EventLogger;
+import in.koreatech.koin.core.constant.AnalyticsConstant;
public class AppBarBase extends AppBarLayout {
@@ -50,7 +52,14 @@ public void setOnClickListener(OnClickListener onClickListener) {
this.onClickListener = onClickListener;
background.setOnClickListener(onClickListener);
leftButton.setOnClickListener(onClickListener);
- rightButton.setOnClickListener(onClickListener);
+ rightButton.setOnClickListener( v -> {
+ onClickListener.onClick(v);
+ EventLogger.INSTANCE.logClickEvent(
+ AnalyticsConstant.Domain.USER,
+ AnalyticsConstant.Label.HAMBURGER,
+ getContext().getString(R.string.hamburger)
+ );
+ });
title.setOnClickListener(onClickListener);
}
@@ -107,7 +116,7 @@ private void setTypeArray(TypedArray typedArray) {
leftButton.setBackground(leftButtonBackground);
leftButton.setText(leftButtonString);
leftButton.setVisibility(leftButtonVisibility);
- if(leftButtonHeight!= -1 || leftButtonWidth != -1){
+ if (leftButtonHeight != -1 || leftButtonWidth != -1) {
leftButton.setHeight(leftButtonHeight);
leftButton.setWidth(leftButtonWidth);
}
@@ -116,7 +125,7 @@ private void setTypeArray(TypedArray typedArray) {
rightButton.setBackground(rightButtonBackground);
rightButton.setText(rightButtonString);
rightButton.setVisibility(rightButtonVisibility);
- if(leftButtonHeight!= -1 || leftButtonWidth != -1){
+ if (leftButtonHeight != -1 || leftButtonWidth != -1) {
rightButton.setHeight(rightButtonHeight);
rightButton.setWidth(rightButtonWidth);
}
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
new file mode 100644
index 000000000..6871441fa
--- /dev/null
+++ b/core/src/main/java/in/koreatech/koin/core/constant/AnalyticsConstant.kt
@@ -0,0 +1,48 @@
+package `in`.koreatech.koin.core.constant
+
+object AnalyticsConstant {
+
+ object Domain {
+ const val BUSINESS = "BUSINESS"
+ const val CAMPUS = "CAMPUS"
+ const val USER = "USER"
+ }
+
+ object Category {
+ const val CLICK = "click"
+ const val SCROLL = "scroll"
+ }
+
+ object Label {
+ const val MAIN_SHOP_CATEGORIES = "main_shop_categories"
+ const val SHOP_CATEGORIES = "shop_categories"
+ const val SHOP_CATEGORIES_SEARCH = "shop_categories_search"
+ const val HAMBURGER = "hamburger"
+ const val HAMBURGER_SHOP = "${HAMBURGER}_shop"
+ const val HAMBURGER_DINING = "${HAMBURGER}_dining"
+ const val HAMBURGER_MY_INFO_WITHOUT_LOGIN = "${HAMBURGER}_my_info_without_login"
+ const val HAMBURGER_MY_INFO_WITH_LOGIN = "${HAMBURGER}_my_info_with_login"
+ const val HAMBURGER_BUS = "${HAMBURGER}_bus"
+ const val USER_ONLY_OK = "user_only_ok"
+ const val MAIN_MENU_MOVEDETAILVIEW = "main_menu_moveDetailView"
+ const val MAIN_MENU_CORNER = "main_menu_corner"
+ const val MENU_TIME = "menu_time"
+ const val MAIN_BUS = "main_bus"
+ const val MAIN_BUS_CHANGETOFROM = "main_bus_changeToFrom"
+ const val MAIN_BUS_SCROLL = "main_bus_scroll"
+ const val BUS_DEPARTURE = "bus_departure"
+ const val BUS_ARRIVAL = "bus_arrival"
+ const val BUS_TIMETABLE = "bus_timetable"
+ const val BUS_TIMETABLE_AREA = "bus_timetable_area"
+ const val BUS_TIMETABLE_TIME = "bus_timetable_time"
+ const val BUS_TIMETABLE_EXPRESS = "bus_timetable_express"
+ const val MENU_IMAGE = "menu_image"
+ const val LOGIN = "login"
+ const val START_SIGN_UP = "start_sign_up"
+ const val COMPLETE_SIGN_UP = "complete_sign_up"
+ const val SHOP_PICTURE = "shop_picture"
+ const val SHOP_CALL = "shop_call"
+ const val SHOP_CLICK = "shop_click"
+ }
+
+}
\ No newline at end of file
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index f6bee74e2..e97e247f1 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -76,4 +76,5 @@
문의하기
님, 안녕하세요!
내 정보
+ 햄버거
diff --git a/data/src/main/res/values/strings.xml b/data/src/main/res/values/strings.xml
index 919578216..d59d863ed 100644
--- a/data/src/main/res/values/strings.xml
+++ b/data/src/main/res/values/strings.xml
@@ -41,6 +41,7 @@
통학버스
대성고속
셔틀버스
+ 학교셔틀
%1$d번 버스
기계공학부
diff --git a/domain/src/main/java/in/koreatech/koin/domain/util/DiningUtil.kt b/domain/src/main/java/in/koreatech/koin/domain/util/DiningUtil.kt
index bdda26a05..5dfa1fea5 100644
--- a/domain/src/main/java/in/koreatech/koin/domain/util/DiningUtil.kt
+++ b/domain/src/main/java/in/koreatech/koin/domain/util/DiningUtil.kt
@@ -40,4 +40,14 @@ object DiningUtil {
}
return null
}
+
+ fun getKoreanName(type: String): String {
+ return when (type) {
+ DiningType.Breakfast.typeEnglish -> DiningType.Breakfast.typeKorean
+ DiningType.Lunch.typeEnglish -> DiningType.Lunch.typeKorean
+ DiningType.Dinner.typeEnglish -> DiningType.Dinner.typeKorean
+ DiningType.NextBreakfast.typeEnglish -> DiningType.NextBreakfast.typeKorean
+ else -> "Unknown type"
+ }
+ }
}
\ No newline at end of file
diff --git a/koin/src/main/java/in/koreatech/koin/ui/bus/fragment/BusMainFragment.kt b/koin/src/main/java/in/koreatech/koin/ui/bus/fragment/BusMainFragment.kt
index e75bf77b1..c5613c3cc 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/bus/fragment/BusMainFragment.kt
+++ b/koin/src/main/java/in/koreatech/koin/ui/bus/fragment/BusMainFragment.kt
@@ -24,6 +24,8 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.LinearLayoutManager
import dagger.hilt.android.AndroidEntryPoint
+import `in`.koreatech.koin.core.analytics.EventLogger
+import `in`.koreatech.koin.core.constant.AnalyticsConstant
import `in`.koreatech.koin.core.util.dataBinding
@AndroidEntryPoint
@@ -44,11 +46,36 @@ class BusMainFragment : Fragment(R.layout.bus_main_fragment) {
private fun initView() = with(binding) {
busDepartureSpinner.setSelection(BusNode.Koreatech.spinnerSelection)
busArrivalSpinner.setSelection(BusNode.Terminal.spinnerSelection)
+ busDepartureSpinner.setOnTouchListener { _, _ ->
+ viewModel.isUserSelection = true
+ busDepartureSpinner.performClick()
+ }
busDepartureSpinner.setOnItemSelectedListener { _, _, position, _ ->
viewModel.setDeparture(position.busNodeSelection)
+ if(viewModel.isUserSelection) {
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.CAMPUS,
+ AnalyticsConstant.Label.BUS_DEPARTURE,
+ resources.getStringArray(R.array.bus_place)[position]
+ )
+ viewModel.isUserSelection = false
+ }
+ }
+
+ busArrivalSpinner.setOnTouchListener { _, _ ->
+ viewModel.isUserSelection = true
+ busArrivalSpinner.performClick()
}
busArrivalSpinner.setOnItemSelectedListener { _, _, position, _ ->
viewModel.setArrival(position.busNodeSelection)
+ if(viewModel.isUserSelection) {
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.CAMPUS,
+ AnalyticsConstant.Label.BUS_ARRIVAL,
+ resources.getStringArray(R.array.bus_place)[position]
+ )
+ viewModel.isUserSelection = false
+ }
}
recyclerView.apply {
layoutManager = LinearLayoutManager(requireContext())
diff --git a/koin/src/main/java/in/koreatech/koin/ui/bus/fragment/BusTimetableFragment.kt b/koin/src/main/java/in/koreatech/koin/ui/bus/fragment/BusTimetableFragment.kt
index 317bc0eab..f23636b97 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/bus/fragment/BusTimetableFragment.kt
+++ b/koin/src/main/java/in/koreatech/koin/ui/bus/fragment/BusTimetableFragment.kt
@@ -12,6 +12,8 @@ import android.view.View
import androidx.fragment.app.commit
import androidx.fragment.app.viewModels
import dagger.hilt.android.AndroidEntryPoint
+import `in`.koreatech.koin.core.analytics.EventLogger
+import `in`.koreatech.koin.core.constant.AnalyticsConstant
@AndroidEntryPoint
class BusTimetableFragment : DataBindingFragment() {
@@ -39,12 +41,27 @@ class BusTimetableFragment : DataBindingFragment()
binding.busTimetableBustypeShuttle.setOnClickListener {
busTimetableViewModel.setBusType(BusType.Shuttle)
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.CAMPUS,
+ AnalyticsConstant.Label.BUS_TIMETABLE,
+ getString(R.string.bus_name_school_shuttle)
+ )
}
binding.busTimetableBustypeDaesung.setOnClickListener {
busTimetableViewModel.setBusType(BusType.Express)
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.CAMPUS,
+ AnalyticsConstant.Label.BUS_TIMETABLE,
+ getString(R.string.bus_name_express)
+ )
}
binding.busTimetableBustypeCity.setOnClickListener {
busTimetableViewModel.setBusType(BusType.City)
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.CAMPUS,
+ AnalyticsConstant.Label.BUS_TIMETABLE,
+ getString(R.string.bus_name_city)
+ )
}
}
diff --git a/koin/src/main/java/in/koreatech/koin/ui/bus/fragment/ExpressBusTimetableFragment.kt b/koin/src/main/java/in/koreatech/koin/ui/bus/fragment/ExpressBusTimetableFragment.kt
index 094bdf497..6f6863f57 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/bus/fragment/ExpressBusTimetableFragment.kt
+++ b/koin/src/main/java/in/koreatech/koin/ui/bus/fragment/ExpressBusTimetableFragment.kt
@@ -1,28 +1,25 @@
package `in`.koreatech.koin.ui.bus.fragment
+import android.os.Bundle
+import android.view.View
+import android.widget.ArrayAdapter
+import androidx.core.view.isVisible
+import androidx.fragment.app.viewModels
+import androidx.recyclerview.widget.LinearLayoutManager
+import dagger.hilt.android.AndroidEntryPoint
import `in`.koreatech.koin.R
+import `in`.koreatech.koin.core.analytics.EventLogger
+import `in`.koreatech.koin.core.constant.AnalyticsConstant
import `in`.koreatech.koin.core.fragment.DataBindingFragment
import `in`.koreatech.koin.core.progressdialog.IProgressDialog
import `in`.koreatech.koin.databinding.LayoutExpressBusTimetableBinding
-import `in`.koreatech.koin.databinding.LayoutShuttleBusTimetableBinding
import `in`.koreatech.koin.ui.bus.adpater.timetable.ExpressBusTimetableAdapter
-import `in`.koreatech.koin.ui.bus.adpater.timetable.ShuttleBusTimetableAdapter
import `in`.koreatech.koin.ui.bus.state.toExpressBusTimetableUiItem
-import `in`.koreatech.koin.ui.bus.state.toShuttleBusTimetableUiItem
import `in`.koreatech.koin.ui.bus.viewmodel.ExpressBusTimetableViewModel
-import `in`.koreatech.koin.ui.bus.viewmodel.ShuttleBusTimetableViewModel
-import `in`.koreatech.koin.util.SnackbarUtil
import `in`.koreatech.koin.util.ext.observeLiveData
import `in`.koreatech.koin.util.ext.setOnItemSelectedListener
import `in`.koreatech.koin.util.ext.withLoading
import `in`.koreatech.koin.util.ext.withToastError
-import android.os.Bundle
-import android.view.View
-import android.widget.ArrayAdapter
-import androidx.core.view.isVisible
-import androidx.fragment.app.viewModels
-import androidx.recyclerview.widget.LinearLayoutManager
-import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class ExpressBusTimetableFragment : DataBindingFragment() {
@@ -30,6 +27,7 @@ class ExpressBusTimetableFragment : DataBindingFragment()
private val expressBusTimetableAdapter = ExpressBusTimetableAdapter()
+ private var isInitialization = true
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -47,6 +45,15 @@ class ExpressBusTimetableFragment : DataBindingFragment
expressBusTimetableViewModel.setCoursePosition(position)
+ if (isInitialization) {
+ isInitialization = false
+ return@setOnItemSelectedListener
+ }
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.CAMPUS,
+ AnalyticsConstant.Label.BUS_TIMETABLE_EXPRESS,
+ busTimetableCoursesSpinner.selectedItem.toString()
+ )
}
}
@@ -56,7 +63,7 @@ class ExpressBusTimetableFragment : DataBindingFragment
- if(courses.isNullOrEmpty()) {
+ if (courses.isNullOrEmpty()) {
binding.busTimetableCoursesSpinner.isVisible = false
} else {
binding.busTimetableCoursesSpinner.isVisible = true
diff --git a/koin/src/main/java/in/koreatech/koin/ui/bus/fragment/ShuttleBusTimetableFragment.kt b/koin/src/main/java/in/koreatech/koin/ui/bus/fragment/ShuttleBusTimetableFragment.kt
index b88eda563..d1757558c 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/bus/fragment/ShuttleBusTimetableFragment.kt
+++ b/koin/src/main/java/in/koreatech/koin/ui/bus/fragment/ShuttleBusTimetableFragment.kt
@@ -8,6 +8,8 @@ import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.LinearLayoutManager
import dagger.hilt.android.AndroidEntryPoint
import `in`.koreatech.koin.R
+import `in`.koreatech.koin.core.analytics.EventLogger
+import `in`.koreatech.koin.core.constant.AnalyticsConstant
import `in`.koreatech.koin.core.fragment.DataBindingFragment
import `in`.koreatech.koin.core.progressdialog.IProgressDialog
import `in`.koreatech.koin.databinding.LayoutShuttleBusTimetableBinding
@@ -25,6 +27,8 @@ class ShuttleBusTimetableFragment : DataBindingFragment()
private val shuttleBusTimetableAdapter = ShuttleBusTimetableAdapter()
+ private var isCourseInitialization = true
+ private var isRouteInitialization = true
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -42,10 +46,28 @@ class ShuttleBusTimetableFragment : DataBindingFragment
shuttleBusTimetableViewModel.setCoursePosition(position)
+ if (isCourseInitialization) {
+ isCourseInitialization = false
+ return@setOnItemSelectedListener
+ }
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.CAMPUS,
+ AnalyticsConstant.Label.BUS_TIMETABLE_AREA,
+ busTimetableCoursesSpinner.selectedItem.toString()
+ )
}
busTimetableRoutesSpinner.setOnItemSelectedListener { _, _, position, _ ->
shuttleBusTimetableViewModel.setRoutePosition(position)
+ if (isRouteInitialization) {
+ isRouteInitialization = false
+ return@setOnItemSelectedListener
+ }
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.CAMPUS,
+ AnalyticsConstant.Label.BUS_TIMETABLE_TIME,
+ busTimetableRoutesSpinner.selectedItem.toString()
+ )
}
}
@@ -55,7 +77,7 @@ class ShuttleBusTimetableFragment : DataBindingFragment
- if(courses.isNullOrEmpty()) {
+ if (courses.isNullOrEmpty()) {
binding.busTimetableCoursesSpinner.isVisible = false
} else {
binding.busTimetableCoursesSpinner.isVisible = true
@@ -81,7 +103,7 @@ class ShuttleBusTimetableFragment : DataBindingFragment(BusNode.Koreatech)
private val _arrival = MutableLiveData(BusNode.Terminal)
+ var isUserSelection = false
val departure: LiveData get() = _departure
val arrival: LiveData get() = _arrival
diff --git a/koin/src/main/java/in/koreatech/koin/ui/dining/DiningActivity.kt b/koin/src/main/java/in/koreatech/koin/ui/dining/DiningActivity.kt
index 555128f34..23b884bb5 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/dining/DiningActivity.kt
+++ b/koin/src/main/java/in/koreatech/koin/ui/dining/DiningActivity.kt
@@ -6,10 +6,13 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.tabs.TabLayoutMediator
import dagger.hilt.android.AndroidEntryPoint
import `in`.koreatech.koin.R
+import `in`.koreatech.koin.core.analytics.EventLogger
import `in`.koreatech.koin.core.appbar.AppBarBase
+import `in`.koreatech.koin.core.constant.AnalyticsConstant
import `in`.koreatech.koin.core.util.dataBinding
import `in`.koreatech.koin.databinding.ActivityDiningBinding
import `in`.koreatech.koin.domain.model.dining.DiningType
@@ -35,11 +38,14 @@ class DiningActivity : KoinNavigationDrawerActivity() {
private val diningDateAdapter by lazy { DiningDateAdapter {
viewModel.setSelectedDate(it)
} }
+ private lateinit var diningViewPagerScrollCallback: ViewPager2.OnPageChangeCallback
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
+ initDiningViewPagerScrollCallback()
initCalendar()
initViewPager()
@@ -67,6 +73,7 @@ class DiningActivity : KoinNavigationDrawerActivity() {
diningViewPager.apply {
offscreenPageLimit = 3
adapter = DiningItemsViewPager2Adapter(this@DiningActivity)
+ registerOnPageChangeCallback(diningViewPagerScrollCallback)
}
TabLayoutMediator(tabsDiningTime, diningViewPager) { tab, position ->
tab.text = when (position) {
@@ -85,6 +92,17 @@ class DiningActivity : KoinNavigationDrawerActivity() {
diningDateAdapter.setSelectedPosition(dates.size / 2 + 1)
}
}
+ // 스크롤이 아닌 탭 선택 이벤트만 받기 위한 구현
+ repeat(binding.tabsDiningTime.tabCount) {
+ val tab = binding.tabsDiningTime.getTabAt(it)
+ tab?.view?.setOnClickListener {
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.CAMPUS,
+ AnalyticsConstant.Label.MENU_TIME,
+ tab.text.toString()
+ )
+ }
+ }
}
}
@@ -116,4 +134,30 @@ class DiningActivity : KoinNavigationDrawerActivity() {
layoutManager?.scrollToPositionWithOffset(todayPosition, offset)
}
}
+
+ private fun initDiningViewPagerScrollCallback() {
+ // 탭 선택이 아닌 스크롤 이벤트만 받기 위한 구현
+ diningViewPagerScrollCallback = object : ViewPager2.OnPageChangeCallback() {
+ var isUserScrolling = false
+ override fun onPageScrollStateChanged(state: Int) {
+ super.onPageScrollStateChanged(state)
+ if(state == ViewPager2.SCROLL_STATE_DRAGGING){
+ isUserScrolling = true
+ } else if(state == ViewPager2.SCROLL_STATE_IDLE){
+ if(isUserScrolling){
+ EventLogger.logScrollEvent(
+ AnalyticsConstant.Domain.CAMPUS,
+ AnalyticsConstant.Label.MENU_TIME,
+ binding.tabsDiningTime.getTabAt(binding.tabsDiningTime.selectedTabPosition)?.text.toString()
+ )
+ }
+ isUserScrolling = false
+ }
+ }
+ }
+ }
+ override fun onDestroy() {
+ super.onDestroy()
+ binding.diningViewPager.unregisterOnPageChangeCallback(diningViewPagerScrollCallback)
+ }
}
\ No newline at end of file
diff --git a/koin/src/main/java/in/koreatech/koin/ui/dining/adapter/DiningAdapter.kt b/koin/src/main/java/in/koreatech/koin/ui/dining/adapter/DiningAdapter.kt
index 3d56b696a..02713b93b 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/dining/adapter/DiningAdapter.kt
+++ b/koin/src/main/java/in/koreatech/koin/ui/dining/adapter/DiningAdapter.kt
@@ -13,8 +13,11 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import `in`.koreatech.koin.R
+import `in`.koreatech.koin.core.analytics.EventLogger
+import `in`.koreatech.koin.core.constant.AnalyticsConstant
import `in`.koreatech.koin.databinding.ItemDiningBinding
import `in`.koreatech.koin.domain.model.dining.Dining
+import `in`.koreatech.koin.domain.util.DiningUtil
class DiningAdapter : ListAdapter(diffCallback) {
@@ -85,6 +88,19 @@ class DiningAdapter : ListAdapter(diffCallback)
.load(dining.imageUrl)
.into(imageView)
dialog.show()
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.CAMPUS,
+ AnalyticsConstant.Label.MENU_IMAGE,
+ DiningUtil.getKoreanName(dining.type) + "_" + dining.place
+ )
+ }
+ } else {
+ cardViewDining.setOnClickListener {
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.CAMPUS,
+ AnalyticsConstant.Label.MENU_IMAGE,
+ DiningUtil.getKoreanName(dining.type) + "_" + dining.place
+ )
}
}
diff --git a/koin/src/main/java/in/koreatech/koin/ui/login/LoginActivity.kt b/koin/src/main/java/in/koreatech/koin/ui/login/LoginActivity.kt
index 912fb3a42..4d51877ab 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/login/LoginActivity.kt
+++ b/koin/src/main/java/in/koreatech/koin/ui/login/LoginActivity.kt
@@ -2,17 +2,17 @@ package `in`.koreatech.koin.ui.login
import android.content.Intent
import android.os.Bundle
-import android.util.Log
import android.view.MotionEvent
import androidx.activity.viewModels
import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import dagger.hilt.android.AndroidEntryPoint
import `in`.koreatech.koin.R
import `in`.koreatech.koin.common.UiStatus
import `in`.koreatech.koin.core.activity.ActivityBase
+import `in`.koreatech.koin.core.analytics.EventLogger
+import `in`.koreatech.koin.core.constant.AnalyticsConstant
import `in`.koreatech.koin.core.util.dataBinding
import `in`.koreatech.koin.databinding.ActivityLoginBinding
import `in`.koreatech.koin.ui.businesslogin.BusinessLoginActivity
@@ -24,8 +24,6 @@ import `in`.koreatech.koin.util.SnackbarUtil
import `in`.koreatech.koin.util.ext.hideKeyboard
import `in`.koreatech.koin.util.ext.textString
import `in`.koreatech.koin.util.ext.withLoading
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
@AndroidEntryPoint
@@ -95,10 +93,20 @@ class LoginActivity : ActivityBase(R.layout.activity_login) {
password = loginEdittextPw.text.toString().trim()
)
}
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.USER,
+ AnalyticsConstant.Label.LOGIN,
+ getString(R.string.login)
+ )
}
loginButtonSignup.setOnClickListener {
startActivity(Intent(this@LoginActivity, SignupActivity::class.java))
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.USER,
+ AnalyticsConstant.Label.START_SIGN_UP,
+ getString(R.string.sign_up)
+ )
}
forgotPasswordLinearLayout.setOnClickListener {
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 1650c7086..bb21637aa 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
@@ -2,19 +2,24 @@ package `in`.koreatech.koin.ui.main.activity
import android.os.Bundle
import android.view.View
+import android.widget.TextView
import androidx.activity.viewModels
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
+import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import dagger.hilt.android.AndroidEntryPoint
import `in`.koreatech.koin.R
+import `in`.koreatech.koin.core.analytics.EventLogger
+import `in`.koreatech.koin.core.constant.AnalyticsConstant
import `in`.koreatech.koin.core.recyclerview.RecyclerViewClickListener
import `in`.koreatech.koin.core.util.dataBinding
import `in`.koreatech.koin.core.viewpager.HorizontalMarginItemDecoration
-import `in`.koreatech.koin.core.viewpager.ScaledViewPager2Transformation
+import `in`.koreatech.koin.data.util.localized
import `in`.koreatech.koin.data.util.todayOrTomorrow
import `in`.koreatech.koin.databinding.ActivityMainBinding
+import `in`.koreatech.koin.domain.model.bus.timer.BusArrivalInfo
import `in`.koreatech.koin.domain.model.dining.DiningPlace
import `in`.koreatech.koin.ui.main.StoreCategoryRecyclerAdapter
import `in`.koreatech.koin.ui.main.adapter.BusPagerAdapter
@@ -33,15 +38,36 @@ class MainActivity : KoinNavigationDrawerActivity() {
private val viewModel by viewModels()
private val busPagerAdapter = BusPagerAdapter().apply {
- setOnCardClickListener { callDrawerItem(R.id.navi_item_bus, Bundle()) }
- setOnSwitchClickListener { viewModel.switchBusNode() }
+ setOnCardClickListener {
+ callDrawerItem(R.id.navi_item_bus, Bundle())
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.CAMPUS,
+ AnalyticsConstant.Label.MAIN_BUS,
+ getString(R.string.bus)
+ )
+ }
+ setOnSwitchClickListener {
+ viewModel.switchBusNode()
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.CAMPUS,
+ AnalyticsConstant.Label.MAIN_BUS_CHANGETOFROM,
+ it.localized(this@MainActivity)
+ )
+ }
}
+ private lateinit var busViewPagerScrollCallback: ViewPager2.OnPageChangeCallback
+
private val diningContainerAdapter by lazy { DiningContainerViewPager2Adapter(this) }
private val storeCategoryRecyclerAdapter = StoreCategoryRecyclerAdapter().apply {
setRecyclerViewClickListener(object : RecyclerViewClickListener {
override fun onClick(view: View?, position: Int) {
gotoStoreActivity(position)
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.BUSINESS,
+ AnalyticsConstant.Label.MAIN_SHOP_CATEGORIES,
+ view?.findViewById(R.id.text_view_store_category)?.text.toString()
+ )
}
override fun onLongClick(view: View?, position: Int) {
@@ -66,6 +92,11 @@ class MainActivity : KoinNavigationDrawerActivity() {
private fun initView() = with(binding) {
buttonCategory.setOnClickListener {
toggleNavigationDrawer()
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.USER,
+ AnalyticsConstant.Label.HAMBURGER,
+ getString(R.string.hamburger)
+ )
}
busViewPager.apply {
@@ -107,6 +138,10 @@ class MainActivity : KoinNavigationDrawerActivity() {
tabDining.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab) {
viewModel.setSelectedPosition(tab.position)
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.CAMPUS,
+ AnalyticsConstant.Label.MAIN_MENU_CORNER,
+ tab.text.toString())
}
override fun onTabUnselected(tab: TabLayout.Tab) {}
@@ -126,12 +161,35 @@ class MainActivity : KoinNavigationDrawerActivity() {
observeLiveData(busTimer) {
busPagerAdapter.setBusTimerItems(it)
+ if (this@MainActivity::busViewPagerScrollCallback.isInitialized.not()) {
+ initBusViewPagerScrollCallback(it)
+ }
}
}
+ private fun initBusViewPagerScrollCallback(busArrivalInfos: List) {
+ busViewPagerScrollCallback = object : ViewPager2.OnPageChangeCallback() {
+ var prev = 0
+ override fun onPageSelected(position: Int) {
+ super.onPageSelected(position)
+ EventLogger.logScrollEvent(
+ AnalyticsConstant.Domain.CAMPUS,
+ AnalyticsConstant.Label.MAIN_BUS_SCROLL,
+ busArrivalInfos[prev % 3].localized(this@MainActivity) + ">" + busArrivalInfos[position % 3].localized(this@MainActivity)
+ )
+ prev = position
+ }
+ }.also { binding.busViewPager.registerOnPageChangeCallback(it) }
+ }
+
private fun gotoStoreActivity(position: Int) {
val bundle = Bundle()
bundle.putInt(StoreActivityContract.STORE_CATEGORY, position)
callDrawerItem(R.id.navi_item_store, bundle)
}
+
+ override fun onDestroy() {
+ super.onDestroy()
+ binding.busViewPager.unregisterOnPageChangeCallback(busViewPagerScrollCallback)
+ }
}
diff --git a/koin/src/main/java/in/koreatech/koin/ui/main/adapter/BusPagerAdapter.kt b/koin/src/main/java/in/koreatech/koin/ui/main/adapter/BusPagerAdapter.kt
index 65f7624cd..2f5df7004 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/main/adapter/BusPagerAdapter.kt
+++ b/koin/src/main/java/in/koreatech/koin/ui/main/adapter/BusPagerAdapter.kt
@@ -30,7 +30,7 @@ class BusPagerAdapter : RecyclerView.Adapter Unit) {
+ inline fun setOnSwitchClickListener(crossinline onSwitchClick: (BusArrivalInfo) -> Unit) {
onSwitchClickListener = object : OnSwitchClickListener {
- override fun onSwitchClick() {
- onSwitchClick()
+ override fun onSwitchClick(busArrivalInfo: BusArrivalInfo) {
+ onSwitchClick(busArrivalInfo)
}
}
}
@@ -111,7 +111,7 @@ class BusPagerAdapter : RecyclerView.Adapter {
koinNavigationDrawerViewModel.selectMenu(state)
+ when (state) {
+ MenuState.Store -> {
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.BUSINESS,
+ AnalyticsConstant.Label.HAMBURGER_SHOP,
+ getString(R.string.nearby_stores)
+ )
+ }
+
+ MenuState.Bus -> {
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.CAMPUS,
+ AnalyticsConstant.Label.HAMBURGER_BUS,
+ getString(R.string.bus)
+ )
+ }
+
+ MenuState.Dining -> {
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.CAMPUS,
+ AnalyticsConstant.Label.HAMBURGER_DINING,
+ getString(R.string.navigation_item_dining)
+ )
+ }
+
+ MenuState.UserInfo -> {
+ if (koinNavigationDrawerViewModel.userState.value == null || koinNavigationDrawerViewModel.userState.value?.isAnonymous == true) {
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.USER,
+ AnalyticsConstant.Label.HAMBURGER_MY_INFO_WITHOUT_LOGIN,
+ getString(R.string.navigation_drawer_right_myinfo)
+ )
+ showLoginRequestDialog()
+ } else {
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.USER,
+ AnalyticsConstant.Label.HAMBURGER_MY_INFO_WITH_LOGIN,
+ getString(R.string.navigation_drawer_right_myinfo)
+ )
+ goToUserInfoActivity()
+ }
+ }
+
+ else -> Unit
+ }
}
}
}
@@ -379,6 +426,11 @@ abstract class KoinNavigationDrawerActivity : ActivityBase(),
)
intent.putExtra("FIRST_LOGIN", false)
startActivity(intent)
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.USER,
+ AnalyticsConstant.Label.USER_ONLY_OK,
+ getString(R.string.user_only_ok)
+ )
overridePendingTransition(android.R.anim.slide_in_left, android.R.anim.fade_out)
}
.setNegativeButton(getString(R.string.navigation_cancel)) { dialog, _ ->
diff --git a/koin/src/main/java/in/koreatech/koin/ui/signup/SignUpWithDetailInfoActivity.kt b/koin/src/main/java/in/koreatech/koin/ui/signup/SignUpWithDetailInfoActivity.kt
index e4391b0cc..87bb5509a 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/signup/SignUpWithDetailInfoActivity.kt
+++ b/koin/src/main/java/in/koreatech/koin/ui/signup/SignUpWithDetailInfoActivity.kt
@@ -11,6 +11,8 @@ import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
import `in`.koreatech.koin.R
import `in`.koreatech.koin.core.activity.ActivityBase
+import `in`.koreatech.koin.core.analytics.EventLogger
+import `in`.koreatech.koin.core.constant.AnalyticsConstant
import `in`.koreatech.koin.databinding.ActivitySignUpWithDetailInfoBinding
import `in`.koreatech.koin.domain.error.signup.SignupAlreadySentEmailException
import `in`.koreatech.koin.domain.model.user.Gender
@@ -93,6 +95,11 @@ class SignupWithDetailInfoActivity : ActivityBase() {
studentNumber = signupUserEdittextStudentId.text.toString(),
isCheckNickname = signupViewModel.isCheckedNickname
)
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.USER,
+ AnalyticsConstant.Label.COMPLETE_SIGN_UP,
+ getString(R.string.complete_sign_up)
+ )
}
}
}
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 832669f91..c10f847b2 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,7 +1,7 @@
package `in`.koreatech.koin.ui.store.activity
import android.os.Bundle
-import android.util.Log
+import android.view.MotionEvent
import android.view.View
import android.widget.TextView
import androidx.activity.viewModels
@@ -14,7 +14,9 @@ import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.LinearLayoutManager
import dagger.hilt.android.AndroidEntryPoint
import `in`.koreatech.koin.R
+import `in`.koreatech.koin.core.analytics.EventLogger
import `in`.koreatech.koin.core.appbar.AppBarBase
+import `in`.koreatech.koin.core.constant.AnalyticsConstant
import `in`.koreatech.koin.core.util.dataBinding
import `in`.koreatech.koin.databinding.StoreActivityMainBinding
import `in`.koreatech.koin.domain.model.store.StoreCategory
@@ -46,6 +48,11 @@ class StoreActivity : KoinNavigationDrawerActivity() {
private val storeAdapter = StoreRecyclerAdapter().apply {
setOnItemClickListener {
storeDetailContract.launch(it.uid)
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.BUSINESS,
+ AnalyticsConstant.Label.SHOP_CLICK,
+ it.name
+ )
}
}
@@ -57,29 +64,29 @@ class StoreActivity : KoinNavigationDrawerActivity() {
field = value
}
- private var showRemoveQueryButton : Boolean = false
- set(value) {
- if (!value) {
- binding.searchImageView.background = ContextCompat.getDrawable(
- this,
- R.drawable.ic_search
- )
- binding.searchImageView.layoutParams.apply {
- width = dpToPx(24)
- height = dpToPx(24)
- }
- } else {
- binding.searchImageView.background = ContextCompat.getDrawable(
- this,
- R.drawable.ic_search_close
- )
- binding.searchImageView.layoutParams.apply {
- width = dpToPx(16)
- height = dpToPx(16)
+ private var showRemoveQueryButton: Boolean = false
+ set(value) {
+ if (!value) {
+ binding.searchImageView.background = ContextCompat.getDrawable(
+ this,
+ R.drawable.ic_search
+ )
+ binding.searchImageView.layoutParams.apply {
+ width = dpToPx(24)
+ height = dpToPx(24)
+ }
+ } else {
+ binding.searchImageView.background = ContextCompat.getDrawable(
+ this,
+ R.drawable.ic_search_close
+ )
+ binding.searchImageView.layoutParams.apply {
+ width = dpToPx(16)
+ height = dpToPx(16)
+ }
}
+ field = value
}
- field = value
- }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -101,6 +108,18 @@ class StoreActivity : KoinNavigationDrawerActivity() {
isSearchMode = hasFocus
}
+ binding.searchEditText.setOnTouchListener { v, event ->
+ if (event.action == MotionEvent.ACTION_DOWN) {
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.BUSINESS,
+ AnalyticsConstant.Label.SHOP_CATEGORIES_SEARCH,
+ "search in " + getStoreCategoryName(viewModel.category.value)
+ )
+ }
+ v.performClick()
+ }
+
+
binding.storeRecyclerview.apply {
layoutManager = LinearLayoutManager(this@StoreActivity)
adapter = storeAdapter
@@ -111,7 +130,7 @@ class StoreActivity : KoinNavigationDrawerActivity() {
}
binding.searchImageView.setOnClickListener {
- if(showRemoveQueryButton) binding.searchEditText.setText("")
+ if (showRemoveQueryButton) binding.searchEditText.setText("")
}
handleCategoryClickEvent()
@@ -195,10 +214,33 @@ class StoreActivity : KoinNavigationDrawerActivity() {
binding.storeCategoryEtcTextview.setCategorySelected(category == StoreCategory.Etc)
}
+ private fun getStoreCategoryName(category: StoreCategory?): String {
+ return when (category) {
+ StoreCategory.Chicken -> getString(R.string.chicken)
+ StoreCategory.Pizza -> getString(R.string.pizza)
+ StoreCategory.DOSIRAK -> getString(R.string.dorisak)
+ StoreCategory.PorkFeet -> getString(R.string.pork_feet)
+ StoreCategory.Chinese -> getString(R.string.chinese)
+ StoreCategory.NormalFood -> getString(R.string.normal_food)
+ StoreCategory.Cafe -> getString(R.string.cafe)
+ StoreCategory.BeautySalon -> getString(R.string.beauty_salon)
+ StoreCategory.Etc -> getString(R.string.etc)
+ StoreCategory.All, null -> getString(R.string.see_all)
+ }
+ }
+
private fun View.setCategoryOnClick(category: StoreCategory) {
setOnClickListener {
binding.searchEditText.clearFocus()
viewModel.setCategory(category)
+
+ val eventValue = getStoreCategoryName(viewModel.category.value)
+
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.BUSINESS,
+ AnalyticsConstant.Label.SHOP_CATEGORIES,
+ eventValue
+ )
}
}
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 785386cb9..652e08cbd 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
@@ -8,6 +8,8 @@ import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
import `in`.koreatech.koin.R
+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.util.dataBinding
import `in`.koreatech.koin.databinding.StoreActivityDetailBinding
@@ -84,6 +86,10 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() {
flyerDialogFragment = StoreFlyerDialogFragment()
flyerDialogFragment?.initialPosition = position
flyerDialogFragment?.show(supportFragmentManager, DIALOG_TAG)
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.BUSINESS,
+ AnalyticsConstant.Label.SHOP_PICTURE,
+ viewModel.store.value?.name ?: "Unknown")
}
}
@@ -120,6 +126,10 @@ class StoreDetailActivity : KoinNavigationDrawerActivity() {
binding.storeDetailCallButton.setOnClickListener {
showCallDialog()
+ EventLogger.logClickEvent(
+ AnalyticsConstant.Domain.BUSINESS,
+ AnalyticsConstant.Label.SHOP_CALL,
+ viewModel.store.value?.name ?: "Unknown")
}
binding.menuSpreadTextView.setOnClickListener {
diff --git a/koin/src/main/res/layout/activity_login.xml b/koin/src/main/res/layout/activity_login.xml
index cde0243ad..44b311600 100644
--- a/koin/src/main/res/layout/activity_login.xml
+++ b/koin/src/main/res/layout/activity_login.xml
@@ -265,7 +265,7 @@
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@color/colorPrimary"
- android:text="회원가입"
+ android:text="@string/sign_up"
android:textColor="@color/white"
android:textSize="15sp"
app:fontName="Normal"
diff --git a/koin/src/main/res/values/strings.xml b/koin/src/main/res/values/strings.xml
index 3239f24c4..181e402e5 100644
--- a/koin/src/main/res/values/strings.xml
+++ b/koin/src/main/res/values/strings.xml
@@ -1,7 +1,8 @@
코인\n커뮤니티
- 회원 가입
+ 회원가입
+ 로그인
홈
@@ -371,4 +372,18 @@
품절
변경됨
%1$s원
+ 치킨
+ 피자
+ 도시락
+ 족발
+ 중국집
+ 일반음식
+ 카페
+ 미용실
+ 기타
+ 주변상점
+ 회원전용 확인
+ 버스
+ 전체보기
+ 회원가입 완료