Skip to content

Commit f808c7e

Browse files
Merge pull request #94 from boostcampwm-2022/91-feat-route-ui
경로 화면 그리기
2 parents 7b8378d + f201c94 commit f808c7e

File tree

22 files changed

+375
-279
lines changed

22 files changed

+375
-279
lines changed

data/src/main/java/com/stop/data/remote/source/route/RouteRemoteDataSourceImpl.kt

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -211,24 +211,25 @@ internal class RouteRemoteDataSourceImpl @Inject constructor(
211211
private fun eraseDuplicateLeg(itineraries: List<Itinerary>): List<Itinerary> {
212212
return itineraries.map { itinerary ->
213213
var beforeInfo: Pair<String, Coordinate>? = null
214-
var subtractTime = 0.0
215-
var subtractDistance = 0.0
214+
var calculatedTotalTime = 0.0
215+
var calculatedTotalDistance = 0.0
216216

217217
val newLegs = itinerary.legs.fold(listOf<Leg>()) { legs, leg ->
218218
val current =
219219
Pair(leg.mode, Coordinate(leg.start.lat.toString(), leg.start.lon.toString()))
220220

221221
if (legs.isEmpty()) {
222222
beforeInfo = current
223+
calculatedTotalTime += leg.sectionTime
224+
calculatedTotalDistance += leg.distance
223225
return@fold legs + leg
224226
}
225-
226227
if (beforeInfo == current) {
227-
subtractDistance += leg.distance
228-
subtractTime += leg.sectionTime
229228
return@fold legs
230229
}
231230
beforeInfo = current
231+
calculatedTotalTime += leg.sectionTime
232+
calculatedTotalDistance += leg.distance
232233
legs + leg
233234
}
234235

@@ -237,8 +238,8 @@ internal class RouteRemoteDataSourceImpl @Inject constructor(
237238
fare = fare,
238239
legs = newLegs,
239240
pathType = pathType,
240-
totalDistance = totalDistance - subtractDistance,
241-
totalTime = totalTime - subtractTime.toInt(),
241+
totalDistance = calculatedTotalDistance,
242+
totalTime = calculatedTotalTime.toInt(),
242243
transferCount = transferCount,
243244
walkDistance = walkDistance,
244245
walkTime = walkTime,

data/src/main/java/com/stop/data/repository/RouteRepositoryImpl.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ internal class RouteRepositoryImpl @Inject constructor(
4141
remoteDataSource.getSubwayStationCd(stationId, stationName)
4242
} catch (exception: JsonDataException) {
4343
""
44+
} catch (exception: IllegalArgumentException) {
45+
exception.printStackTrace()
46+
""
4447
}
4548
}
4649

domain/src/main/java/com/stop/domain/usecase/route/GetRouteUseCaseImpl.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ internal class GetRouteUseCaseImpl @Inject constructor(
9595
}
9696

9797
private fun calculateProportionOfSectionTime(sectionTime: Double, totalTime: Int): Float {
98-
return (sectionTime / totalTime * 100).toInt().toFloat() / 100
98+
return (sectionTime / totalTime * 10_000).toInt().toFloat() / 10000
9999
}
100100

101101
private fun createCoordinates(linesString: String): List<Coordinate> {

presentation/src/main/java/com/stop/ui/alarmsetting/AlarmSettingFragment.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ class AlarmSettingFragment : Fragment() {
9898
val alarmUseCaseItem = AlarmUseCaseItem(
9999
startPosition = routeResultViewModel.origin.value?.name ?: "",
100100
endPosition = routeResultViewModel.destination.value?.name ?: "",
101-
routes = itinerary.routes,
101+
routes = itinerary.routes.first(),
102102
lastTime = transportLastTime.timeToBoard,
103103
walkTime = (itinerary.routes.first().sectionTime.div(60)).roundToInt(),
104104
0,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class RouteAdapter(
4040
oldItinerary: Itinerary,
4141
newItinerary: Itinerary
4242
): Boolean {
43-
return oldItinerary.totalTime == newItinerary.totalTime
43+
return oldItinerary.totalDistance == newItinerary.totalDistance
4444
}
4545

4646
override fun areContentsTheSame(

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

Lines changed: 0 additions & 44 deletions
This file was deleted.

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

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,18 @@ class RouteFragment : Fragment() {
2929
private val routeViewModel: RouteViewModel by activityViewModels()
3030
private val routeResultViewModel: RouteResultViewModel by navGraphViewModels(R.id.route_nav_graph)
3131

32-
private val args: RouteFragmentArgs by navArgs()
32+
private var args: RouteFragmentArgs? = null
3333

3434
private lateinit var adapter: RouteAdapter
3535
private lateinit var backPressedCallback: OnBackPressedCallback
36-
private var progressDialog: AlertDialog? = null
36+
private lateinit var alertDialog: AlertDialog
37+
38+
override fun onCreate(savedInstanceState: Bundle?) {
39+
super.onCreate(savedInstanceState)
40+
41+
val currentArgs: RouteFragmentArgs by navArgs()
42+
args = currentArgs
43+
}
3744

3845
override fun onCreateView(
3946
inflater: LayoutInflater, container: ViewGroup?,
@@ -46,7 +53,7 @@ class RouteFragment : Fragment() {
4653
override fun onAttach(context: Context) {
4754
super.onAttach(context)
4855

49-
backPressedCallback = object: OnBackPressedCallback(true) {
56+
backPressedCallback = object : OnBackPressedCallback(true) {
5057
override fun handleOnBackPressed() {
5158
val navController = findNavController()
5259
navController.setGraph(R.navigation.nav_graph)
@@ -63,8 +70,8 @@ class RouteFragment : Fragment() {
6370
setListener()
6471
setRecyclerView()
6572
setStartAndDestinationText()
66-
setObserve()
6773
initDialog()
74+
setObserve()
6875
}
6976

7077
private fun setBinding() {
@@ -83,16 +90,23 @@ class RouteFragment : Fragment() {
8390
navController.setGraph(R.navigation.nav_graph)
8491
navController.navigate(R.id.action_global_placeSearchFragment)
8592
}
93+
binding.imageViewSwapOriginWithDestination.setOnClickListener {
94+
routeViewModel.changeOriginAndDestination()
95+
}
96+
binding.imageViewExit.setOnClickListener {
97+
val navController = findNavController()
98+
navController.setGraph(R.navigation.nav_graph)
99+
navController.popBackStack(R.id.mapFragment, false)
100+
}
101+
binding.imageViewResearch.setOnClickListener {
102+
routeViewModel.getRoute()
103+
}
86104
}
87105

88106
private fun setRecyclerView() {
89107
adapter = RouteAdapter(object : OnItineraryClickListener {
90108
override fun onItineraryClick(itinerary: Itinerary) {
91-
/**
92-
* UI가 ViewModel을 직접 호출하면 안 되지만, 테스트를 위해 막차 조회 함수를 호출했습니다.
93-
* 여기서 UI가 ViewModel을 직접 호출하지 않으면서 막차 조회 함수를 호출할 수 있을까요?
94-
*/
95-
progressDialog?.show()
109+
alertDialog.show()
96110
routeViewModel.calculateLastTransportTime(itinerary)
97111
routeResultViewModel.setItineraries(itinerary)
98112
}
@@ -121,35 +135,57 @@ class RouteFragment : Fragment() {
121135
routeResultViewModel.setLastTimes(response)
122136
routeResultViewModel.setOrigin(routeViewModel.origin.value)
123137
routeResultViewModel.setDestination(routeViewModel.destination.value)
124-
progressDialog?.dismiss()
138+
alertDialog.dismiss()
125139

126140
binding.root.findNavController()
127141
.navigate(R.id.action_routeFragment_to_routeDetailFragment)
128142
}
129143
}
144+
routeViewModel.isLoading.observe(viewLifecycleOwner) {
145+
it.getContentIfNotHandled()?.let { isLoading ->
146+
if (isLoading) {
147+
alertDialog.show()
148+
return@let
149+
}
150+
alertDialog.dismiss()
151+
}
152+
}
130153
}
131154

132155
private fun setStartAndDestinationText() {
133-
args.start?.let {
156+
args?.start?.let {
134157
routeViewModel.setOrigin(it)
135158
}
136-
args.end?.let {
159+
args?.end?.let {
137160
routeViewModel.setDestination(it)
138161
}
139-
routeViewModel.getRoute()
162+
163+
requireArguments().clear()
164+
165+
if (args?.start != null || args?.end != null) {
166+
routeViewModel.getRoute()
167+
}
140168
}
141169

142170
private fun initDialog() {
171+
val viewModelDialog = routeViewModel.alertDialog
172+
if (viewModelDialog != null) {
173+
alertDialog = viewModelDialog
174+
return
175+
}
176+
143177
val dialogView = layoutInflater.inflate(R.layout.dialog_progress, null)
144-
progressDialog = AlertDialog.Builder(requireContext())
145-
.setView(dialogView)
146-
.setCancelable(false)
147-
.create()
148-
progressDialog?.window?.setBackgroundDrawableResource(R.color.transparent)
178+
alertDialog = AlertDialog.Builder(requireContext())
179+
.setView(dialogView)
180+
.setCancelable(false)
181+
.create()
182+
alertDialog.window?.setBackgroundDrawableResource(R.color.transparent)
183+
routeViewModel.alertDialog = alertDialog
149184
}
150185

151186
override fun onDestroyView() {
152187
_binding = null
188+
args = null
153189

154190
super.onDestroyView()
155191
}

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

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package com.stop.ui.route
22

33
import android.graphics.Color
4+
import android.view.View
5+
import android.view.ViewGroup
46
import androidx.core.content.ContextCompat
7+
import androidx.core.view.updateLayoutParams
58
import androidx.recyclerview.widget.RecyclerView
69
import com.stop.R
710
import com.stop.databinding.RouteItemBinding
@@ -13,16 +16,11 @@ class RouteViewHolder(
1316
private val binding: RouteItemBinding
1417
) : RecyclerView.ViewHolder(binding.root) {
1518

16-
private val adapter = RouteDetailAdapter()
17-
var routeItemColor = 0
18-
19-
init {
20-
binding.recyclerviewTimeLine.adapter = adapter
21-
binding.recyclerviewTimeLine.setHasFixedSize(true)
22-
}
19+
private val density = binding.root.context.resources.displayMetrics.density
20+
private var routeItemColor = 0
2321

2422
fun bind(itinerary: Itinerary) {
25-
binding.textViewExpectedRequiredTime.text = secondToHourAndMinute(itinerary.totalTime)
23+
setRequireTime(itinerary.totalTime)
2624
val routeItems = mutableListOf<RouteItem>()
2725

2826
itinerary.routes.drop(1).forEachIndexed { index, route ->
@@ -50,10 +48,12 @@ class RouteViewHolder(
5048
)
5149
)
5250
}
53-
adapter.submitList(routeItems)
54-
binding.timeLineContainer.post {
55-
binding.timeLineContainer.submitList(itinerary.routes)
56-
}
51+
binding.stationContainer.removeAllViewsInLayout()
52+
53+
binding.timeLineContainer.removeAllViewsInLayout()
54+
55+
binding.stationContainer.submitList(routeItems.toList())
56+
binding.timeLineContainer.submitList(itinerary.routes)
5757
}
5858

5959
private fun getRouteItemDistance(route: Route): Double {
@@ -89,11 +89,12 @@ class RouteViewHolder(
8989

9090
private fun getRouteItemColor(route: Route, isCurrent: Boolean): Int {
9191
return if (isCurrent) {
92-
when (route) {
92+
routeItemColor = when (route) {
9393
is TransportRoute -> Color.parseColor("#${route.routeColor}")
9494
is WalkRoute -> ContextCompat.getColor(binding.root.context, R.color.main_yellow)
9595
else -> ContextCompat.getColor(binding.root.context, R.color.main_lighter_grey)
9696
}
97+
routeItemColor
9798
} else {
9899
if (routeItemColor != 0) {
99100
routeItemColor
@@ -112,7 +113,26 @@ class RouteViewHolder(
112113
}
113114
}
114115

115-
private fun secondToHourAndMinute(second: Int): String {
116-
return "${second / 60 / 60}시간 ${second / 60 % 60}"
116+
private fun setRequireTime(second: Int) {
117+
val hour = second / 60 / 60
118+
val minute = second / 60 % 60
119+
if (hour != 0) {
120+
binding.textViewRequiredHour.visibility = View.VISIBLE
121+
binding.textViewRequiredHourText.visibility = View.VISIBLE
122+
123+
binding.textViewRequiredHour.text = hour.toString()
124+
binding.textViewRequiredMinute.updateLayoutParams<ViewGroup.MarginLayoutParams> {
125+
setMargins(convertDpToPixel(5f), 0, 0, 0)
126+
}
127+
} else {
128+
binding.textViewRequiredHour.visibility = View.GONE
129+
binding.textViewRequiredHourText.visibility = View.GONE
130+
}
131+
132+
binding.textViewRequiredMinute.text = minute.toString()
133+
}
134+
135+
private fun convertDpToPixel(size: Float): Int {
136+
return (size * density + 0.5f).toInt()
117137
}
118138
}

0 commit comments

Comments
 (0)