Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into stage/sandbox
Browse files Browse the repository at this point in the history
  • Loading branch information
re4rk committed Feb 1, 2023
2 parents c98ddd5 + 8372877 commit dcb23c5
Show file tree
Hide file tree
Showing 30 changed files with 456 additions and 359 deletions.
13 changes: 13 additions & 0 deletions data/src/main/java/com/fakedevelopers/data/di/MainModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ package com.fakedevelopers.data.di

import android.content.Context
import com.fakedevelopers.data.repository.ImageRepositoryImpl
import com.fakedevelopers.data.repository.LocalStorageRepositoryImpl
import com.fakedevelopers.data.repository.ProductEditorRepositoryImpl
import com.fakedevelopers.data.repository.ProductListRepositoryImpl
import com.fakedevelopers.data.service.ProductEditorService
import com.fakedevelopers.data.service.ProductListService
import com.fakedevelopers.data.source.LocalStorageDataSource
import com.fakedevelopers.domain.repository.ImageRepository
import com.fakedevelopers.domain.repository.LocalStorageRepository
import com.fakedevelopers.domain.repository.ProductEditorRepository
import com.fakedevelopers.domain.repository.ProductListRepository
import dagger.Module
Expand Down Expand Up @@ -45,4 +48,14 @@ object MainModule {
@Provides
fun provideImageRepository(@ApplicationContext context: Context): ImageRepository =
ImageRepositoryImpl(context.contentResolver)

@Singleton
@Provides
fun provideLocalStorageRepository(localStorageDataSource: LocalStorageDataSource): LocalStorageRepository =
LocalStorageRepositoryImpl(localStorageDataSource)

@Singleton
@Provides
fun provideLocalStorageDataSource(@ApplicationContext context: Context): LocalStorageDataSource =
LocalStorageDataSource(context)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.fakedevelopers.data.repository

import com.fakedevelopers.data.source.LocalStorageDataSource
import com.fakedevelopers.domain.repository.LocalStorageRepository
import javax.inject.Inject

class LocalStorageRepositoryImpl @Inject constructor(
private val localStorageDataSource: LocalStorageDataSource
) : LocalStorageRepository {
override suspend fun getSearchHistory(): List<String> =
localStorageDataSource.getSearchHistory()

override suspend fun setSearchHistory(searchHistory: List<String>) =
localStorageDataSource.setSearchHistory(searchHistory)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.fakedevelopers.data.source

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringSetPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import javax.inject.Inject

class LocalStorageDataSource @Inject constructor(
private val context: Context
) {
private val Context.datastore: DataStore<Preferences> by preferencesDataStore(name = "dataStore")
private val searchHistoryKey = stringSetPreferencesKey(name = "search_history")

suspend fun setSearchHistory(searchHistory: List<String>): Boolean =
runCatching {
context.datastore.edit { preferences ->
preferences[searchHistoryKey] = searchHistory.toSet()
}
}.isSuccess

suspend fun getSearchHistory(): List<String> =
context.datastore.data.map { preferences ->
preferences[searchHistoryKey]?.toList() ?: emptyList()
}.first()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.fakedevelopers.domain.repository

interface LocalStorageRepository {
suspend fun getSearchHistory(): List<String>
suspend fun setSearchHistory(searchHistory: List<String>): Boolean
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.fakedevelopers.domain.usecase

import com.fakedevelopers.domain.repository.LocalStorageRepository
import javax.inject.Inject

class GetSearchHistoryUseCase @Inject constructor(
private val repository: LocalStorageRepository
) {
suspend operator fun invoke(): List<String> =
repository.getSearchHistory()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.fakedevelopers.domain.usecase

import com.fakedevelopers.domain.repository.LocalStorageRepository
import javax.inject.Inject

class SetSearchHistoryUseCase @Inject constructor(
private val repository: LocalStorageRepository
) {
suspend operator fun invoke(searchHistory: List<String>): Boolean =
repository.setSearchHistory(searchHistory)
}
2 changes: 0 additions & 2 deletions presentation/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ dependencies {
kapt 'com.github.bumptech.glide:compiler:4.14.2'
// time 라이브러리 백포트
implementation 'com.jakewharton.threetenabp:threetenabp:1.4.1'
// datastore
implementation 'androidx.datastore:datastore-preferences:1.0.0'
// viewpager2
implementation "androidx.viewpager2:viewpager2:1.0.0"
// Sentry
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
when (item.itemId) {
R.id.menu_product_registration -> navController.safeNavigate(R.id.productRegistrationFragment)
R.id.menu_chat -> navController.safeNavigate(R.id.channelListFragment)
R.id.menu_product_search -> navController.safeNavigate(R.id.productSearchFragment)
}
true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collectLatest

@AndroidEntryPoint
open class ProductEditorFragment : BaseFragment<FragmentProductEditorBinding>(
abstract class ProductEditorFragment : BaseFragment<FragmentProductEditorBinding>(
R.layout.fragment_product_editor
) {
private lateinit var keyboardVisibilityUtils: KeyboardVisibilityUtils
Expand Down Expand Up @@ -107,9 +107,7 @@ open class ProductEditorFragment : BaseFragment<FragmentProductEditorBinding>(
}
}

protected open fun navigatePictureSelectFragment() {
findNavController().navigate(R.id.action_productRegistrationFragment_to_pictureSelectFragment)
}
protected abstract fun navigatePictureSelectFragment()

protected open fun initListener() {
// 가격 필터 등록
Expand Down Expand Up @@ -247,7 +245,7 @@ open class ProductEditorFragment : BaseFragment<FragmentProductEditorBinding>(
val openingBid = viewModel.openingBid.priceToLong() ?: return false
val hopePrice = viewModel.hopePrice.priceToLong()
if (hopePrice != null && hopePrice <= openingBid) {
sendSnackBar(getString(R.string.product_registration_error_minimum_bid))
sendSnackBar(getString(R.string.product_editor_error_minimum_bid))
return false
}
return true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class ProductModificationFragment : ProductEditorFragment() {

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.editorToolbarTitle = "내 물건 수정"
viewModel.editorToolbarTitle = getString(R.string.product_modification_title)
viewModel.productId = args.productId
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,16 @@ import android.os.Bundle
import android.view.View
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.emptyPreferences
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import com.fakedevelopers.presentation.R
import com.fakedevelopers.presentation.api.datastore.DatastoreSetting.Companion.SEARCH_HISTORY
import com.fakedevelopers.presentation.api.datastore.DatastoreSetting.Companion.datastore
import com.fakedevelopers.presentation.databinding.FragmentProductSearchBinding
import com.fakedevelopers.presentation.ui.base.BaseFragment
import com.fakedevelopers.presentation.ui.util.repeatOnStarted
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import java.io.IOException

@AndroidEntryPoint
class ProductSearchFragment : BaseFragment<FragmentProductSearchBinding>(
Expand All @@ -37,20 +27,6 @@ class ProductSearchFragment : BaseFragment<FragmentProductSearchBinding>(
requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
}

private val searchHistory by lazy {
requireContext().datastore.data
.catch { exception ->
if (exception is IOException) {
emit(emptyPreferences())
} else {
throw exception
}
}
.map { preferences ->
preferences[SEARCH_HISTORY]?.toList() ?: listOf()
}
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.vm = viewModel
Expand All @@ -59,74 +35,49 @@ class ProductSearchFragment : BaseFragment<FragmentProductSearchBinding>(
}

private fun initCollector() {
lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
searchHistory.collect {
viewModel.setHistoryList(it)
}
}
}
lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.searchWord.collectLatest {
findNavController().apply {
getViewModelStoreOwner(R.id.nav_graph).viewModelStore.clear()
navigate(ProductSearchFragmentDirections.actionProductSearchFragmentToProductListFragment(it))
}
repeatOnStarted(viewLifecycleOwner) {
viewModel.searchWord.collectLatest {
findNavController().apply {
getViewModelStoreOwner(R.id.nav_graph).viewModelStore.clear()
navigate(ProductSearchFragmentDirections.actionProductSearchFragmentToProductListFragment(it))
}
}
}
lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.historySet.collect {
requireContext().datastore.edit { preferences ->
preferences[SEARCH_HISTORY] = it
}
}
}
}
lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.searchBar.collectLatest {
if (it.isNotEmpty()) {
binding.recyclerProductSearchResult.visibility = View.VISIBLE
binding.layoutProductSearchBeforeSearch.visibility = View.INVISIBLE
// 0.7초동안 키보드 조작이 없을때만 api를 요청한다.
delay(WAIT_BEFORE_REQUEST)
viewModel.requestSearchResult()
} else {
binding.recyclerProductSearchResult.visibility = View.INVISIBLE
binding.layoutProductSearchBeforeSearch.visibility = View.VISIBLE
viewModel.clearResult()
}
repeatOnStarted(viewLifecycleOwner) {
viewModel.searchBar.collectLatest {
if (it.isNotEmpty()) {
binding.recyclerProductSearchResult.visibility = View.VISIBLE
binding.layoutProductSearchBeforeSearch.visibility = View.INVISIBLE
// 0.7초동안 키보드 조작이 없을때만 api를 요청한다.
delay(WAIT_BEFORE_REQUEST)
viewModel.requestSearchResult()
} else {
binding.recyclerProductSearchResult.visibility = View.INVISIBLE
binding.layoutProductSearchBeforeSearch.visibility = View.VISIBLE
viewModel.clearResult()
}
}
}
}

private fun initListener() {
binding.toolbarProductSearch.apply {
edittextToolbarSearch.let {
// 키보드 올리기 전에 포커싱을 줘야함
it.requestFocus()
imm.showSoftInput(it, 0)
viewModel.setSearchBar(args.searchWord)
it.setOnEditorActionListener { v, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
imm.hideSoftInputFromWindow(it.windowToken, 0)
viewModel.searchEvent(v.text.toString())
}
true
viewModel.setSearchBar(args.searchWord)
binding.edittextToolbarSearch.run {
// 키보드 올리기 전에 포커싱을 줘야함
requestFocus()
imm.showSoftInput(this, 0)
setOnEditorActionListener { v, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
imm.hideSoftInputFromWindow(windowToken, 0)
viewModel.searchEvent(v.text.toString())
}
true
}
buttonToolbarBack.setOnClickListener { requireActivity().onBackPressedDispatcher.onBackPressed() }
}
binding.textviewProductSearchEraseAll.setOnClickListener {
viewModel.clearHistory()
}
binding.buttonToolbarBack.setOnClickListener { requireActivity().onBackPressedDispatcher.onBackPressed() }
}

companion object {
const val WAIT_BEFORE_REQUEST = 700L
private const val WAIT_BEFORE_REQUEST = 700L
}
}
Loading

0 comments on commit dcb23c5

Please sign in to comment.