Skip to content

Commit cab505e

Browse files
authored
Merge pull request #73 from boostcampwm-2022/70-feature-fix-ui
[PR] 버그 ν”½μŠ€ 및 μž₯μ†Œ 검색 UI μˆ˜μ •
2 parents fdae435 + fcfdb85 commit cab505e

File tree

22 files changed

+324
-189
lines changed

22 files changed

+324
-189
lines changed

β€Ždata/src/main/java/com/stop/data/local/model/RecentPlaceSearchEntity.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
package com.stop.data.local.model
22

33
import androidx.room.Entity
4+
import androidx.room.Index
45
import androidx.room.PrimaryKey
56
import com.stop.data.model.nearplace.PlaceRepositoryItem
67

7-
@Entity
8+
@Entity(indices = [Index(value = ["name"], unique = true)])
89
data class RecentPlaceSearchEntity(
9-
@PrimaryKey(autoGenerate = true)
10-
val id: Int? = null,
1110
val name: String,
1211
val radius: String,
1312
val fullAddressRoad: String,
1413
val centerLat: Double,
15-
val centerLon: Double
14+
val centerLon: Double,
15+
@PrimaryKey(autoGenerate = true)
16+
val id: Long = 0,
1617
) {
1718

1819
fun toRepositoryModel() = PlaceRepositoryItem(

β€Ždata/src/main/java/com/stop/data/remote/model/nearplace/Poi.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.stop.data.remote.model.nearplace
22

33
import com.squareup.moshi.JsonClass
44
import com.stop.data.model.nearplace.PlaceRepositoryItem
5+
import kotlin.math.round
56

67
@JsonClass(generateAdapter = true)
78
data class Poi(
@@ -45,7 +46,7 @@ data class Poi(
4546
val road = newAddressList.newAddress.firstOrNull()
4647
return PlaceRepositoryItem(
4748
name = name,
48-
radius = radius,
49+
radius = (round(radius.toDouble() * 100) / 100).toString(),
4950
fullAddressRoad = road?.fullAddressRoad ?: "",
5051
centerLat = road?.centerLat?.toDouble() ?: 0.0,
5152
centerLon = road?.centerLon?.toDouble() ?: 0.0

β€Žpresentation/src/main/java/com/stop/MainActivity.kt

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import android.view.inputmethod.InputMethodManager
1212
import android.widget.EditText
1313
import androidx.appcompat.app.AppCompatActivity
1414
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
15+
import androidx.core.view.WindowCompat
1516
import androidx.navigation.fragment.NavHostFragment
1617
import com.stop.databinding.ActivityMainBinding
1718
import dagger.hilt.android.AndroidEntryPoint
@@ -36,24 +37,16 @@ class MainActivity : AppCompatActivity() {
3637

3738
override fun onCreate(savedInstanceState: Bundle?) {
3839
installSplashScreen()
39-
40+
WindowCompat.setDecorFitsSystemWindows(window, false)
4041
super.onCreate(savedInstanceState)
4142

4243
binding = ActivityMainBinding.inflate(layoutInflater)
4344
setContentView(binding.root)
4445

45-
hideStatusBar()
46+
binding.navHostFragment.setPadding(0, 0, 0, this.navigationHeight())
4647
showOverLockScreen()
4748
}
4849

49-
50-
private fun hideStatusBar() {
51-
window.setFlags(
52-
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
53-
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
54-
)
55-
}
56-
5750
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
5851
if (event.action == MotionEvent.ACTION_DOWN) {
5952
val view = currentFocus
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.stop
2+
3+
import android.content.Context
4+
5+
fun Context.statusBarHeight(): Int {
6+
val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
7+
8+
return if (resourceId > 0) resources.getDimensionPixelSize(resourceId)
9+
else 0
10+
}
11+
12+
fun Context.navigationHeight(): Int {
13+
val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android")
14+
15+
return if (resourceId > 0) resources.getDimensionPixelSize(resourceId)
16+
else 0
17+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.stop.bindingadapter
2+
3+
import android.text.Editable
4+
import android.text.TextWatcher
5+
import android.widget.EditText
6+
import kotlinx.coroutines.channels.awaitClose
7+
import kotlinx.coroutines.flow.Flow
8+
import kotlinx.coroutines.flow.callbackFlow
9+
import kotlinx.coroutines.flow.onStart
10+
11+
fun EditText.textChangesToFlow(): Flow<CharSequence?> {
12+
return callbackFlow {
13+
val listener = object : TextWatcher {
14+
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
15+
override fun afterTextChanged(s: Editable?) = Unit
16+
override fun onTextChanged(text: CharSequence?, start: Int, before: Int, count: Int) {
17+
trySend(text)
18+
}
19+
}
20+
addTextChangedListener(listener)
21+
awaitClose { removeTextChangedListener(listener) }
22+
}.onStart {
23+
emit(text)
24+
}
25+
}

β€Žpresentation/src/main/java/com/stop/ui/map/MapFragment.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ class MapFragment : Fragment(), MapHandler {
213213

214214
private fun setViewVisibility() {
215215
with(binding) {
216-
layoutSearch.visibility = mapUIVisibility
216+
textViewSearch.visibility = mapUIVisibility
217217
layoutCompass.visibility = mapUIVisibility
218218
layoutCurrent.visibility = mapUIVisibility
219219
}

β€Žpresentation/src/main/java/com/stop/ui/placesearch/PlaceSearchFragment.kt

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@ import androidx.lifecycle.flowWithLifecycle
1515
import androidx.lifecycle.lifecycleScope
1616
import androidx.navigation.fragment.findNavController
1717
import com.stop.R
18+
import com.stop.bindingadapter.textChangesToFlow
1819
import com.stop.databinding.FragmentPlaceSearchBinding
1920
import com.stop.domain.model.nearplace.PlaceUseCaseItem
2021
import dagger.hilt.android.AndroidEntryPoint
21-
import kotlinx.coroutines.FlowPreview
22+
import kotlinx.coroutines.Dispatchers
2223
import kotlinx.coroutines.flow.debounce
2324
import kotlinx.coroutines.flow.launchIn
2425
import kotlinx.coroutines.flow.onEach
@@ -56,18 +57,24 @@ class PlaceSearchFragment : Fragment() {
5657
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
5758
super.onViewCreated(view, savedInstanceState)
5859

60+
initTextEditText()
5961
initAdapter()
6062
buttonClick()
6163
listenEditTextChange()
6264
logErrorMessage()
63-
observeSearchKeyword()
65+
listenSearchEditText()
66+
}
67+
68+
private fun initTextEditText() {
69+
binding.textInputEditTextPlaceSearch.requestFocus()
70+
showKeyBoard()
6471
}
6572

6673
private fun initAdapter() {
67-
placeSearchAdapter = PlaceSearchAdapter{
74+
placeSearchAdapter = PlaceSearchAdapter {
6875
clickPlace(it)
6976
}
70-
recentPlaceSearchAdapter = RecentPlaceSearchAdapter{
77+
recentPlaceSearchAdapter = RecentPlaceSearchAdapter {
7178
clickPlace(it)
7279
}
7380

@@ -85,13 +92,13 @@ class PlaceSearchFragment : Fragment() {
8592

8693
private fun buttonClick() {
8794
with(binding) {
88-
textViewCurrentLocation.setOnClickListener {
95+
layoutRecentSearch.textViewCurrentLocation.setOnClickListener {
8996
placeSearchViewModel.setClickCurrentLocation()
9097

9198
findNavController().navigate(R.id.action_placeSearchFragment_to_mapFragment)
9299
}
93100

94-
textViewSelectMap.setOnClickListener {
101+
layoutRecentSearch.textViewSelectMap.setOnClickListener {
95102
findNavController().navigate(R.id.action_placeSearchFragment_to_mapFragment)
96103
}
97104
}
@@ -117,6 +124,11 @@ class PlaceSearchFragment : Fragment() {
117124
}
118125
}
119126

127+
private fun showKeyBoard() {
128+
val imm = requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
129+
imm.showSoftInput(binding.textInputEditTextPlaceSearch, InputMethodManager.SHOW_IMPLICIT)
130+
}
131+
120132
private fun hideKeyBoard() {
121133
val imm = requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
122134
imm.hideSoftInputFromWindow(requireActivity().currentFocus?.windowToken, 0)
@@ -135,17 +147,17 @@ class PlaceSearchFragment : Fragment() {
135147
}
136148
}
137149

138-
@OptIn(FlowPreview::class)
139-
private fun observeSearchKeyword(){
140-
placeSearchViewModel.searchKeyword.debounce(100)
141-
.onEach {
142-
if(it.isBlank()){
143-
placeSearchViewModel.setNearPlacesEmpty()
144-
}else{
145-
placeSearchViewModel.getNearPlaces(it)
150+
private fun listenSearchEditText() {
151+
lifecycleScope.launch(Dispatchers.IO) {
152+
val editTextFlow = binding.textInputEditTextPlaceSearch.textChangesToFlow()
153+
154+
editTextFlow
155+
.debounce(500)
156+
.onEach {
157+
placeSearchViewModel.getNearPlaces(it.toString())
146158
}
147-
}
148-
.launchIn(lifecycleScope)
159+
.launchIn(this)
160+
}
149161
}
150162

151163
override fun onDestroyView() {

β€Žpresentation/src/main/java/com/stop/ui/placesearch/PlaceSearchViewModel.kt

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.stop.ui.placesearch
22

3-
import android.text.Editable
43
import android.view.View
54
import androidx.lifecycle.LiveData
65
import androidx.lifecycle.MutableLiveData
@@ -28,12 +27,13 @@ import kotlin.math.round
2827
class PlaceSearchViewModel @Inject constructor(
2928
private val getNearPlacesUseCase: GetNearPlacesUseCase,
3029
private val geoLocationUseCase: GeoLocationUseCase,
31-
private val getRecentPlaceSearchUseCase: GetRecentPlaceSearchUseCase,
30+
getRecentPlaceSearchUseCase: GetRecentPlaceSearchUseCase,
3231
private val deleteRecentPlaceSearchUseCase: DeleteRecentPlaceSearchUseCase,
3332
private val insertRecentPlaceSearchUseCase: InsertRecentPlaceSearchUseCase
3433
) : ViewModel() {
3534

36-
var currentLocation = Location(0.0, 0.0)
35+
// κΈ°λ³Έ μ£Όμ†Œλ‘œ μ„œμšΈμ—­ μ£Όμ†Œ μ§€μ •
36+
var currentLocation = Location(37.553836, 126.969652)
3737

3838
var panelInfo: com.stop.model.route.Place? = null
3939

@@ -52,9 +52,6 @@ class PlaceSearchViewModel @Inject constructor(
5252
private val clickCurrentLocationChannel = Channel<Boolean>()
5353
val clickCurrentLocation = clickCurrentLocationChannel.receiveAsFlow()
5454

55-
private val _searchKeyword = MutableStateFlow("")
56-
val searchKeyword: StateFlow<String> = _searchKeyword
57-
5855
private val _geoLocation = MutableLiveData<GeoLocationInfo>()
5956
val geoLocation: LiveData<GeoLocationInfo> = _geoLocation
6057

@@ -64,17 +61,9 @@ class PlaceSearchViewModel @Inject constructor(
6461
private val _distance = MutableLiveData<Float>()
6562
val distance: LiveData<Float> = _distance
6663

67-
val recentPlaceSearch: StateFlow<List<PlaceUseCaseItem>> =
68-
getRecentPlaceSearchUseCase.getAllRecentPlaceSearch()
69-
.stateIn(
70-
scope = viewModelScope,
71-
started = SharingStarted.WhileSubscribed(),
72-
initialValue = emptyList()
73-
)
74-
75-
fun afterTextChanged(s: Editable?) {
76-
_searchKeyword.value = s.toString()
77-
}
64+
val recentPlaceSearch: StateFlow<List<PlaceUseCaseItem>> = getRecentPlaceSearchUseCase.getAllRecentPlaceSearch().stateIn(
65+
scope = viewModelScope, started = SharingStarted.WhileSubscribed(), initialValue = emptyList()
66+
)
7867

7968
fun getNearPlaces(
8069
searchKeyword: String,
@@ -83,9 +72,7 @@ class PlaceSearchViewModel @Inject constructor(
8372
try {
8473
_nearPlaces.emit(
8574
getNearPlacesUseCase.getNearPlaces(
86-
searchKeyword,
87-
currentLocation.longitude,
88-
currentLocation.latitude
75+
searchKeyword, currentLocation.longitude, currentLocation.latitude
8976
)
9077
)
9178

@@ -99,7 +86,6 @@ class PlaceSearchViewModel @Inject constructor(
9986

10087
fun setNearPlacesEmpty() {
10188
_nearPlaces.value = emptyList()
102-
_searchKeyword.value = ""
10389
_isNearPlacesNotEmpty.value = false
10490
}
10591

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
1-
<vector android:height="24dp" android:tint="#000000"
2-
android:viewportHeight="24" android:viewportWidth="24"
3-
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
4-
<path android:fillColor="@android:color/white" android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="24"
5+
android:viewportHeight="24">
6+
<group>
7+
<path android:name="square"
8+
android:fillColor="@color/blue"
9+
android:pathData="M0,0 L24,0 L24,24 L0,24 z" />
10+
<path
11+
android:fillColor="@android:color/white"
12+
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z" />
13+
14+
</group>
515
</vector>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="48dp"
3+
android:height="48dp"
4+
android:viewportWidth="48"
5+
android:viewportHeight="48">
6+
<group>
7+
<clip-path
8+
android:pathData="M0,0h48v48h-48z"/>
9+
<path
10+
android:pathData="M22,30H26V34H22V30ZM22,14H26V26H22V14ZM23.98,4C12.94,4 4,12.96 4,24C4,35.04 12.94,44 23.98,44C35.04,44 44,35.04 44,24C44,12.96 35.04,4 23.98,4ZM24,40C15.16,40 8,32.84 8,24C8,15.16 15.16,8 24,8C32.84,8 40,15.16 40,24C40,32.84 32.84,40 24,40Z"
11+
android:fillColor="#CCCCCC"/>
12+
</group>
13+
</vector>

0 commit comments

Comments
Β (0)