Skip to content

Commit

Permalink
[FEATURE] 메인화면 ViewPager 제거 (#89)
Browse files Browse the repository at this point in the history
* [FEAT] #84 - 홈화면에서 검색 화면 이동 로직 추가

* [FEAT] #84 - 공통 상품 검색 viewModel 추가

* [FEAT] #84 - 홈 화면에서 탐색 화면 이동 로직 완료

* [FEAT] #84 - 필터링 초기화

* [FEAT] #84 - viewpager를 fragment 전환으로 변경

* [FEAT] #84 - 탐색 화면 fragment 유지

* [FEAT] #84 - 각 fragment 재사용
  • Loading branch information
aurora32s authored Jul 24, 2023
1 parent 57b31de commit 02b32ee
Show file tree
Hide file tree
Showing 24 changed files with 237 additions and 55 deletions.
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ dependencies {
implementation(project(":feature:review"))
implementation(project(":feature:explore"))
implementation(project(":feature:evaluate"))
implementation(project(":core:model"))

implementation(project(":core:data"))

Expand Down
9 changes: 8 additions & 1 deletion app/src/main/java/com/peonlee/PeonLeeNavigator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import android.content.Intent
import androidx.activity.result.ActivityResultLauncher
import com.peonlee.core.ui.Navigator
import com.peonlee.explore.ExploreActivity
import com.peonlee.explore.ExploreFragment
import com.peonlee.feature.detail.ProductCommentsActivity
import com.peonlee.feature.detail.ProductDetailActivity
import com.peonlee.feature.detail.ProductExtra
import com.peonlee.model.product.ProductSearchConditionUiModel
import com.peonlee.review.edit.EditReviewActivity
import javax.inject.Inject
import javax.inject.Singleton
Expand All @@ -34,7 +36,12 @@ class PeonLeeNavigator @Inject constructor() : Navigator {
launcher.launch(EditReviewActivity.newIntent(context, productId, imageUrl, productName, price, content))
}

override fun navigateToExplore(context: Context) {
override fun navigateToSearch(context: Context) {
ExploreActivity.startActivity(context)
}

override fun navigateToExplore(
productSearchConditionUiModel: ProductSearchConditionUiModel?
) {
}
}
2 changes: 2 additions & 0 deletions core/model/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ android {
dependencies {
implementation(project(":core:data"))
implementation(project(":core:common"))

implementation(libs.serialization.json)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import com.peonlee.model.type.EventType
import com.peonlee.model.type.PriceFilter
import com.peonlee.model.type.SortType
import com.peonlee.model.type.StoreType
import kotlinx.serialization.Serializable

@Serializable
data class ProductSearchConditionUiModel(
val keyword: String = "", // 키워드
val sortedBy: SortType = SortType.RECENT, // 정렬 기준
val price: PriceFilter? = null, // 가격 조건
val stores: List<StoreType>? = null, // 상점 조건
val events: List<EventType>? = null, // 행사 조건
val categories: List<Category>? = null // 카테고리 조건
)
): java.io.Serializable
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ enum class SortType(
RECENT("신상품", "최신순", "RECENT"),
POPULAR("인기상품", "인기순", "POPULAR"),
LIKE("", "평가 많은순", "LIKE"),
COMMENT("", "리뷰 많은순", "COMMENT")
COMMENT("", "리뷰 많은순", "COMMENT");
}
9 changes: 8 additions & 1 deletion core/ui/src/main/java/com/peonlee/core/ui/Navigator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.peonlee.core.ui
import android.content.Context
import android.content.Intent
import androidx.activity.result.ActivityResultLauncher
import com.peonlee.model.product.ProductSearchConditionUiModel

interface Navigator {
fun navigateToProductDetail(context: Context, productId: Int)
Expand All @@ -21,5 +22,11 @@ interface Navigator {
/**
* 검색 화면으로 이동
*/
fun navigateToExplore(context: Context)
fun navigateToSearch(context: Context)

/**
* 탐색 화면으로 이동
* @param productSearchConditionUiModel 기본 탐색 조건
*/
fun navigateToExplore(productSearchConditionUiModel: ProductSearchConditionUiModel?)
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ abstract class BaseFragment<T : ViewBinding> : Fragment() {
abstract fun bindingFactory(parent: ViewGroup?): T
open fun initViews() {}

override fun onDestroy() {
super.onDestroy()
override fun onDestroyView() {
_binding = null
super.onDestroyView()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.peonlee.core.ui.base

import androidx.lifecycle.ViewModel
import com.peonlee.model.product.ProductSearchConditionUiModel
import com.peonlee.model.type.SortType
import com.peonlee.model.type.StoreType
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow

/**
* 상품을 검색할 수 있는 viewModel
*/
open class ProductSearchableViewModel : ViewModel() {
protected val _productSearchCondition = MutableStateFlow(ProductSearchConditionUiModel())
val productSearchCondition: StateFlow<ProductSearchConditionUiModel> = _productSearchCondition.asStateFlow()

protected fun setProductSearchCondition(
newProductSearchCondition: ProductSearchConditionUiModel
) {
_productSearchCondition.value = newProductSearchCondition
}

/**
* 정렬 키워드 변경
*/
open fun changeSortType(sortType: SortType) {}

/**
* 편의점의 행사 상품 변경
*/
open fun changeStoreType(storeType: StoreType) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.activity.viewModels
import androidx.core.view.isVisible
import androidx.core.widget.addTextChangedListener
import com.peonlee.core.ui.base.BaseActivity
import com.peonlee.core.ui.base.ProductSearchableViewModel
import com.peonlee.core.ui.extensions.hideKeyboard
import com.peonlee.core.ui.extensions.trim
import com.peonlee.explore.databinding.ActivityExploreActivityBinding
Expand All @@ -14,18 +15,19 @@ import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class ExploreActivity : BaseActivity<ActivityExploreActivityBinding>() {
private val exploreViewModel: ExploreViewModel by viewModels()
private val exploreViewModel: ProductSearchableViewModel by viewModels { ExploreViewModel.ExploreViewModelFactory() }

override fun bindingFactory(): ActivityExploreActivityBinding = ActivityExploreActivityBinding.inflate(layoutInflater)

override fun initViews() = with(binding) {
println(exploreViewModel)
attachProductFragment()
etExploreBar.addTextChangedListener { input -> ivTextCleaer.isVisible = input?.isNotEmpty() ?: false }
tvExploreCancel.setOnClickListener { finish() }
ivTextCleaer.setOnClickListener { etExploreBar.setText("") }
ivSearch.setOnClickListener {
layoutSearchProduct.isVisible = true
exploreViewModel.setKeyword(etExploreBar.trim())
(exploreViewModel as? ExploreViewModel)?.setKeyword(etExploreBar.trim())
etExploreBar.hideKeyboard()
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.peonlee.explore

import android.os.Bundle
import android.view.ViewGroup
import androidx.fragment.app.commit
import com.peonlee.core.ui.Navigator
import com.peonlee.core.ui.base.BaseFragment
import com.peonlee.explore.databinding.FragmentExploreBinding
import com.peonlee.model.product.ProductSearchConditionUiModel
import com.peonlee.product.ProductFragment
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
Expand All @@ -19,16 +21,25 @@ class ExploreFragment : BaseFragment<FragmentExploreBinding>() {
}

override fun initViews() {
childFragmentManager.commit {
add(R.id.layoutProduct, ProductFragment.getInstance(), "Product")
}
// 상단 검색 바 클릭 시, 검색 화면으로 이동
binding.layoutSearch.setOnClickListener {
navigator.navigateToExplore(requireContext())
navigator.navigateToSearch(requireContext())
}
}

companion object {
const val SEARCH_CONDITION = "productSearchCondition"

fun getInstance(): ExploreFragment = ExploreFragment()
fun getInstance(
productSearchConditionUiModel: ProductSearchConditionUiModel
): ExploreFragment {
val bundle = Bundle()
bundle.putSerializable(SEARCH_CONDITION, productSearchConditionUiModel)

val exploreFragment = ExploreFragment()
exploreFragment.arguments = bundle
return exploreFragment
}
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
package com.peonlee.explore

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.peonlee.core.ui.base.ProductSearchableViewModel
import com.peonlee.model.product.ProductSearchConditionUiModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import javax.inject.Inject

@HiltViewModel
class ExploreViewModel @Inject constructor() : ViewModel() {
private val _keyword: MutableStateFlow<String> = MutableStateFlow("")
val keyword = _keyword.asStateFlow()

class ExploreViewModel @Inject constructor() : ProductSearchableViewModel() {
fun setKeyword(newKeyword: String) {
_keyword.value = newKeyword
super.setProductSearchCondition(
_productSearchCondition.value.copy(keyword = newKeyword)
)
}

class ExploreViewModelFactory() : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(ExploreViewModel::class.java)) {
return ExploreViewModel() as T
}
throw IllegalArgumentException("unKnown ViewModel class")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import com.peonlee.core.ui.Navigator
import com.peonlee.core.ui.adapter.decoration.ContentPaddingDecoration
import com.peonlee.core.ui.base.BaseBottomSheetFragment
import com.peonlee.core.ui.base.BaseFragment
import com.peonlee.explore.ExploreViewModel
import com.peonlee.core.ui.base.ProductSearchableViewModel
import com.peonlee.model.product.ProductSearchConditionUiModel
import com.peonlee.model.type.SortType
import com.peonlee.model.type.toRangeString
Expand All @@ -41,7 +41,7 @@ class ProductFragment : BaseFragment<FragmentProductBinding>() {
@Inject
lateinit var navigator: Navigator

private val exploreViewModel: ExploreViewModel by activityViewModels()
private val exploreViewModel: ProductSearchableViewModel by activityViewModels()
private val productViewModel: ProductViewModel by viewModels()

private var currentBottomSheet: BaseBottomSheetFragment? = null
Expand Down Expand Up @@ -70,7 +70,7 @@ class ProductFragment : BaseFragment<FragmentProductBinding>() {
override fun initViews() = with(binding) {
observeKeyword()

com.peonlee.model.type.SortType.values().forEach {
SortType.values().forEach {
tabProductSort.addTab(
tabProductSort.newTab().apply { text = it.uiNameForExplore }
)
Expand Down Expand Up @@ -108,6 +108,7 @@ class ProductFragment : BaseFragment<FragmentProductBinding>() {
productViewModel.productSearchCondition.flowWithLifecycle(viewLifecycleOwner.lifecycle)
.onEach {
currentBottomSheet?.dismiss()
binding.tabProductSort.getTabAt(it.sortedBy.ordinal)?.select()
setFilterView(it)
}.launchIn(viewLifecycleOwner.lifecycleScope)

Expand Down Expand Up @@ -176,10 +177,11 @@ class ProductFragment : BaseFragment<FragmentProductBinding>() {
}

private fun observeKeyword() {
println(exploreViewModel)
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
exploreViewModel.keyword.collect { newKeyword ->
productViewModel.setKeyword(newKeyword)
exploreViewModel.productSearchCondition.collect {
productViewModel.setProductSearchCondition(it)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class ProductViewModel @Inject constructor(
)
}

fun setKeyword(newKeyword: String) {
_productSearchCondition.value = _productSearchCondition.value.copy(keyword = newKeyword)
fun setProductSearchCondition(newProductSearchCondition: ProductSearchConditionUiModel) {
_productSearchCondition.value = newProductSearchCondition
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
tools:context=".ExploreActivity">

<EditText
android:id="@+id/et_explore_bar"
android:id="@+id/et_explore_bar"
style="@style/Text.Subtitle02"
android:layout_width="0dp"
android:layout_height="@dimen/explore_bar_height"
Expand All @@ -16,14 +16,17 @@
android:background="@drawable/bg_white_radius_10dp"
android:backgroundTint="@color/bg10"
android:hint="@string/explore_text_hint"
android:imeOptions="actionDone"
android:inputType="text"
android:maxLines="1"
android:paddingLeft="@dimen/explore_text_left_padding"
android:textColorHint="@color/bg40"
app:layout_constraintEnd_toStartOf="@+id/tv_explore_cancel"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:hint="라면, 음료, 과자, 빵 등"
tools:text="우유"/>
tools:text="우유" />

<TextView
android:id="@+id/tv_explore_cancel"
Expand All @@ -36,7 +39,7 @@
android:textColor="@color/bg40"
app:layout_constraintBottom_toBottomOf="@+id/et_explore_bar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/et_explore_bar"/>
app:layout_constraintTop_toTopOf="@+id/et_explore_bar" />

<ImageView
android:id="@+id/iv_search"
Expand All @@ -59,7 +62,7 @@
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/et_explore_bar"
app:layout_constraintEnd_toEndOf="@+id/et_explore_bar"
app:layout_constraintTop_toTopOf="@+id/et_explore_bar"/>
app:layout_constraintTop_toTopOf="@+id/et_explore_bar" />

<FrameLayout
android:id="@+id/layout_search_product"
Expand All @@ -69,5 +72,5 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/et_explore_bar"/>
app:layout_constraintTop_toBottomOf="@+id/et_explore_bar" />
</androidx.constraintlayout.widget.ConstraintLayout>
1 change: 1 addition & 0 deletions feature/explore/src/main/res/layout/fragment_explore.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
android:id="@+id/layoutProduct"
android:layout_width="0dp"
android:layout_height="0dp"
android:name="com.peonlee.product.ProductFragment"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
Expand Down
Loading

0 comments on commit 02b32ee

Please sign in to comment.