Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[리뷰 작성 - 05] 주소 검색 UseCase 추가 #56

Open
wants to merge 3 commits into
base: 40/04_view_model
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion app/src/main/java/com/ftw/hometerview/di/api/APIModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ package com.ftw.hometerview.di.api

import com.ftw.data.remote.api.BuildingReviewsAPI
import com.ftw.data.remote.api.LoginAPI
import com.ftw.data.remote.api.SearchAPI
import com.ftw.data.remote.api.review.ReviewAPI
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import retrofit2.Retrofit
import javax.inject.Singleton
import retrofit2.Retrofit

@Module
@InstallIn(SingletonComponent::class)
Expand All @@ -31,4 +32,10 @@ class APIModule {
fun provideBuildingReviewsApi(retrofit: Retrofit): BuildingReviewsAPI {
return retrofit.create(BuildingReviewsAPI::class.java)
}

@Provides
@Singleton
fun provideSearchApi(retrofit: Retrofit): SearchAPI {
return retrofit.create(SearchAPI::class.java)
}
}
4 changes: 2 additions & 2 deletions app/src/main/java/com/ftw/hometerview/di/api/NetworkModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import javax.inject.Singleton
class NetworkModule {

companion object {
private const val DEBUG_BASE_URL = "http://13.125.75.159:8080/"
private const val RELEASE_BASE_URL = "http://13.125.75.159:8080/"
private const val DEBUG_BASE_URL = "http://3.36.37.15/:8080/"
private const val RELEASE_BASE_URL = "http://3.36.37.15/:8080/"
}

@Provides
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.ftw.hometerview.di.datasource

import com.ftw.data.datasource.search.SearchDataSource
import com.ftw.data.remote.api.SearchAPI
import com.ftw.data.remote.datasource.search.SearchRemoteDataSource
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
class SearchDataSourceModule {

@Provides
@Singleton
fun provideSearchDataSource(searchAPI: SearchAPI): SearchDataSource {
return SearchRemoteDataSource(searchAPI)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.ftw.hometerview.di.repository

import com.ftw.data.datasource.search.SearchDataSource
import com.ftw.data.repository.search.SearchRepositoryImpl
import com.ftw.domain.repository.search.SearchRepository
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
class SearchRepositoryModule {

@Provides
@Singleton
fun provideSearchRepository(dataSource: SearchDataSource): SearchRepository {
return SearchRepositoryImpl(dataSource)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.ftw.hometerview.di.ui

import com.ftw.domain.usecase.address.GetAddressUseCase
import com.ftw.domain.usecase.search.GetSearchedBuildingAddressesUseCase
import com.ftw.hometerview.dispatcher.Dispatcher
import com.ftw.hometerview.ui.review.first.CreateReviewFirstStepInputAddressViewModel
import com.ftw.hometerview.ui.review.first.CreateReviewFirstStepSelectFloorViewModel
Expand All @@ -20,11 +20,11 @@ class CreateReviewFragmentViewModelModule {
@FragmentScoped
fun provideCreateReviewFirstStepInputAddressViewModel(
dispatcher: Dispatcher,
getAddressUseCase: GetAddressUseCase
getSearchedBuildingAddressesUseCase: GetSearchedBuildingAddressesUseCase
): CreateReviewFirstStepInputAddressViewModel {
return CreateReviewFirstStepInputAddressViewModel(
dispatcher,
getAddressUseCase
getSearchedBuildingAddressesUseCase
)
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.ftw.hometerview.di.usecase

import com.ftw.domain.repository.search.SearchRepository
import com.ftw.domain.usecase.search.GetSearchedBuildingAddressesUseCase
import com.ftw.domain.usecase.search.GetSearchedBuildingAddressesUseCaseImpl
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent

@Module
@InstallIn(SingletonComponent::class)
class SearchUseCaseModule {
@Provides
fun provideSearchBuildingAddressesUseCaseImpl(
repository: SearchRepository
): GetSearchedBuildingAddressesUseCase {
return GetSearchedBuildingAddressesUseCaseImpl(repository)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -177,12 +177,14 @@ class HomeFragment : Fragment() {
).apply {
addUpdateListener { valueAnimator ->
val value = valueAnimator.animatedValue as? Int ?: 0
if (_binding == null) return@addUpdateListener
binding.inducementEmptyLayout.updateLayoutParams<ViewGroup.LayoutParams> {
height = value
}
}

doOnEnd {
if (_binding == null) return@doOnEnd
binding.inducementLayout.isVisible = true
binding.inducementLayout.startAnimation(
AlphaAnimation(0f, 1f).apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import com.ftw.domain.entity.Address
import com.ftw.domain.entity.Review
import com.ftw.hometerview.R
import com.ftw.hometerview.databinding.ActivityCreateReviewBinding
Expand Down Expand Up @@ -51,11 +52,11 @@ class CreateReviewActivity :
)
}

override fun onClickAddressFromFirstStepAddress(address: String) {
viewModel.setAddress(buildingId = "test")
override fun onClickAddressFromFirstStepAddress(address: Address) {
viewModel.setBuildingId(address.id)
addFragment(
R.id.fragment_container_view,
CreateReviewFirstStepSelectFloorFragment.newInstance(address),
CreateReviewFirstStepSelectFloorFragment.newInstance(address.name),
true
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class CreateReviewViewModel(
private var disadvantage: String? = null
private var floor: String? = null

fun setAddress(buildingId: String) {
fun setBuildingId(buildingId: String) {
this.buildingId = buildingId
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.ftw.domain.entity.Address
import com.ftw.hometerview.R
import com.ftw.hometerview.adapter.DataBindingRecyclerAdapter
import com.ftw.hometerview.adapter.DividerItemDecoration
Expand All @@ -26,7 +28,7 @@ class CreateReviewFirstStepInputAddressFragment : Fragment() {
}

interface Listener {
fun onClickAddressFromFirstStepAddress(address: String)
fun onClickAddressFromFirstStepAddress(address: Address)
}

private var _binding: FragmentCreateReviewFirstStepInputAddressBinding? = null
Expand All @@ -48,7 +50,8 @@ class CreateReviewFirstStepInputAddressFragment : Fragment() {
container,
false
).apply {
this.viewModel = [email protected]
lifecycleOwner = viewLifecycleOwner
viewModel = [email protected]
}
return binding.root
}
Expand Down Expand Up @@ -86,6 +89,9 @@ class CreateReviewFirstStepInputAddressFragment : Fragment() {
hideKeyboard()
(activity as? Listener)?.onClickAddressFromFirstStepAddress(event.address)
}
is CreateReviewFirstStepInputAddressViewModel.Event.Error -> {
Toast.makeText(requireContext(), event.throwable.message, Toast.LENGTH_SHORT)
}
else -> {
// Do Nothing
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.ftw.hometerview.ui.review.first

import com.ftw.domain.usecase.address.GetAddressUseCase
import com.ftw.domain.entity.Address
import com.ftw.domain.usecase.search.GetSearchedBuildingAddressesUseCase
import com.ftw.hometerview.BR
import com.ftw.hometerview.R
import com.ftw.hometerview.adapter.RecyclerItem
Expand All @@ -10,38 +11,48 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.transformLatest

class CreateReviewFirstStepInputAddressViewModel(
dispatcher: Dispatcher,
private val getAddressUseCase: GetAddressUseCase
private val getSearchedBuildingAddressesUseCase: GetSearchedBuildingAddressesUseCase
) {

sealed class Event {
object Nothing : Event()
data class OnClickAddress(val address: String) : Event()
data class Error(val throwable: Throwable) : Event()
data class OnClickAddress(val address: Address) : Event()
}

private val _event: MutableStateFlow<Event> = MutableStateFlow(Event.Nothing)
val event: StateFlow<Event> = _event.asStateFlow()

private val _isLoading: MutableStateFlow<Boolean> = MutableStateFlow(false)
val isLoading: StateFlow<Boolean> = _isLoading

val address: MutableStateFlow<String> = MutableStateFlow("")

val addressItems: StateFlow<List<RecyclerItem>> =
address
.debounce(500)
.transformLatest { address ->
flow {
if (address.isNotBlank()) emit(getAddressUseCase(address))
else emit(Result.success(emptyList()))
}.collect { result ->
if (result.isSuccess && result.getOrNull() != null) {
emit(
result.getOrDefault(emptyList())
.map { searchedAddress ->
if (address.isNotBlank()) emit(getSearchedBuildingAddressesUseCase(address))
else emit(emptyList())
}
.onStart { _isLoading.value = true }
.onCompletion { _isLoading.value = false }
.catch { _event.value = Event.Error(it) }
.collect { addresses ->
if (addresses.isNotEmpty()) {
emit(
addresses.map { searchedAddress ->
RecyclerItem(
data = CreateReviewAddressItem(
address = searchedAddress,
Expand All @@ -51,17 +62,17 @@ class CreateReviewFirstStepInputAddressViewModel(
variableId = BR.item
)
}
)
} else {
emit(emptyList<RecyclerItem>())
)
} else {
emit(emptyList<RecyclerItem>())
}
}
}
}.stateIn(CoroutineScope(dispatcher.ui()), SharingStarted.Eagerly, emptyList())
}

data class CreateReviewAddressItem(
val address: String,
val onClick: (String) -> Unit
val address: Address,
val onClick: (Address) -> Unit
) {
fun onClick() {
this.onClick(address)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -280,5 +280,15 @@
tools:itemCount="10"
/>

<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{viewModel.isLoading ? View.VISIBLE : View.GONE}"
app:layout_constraintTop_toBottomOf="@id/toolbar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
/>

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_size_14"
android:onClick="@{() -> viewModel.onClickBack()}"
app:srcCompat="@drawable/icon_back"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
android:padding="@dimen/dp_size_16"
android:background="@color/white"
android:onClick="@{() -> item.onClick()}"
android:text="@{item.address}"
android:text="@{item.address.name}"
android:fontFamily="@font/pretendard_regular"
android:textSize="@dimen/sp_size_14"
android:textColor="@color/gray_900"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.ftw.data.datasource.search

import com.ftw.domain.entity.Address

interface SearchDataSource {
suspend fun buildings(keyword: String): List<Address>
}
14 changes: 14 additions & 0 deletions data/src/main/java/com/ftw/data/remote/api/SearchAPI.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.ftw.data.remote.api

import com.ftw.data.remote.response.RemoteResponse
import com.ftw.data.remote.response.address.AddressResponse
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Query

interface SearchAPI {
@GET("/api/v1/place")
suspend fun buildings(
@Query("keyword") keyword: String
): Response<RemoteResponse<List<AddressResponse>>>
}
Loading