Skip to content

Commit c08dc13

Browse files
authored
Merge pull request #74 from boostcampwm-2022/24-feature-route-detail
[PR] 경로 상세 화면 구현
2 parents cab505e + 8bccce9 commit c08dc13

40 files changed

+1293
-74
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.stop.model.route
2+
3+
import com.stop.domain.model.route.tmap.custom.Coordinate
4+
5+
data class RouteItem(
6+
val name: String,
7+
val coordinate: Coordinate,
8+
val mode: Int,
9+
val distance: Double,
10+
val travelTime: Int,
11+
val lastTime: String?,
12+
val beforeColor: Int,
13+
val currentColor: Int,
14+
val type: RouteItemType
15+
)
16+
17+
fun RouteItem.toFirstRouteItem(): RouteItem {
18+
return this.copy(
19+
type = RouteItemType.FIRST
20+
)
21+
}
22+
23+
fun RouteItem.toLastRouteItem(name: String, coordinate: com.stop.model.route.Coordinate): RouteItem {
24+
return this.copy(
25+
name = name,
26+
coordinate = Coordinate(coordinate.latitude, coordinate.longitude),
27+
beforeColor = currentColor,
28+
type = RouteItemType.LAST
29+
)
30+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.stop.model.route
2+
3+
enum class RouteItemType {
4+
FIRST, PATH, LAST
5+
}

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

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

7373
private fun initTMap() {
74-
tMap = MapTMap(requireContext(), this)
74+
tMap = MapTMap(requireActivity(), this)
7575
tMap.init()
7676

7777
binding.frameLayoutContainer.addView(tMap.tMapView)

presentation/src/main/java/com/stop/ui/mission/MissionFragment.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package com.stop.ui.mission
22

33
import android.animation.Animator
44
import android.animation.AnimatorListenerAdapter
5-
import android.content.ContextWrapper
65
import android.os.Bundle
76
import android.view.LayoutInflater
87
import android.view.View
@@ -64,7 +63,7 @@ class MissionFragment : Fragment(), MissionHandler {
6463
}
6564

6665
private fun initTMap() {
67-
tMap = MissionTMap((requireContext() as ContextWrapper).baseContext, this)
66+
tMap = MissionTMap(requireActivity(), this)
6867
tMap.init()
6968

7069
binding.constraintLayoutContainer.addView(tMap.tMapView)

presentation/src/main/java/com/stop/ui/mission/MissionTMap.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class MissionTMap(
1717
lineColor = color
1818
outLineColor = color
1919
}
20+
2021
tMapView.addTMapPolyLine(polyLine)
2122
}
2223

presentation/src/main/java/com/stop/ui/route/RouteFragment.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ package com.stop.ui.route
22

33
import android.content.Context
44
import android.os.Bundle
5+
import androidx.fragment.app.Fragment
56
import android.view.LayoutInflater
67
import android.view.View
78
import android.view.ViewGroup
89
import android.widget.Toast
910
import androidx.activity.OnBackPressedCallback
10-
import androidx.fragment.app.Fragment
1111
import androidx.navigation.findNavController
1212
import androidx.navigation.fragment.navArgs
1313
import androidx.fragment.app.activityViewModels
@@ -123,8 +123,6 @@ class RouteFragment : Fragment() {
123123
}
124124
}
125125

126-
127-
128126
private fun setStartAndDestinationText() {
129127
args.start?.let {
130128
routeViewModel.setOrigin(it)

presentation/src/main/java/com/stop/ui/route/RouteResultViewModel.kt

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
package com.stop.ui.route
22

3+
import android.graphics.Color
34
import androidx.lifecycle.LiveData
45
import androidx.lifecycle.MutableLiveData
56
import androidx.lifecycle.ViewModel
7+
import com.stop.R
68
import com.stop.domain.model.route.TransportLastTime
79
import com.stop.domain.model.route.tmap.custom.Itinerary
8-
import com.stop.model.route.Place
10+
import com.stop.domain.model.route.tmap.custom.MoveType
11+
import com.stop.domain.model.route.tmap.custom.Route
12+
import com.stop.domain.model.route.tmap.custom.TransportRoute
13+
import com.stop.model.route.*
914

1015
class RouteResultViewModel : ViewModel() {
11-
1216
private val _itinerary = MutableLiveData<Itinerary>()
1317
val itinerary: LiveData<Itinerary>
1418
get() = _itinerary
@@ -25,6 +29,8 @@ class RouteResultViewModel : ViewModel() {
2529
val destination: LiveData<Place>
2630
get() = _destination
2731

32+
private var routeItemColor = 0
33+
2834
fun setItineraries(itinerary: Itinerary) {
2935
_itinerary.value = itinerary
3036
}
@@ -40,4 +46,87 @@ class RouteResultViewModel : ViewModel() {
4046
fun setDestination(destinationPlace: Place?) {
4147
_destination.value = destinationPlace ?: return
4248
}
49+
50+
fun getRouteItems(): List<RouteItem> {
51+
val routeItems = mutableListOf<RouteItem>()
52+
53+
itinerary.value?.routes?.forEachIndexed { index, route ->
54+
routeItems.add(
55+
RouteItem(
56+
name = getRouteItemName(index, route),
57+
coordinate = route.start.coordinate,
58+
mode = getRouteItemMode(route),
59+
distance = getRouteItemDistance(route),
60+
travelTime = route.sectionTime.toInt(),
61+
lastTime = lastTimes.value?.get(index)?.lastTime,
62+
beforeColor = getRouteItemColor(route, false),
63+
currentColor = getRouteItemColor(route, true),
64+
type = RouteItemType.PATH
65+
)
66+
)
67+
}
68+
routeItems.add(0, routeItems.first().toFirstRouteItem())
69+
destination.value?.let {
70+
routeItems.add(routeItems.last().toLastRouteItem(it.name, it.coordinate))
71+
}
72+
73+
return routeItems.toList()
74+
}
75+
76+
private fun getRouteItemName(index: Int, route: Route): String {
77+
return if (index == 0) {
78+
origin.value?.name ?: ""
79+
} else {
80+
route.start.name
81+
}
82+
}
83+
84+
private fun getRouteItemMode(route: Route): Int {
85+
return when (route.mode) {
86+
MoveType.WALK -> R.drawable.ic_walk_white
87+
MoveType.BUS -> R.drawable.ic_bus_white
88+
MoveType.SUBWAY -> R.drawable.ic_subway_white
89+
MoveType.TRANSFER -> R.drawable.ic_transfer_white
90+
else -> R.drawable.ic_star_white
91+
}
92+
}
93+
94+
private fun getRouteItemDistance(route: Route): Double {
95+
return if (route.mode == MoveType.TRANSFER) {
96+
val startPoint = android.location.Location("Start")
97+
val endPoint = android.location.Location("End")
98+
99+
startPoint.latitude = route.start.coordinate.latitude.toDouble()
100+
startPoint.longitude = route.start.coordinate.longitude.toDouble()
101+
endPoint.latitude = route.end.coordinate.latitude.toDouble()
102+
endPoint.longitude = route.end.coordinate.longitude.toDouble()
103+
startPoint.distanceTo(endPoint).toDouble()
104+
} else {
105+
route.distance
106+
}
107+
}
108+
109+
private fun getRouteItemColor(route: Route, isCurrent: Boolean): Int {
110+
return if (isCurrent) {
111+
routeItemColor = if (route is TransportRoute) {
112+
Color.parseColor("#${route.routeColor}")
113+
} else if (route.mode == MoveType.WALK) {
114+
Color.parseColor(MAIN_WALK_GREY)
115+
} else {
116+
Color.parseColor(MAIN_YELLOW)
117+
}
118+
routeItemColor
119+
} else {
120+
if (routeItemColor != 0) {
121+
routeItemColor
122+
} else {
123+
getRouteItemColor(route, true)
124+
}
125+
}
126+
}
127+
128+
companion object {
129+
private const val MAIN_WALK_GREY = "#C0C5CA"
130+
private const val MAIN_YELLOW = "#FFC766"
131+
}
43132
}

presentation/src/main/java/com/stop/ui/route/RouteViewModel.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import androidx.lifecycle.ViewModel
66
import androidx.lifecycle.viewModelScope
77
import com.stop.domain.model.route.TransportLastTime
88
import com.stop.domain.model.route.tmap.RouteRequest
9-
import com.stop.domain.model.route.tmap.custom.Itinerary
9+
import com.stop.domain.model.route.tmap.custom.*
1010
import com.stop.domain.usecase.route.GetLastTransportTimeUseCase
1111
import com.stop.domain.usecase.route.GetRouteUseCase
1212
import com.stop.model.ErrorType
@@ -22,7 +22,7 @@ class RouteViewModel @Inject constructor(
2222
private val getLastTransportTimeUseCase: GetLastTransportTimeUseCase,
2323
) : ViewModel() {
2424

25-
var clickedItineraryIndex: Int = -1
25+
private var clickedItineraryIndex: Int = -1
2626

2727
private val _origin = MutableLiveData<Place>()
2828
val origin: LiveData<Place>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.stop.ui.routedetail
2+
3+
import com.stop.domain.model.route.tmap.custom.Coordinate
4+
5+
interface OnRouteItemClickListener {
6+
fun clickRouteItem(coordinate: Coordinate)
7+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package com.stop.ui.routedetail
2+
3+
import android.view.LayoutInflater
4+
import android.view.ViewGroup
5+
import androidx.databinding.ViewDataBinding
6+
import androidx.recyclerview.widget.DiffUtil
7+
import androidx.recyclerview.widget.ListAdapter
8+
import androidx.recyclerview.widget.RecyclerView
9+
import com.stop.databinding.RouteFirstItemBinding
10+
import com.stop.databinding.RouteLastItemBinding
11+
import com.stop.databinding.RoutePathItemBinding
12+
import com.stop.model.route.RouteItem
13+
import com.stop.model.route.RouteItemType
14+
15+
class RouteDetailAdapter(
16+
private val onRouteItemClickListener: OnRouteItemClickListener
17+
): ListAdapter<RouteItem, RecyclerView.ViewHolder>(diffUtil) {
18+
class FirstViewHolder(
19+
private val binding: RouteFirstItemBinding
20+
) : RecyclerView.ViewHolder(binding.root) {
21+
fun bind(routeItem: RouteItem) {
22+
binding.routeItem = routeItem
23+
}
24+
}
25+
26+
class PathViewHolder(
27+
private val binding: RoutePathItemBinding
28+
) : RecyclerView.ViewHolder(binding.root) {
29+
fun bind(routeItem: RouteItem) {
30+
binding.routeItem = routeItem
31+
}
32+
}
33+
34+
class LastViewHolder(
35+
private val binding: RouteLastItemBinding
36+
) : RecyclerView.ViewHolder(binding.root) {
37+
fun bind(routeItem: RouteItem) {
38+
binding.routeItem = routeItem
39+
}
40+
}
41+
42+
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
43+
val binding: ViewDataBinding
44+
val inflater = LayoutInflater.from(parent.context)
45+
val viewHolder: RecyclerView.ViewHolder = when (viewType) {
46+
TYPE_FIRST -> {
47+
binding = RouteFirstItemBinding.inflate(inflater, parent, false)
48+
FirstViewHolder(binding)
49+
}
50+
TYPE_PATH -> {
51+
binding = RoutePathItemBinding.inflate(inflater, parent, false)
52+
PathViewHolder(binding)
53+
}
54+
TYPE_LAST -> {
55+
binding = RouteLastItemBinding.inflate(inflater, parent, false)
56+
LastViewHolder(binding)
57+
}
58+
else -> throw IllegalArgumentException("Invalid ViewType")
59+
}
60+
61+
binding.root.setOnClickListener {
62+
onRouteItemClickListener.clickRouteItem(getItem(viewHolder.adapterPosition).coordinate)
63+
}
64+
65+
return viewHolder
66+
}
67+
68+
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
69+
when (holder) {
70+
is FirstViewHolder -> holder.bind(getItem(position))
71+
is PathViewHolder -> holder.bind(getItem(position))
72+
is LastViewHolder -> holder.bind(getItem(position))
73+
}
74+
}
75+
76+
override fun getItemViewType(position: Int): Int {
77+
return when ((getItem(position) as RouteItem).type) {
78+
RouteItemType.FIRST -> TYPE_FIRST
79+
RouteItemType.PATH -> TYPE_PATH
80+
RouteItemType.LAST -> TYPE_LAST
81+
}
82+
}
83+
84+
companion object {
85+
private const val TYPE_FIRST = 0
86+
private const val TYPE_PATH = 1
87+
private const val TYPE_LAST = 2
88+
89+
private val diffUtil = object : DiffUtil.ItemCallback<RouteItem>() {
90+
override fun areItemsTheSame(oldItem: RouteItem, newItem: RouteItem): Boolean {
91+
return oldItem.name == newItem.name
92+
}
93+
94+
override fun areContentsTheSame(oldItem: RouteItem, newItem: RouteItem): Boolean {
95+
return oldItem == newItem
96+
}
97+
}
98+
}
99+
}

0 commit comments

Comments
 (0)