Skip to content

Commit f3f8505

Browse files
committed
과정 저장용: child Layout에 constraint가 적용되지 않음
1 parent 7654f6a commit f3f8505

File tree

10 files changed

+471
-36
lines changed

10 files changed

+471
-36
lines changed

presentation/src/main/java/com/stop/model/route/RouteItem.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ data class RouteItem(
1111
val lastTime: String?,
1212
val beforeColor: Int,
1313
val currentColor: Int,
14-
val type: RouteItemType
14+
val type: RouteItemType,
15+
val typeName: String = "",
1516
)
1617

1718
fun RouteItem.toFirstRouteItem(): RouteItem {
@@ -20,7 +21,10 @@ fun RouteItem.toFirstRouteItem(): RouteItem {
2021
)
2122
}
2223

23-
fun RouteItem.toLastRouteItem(name: String, coordinate: com.stop.model.route.Coordinate): RouteItem {
24+
fun RouteItem.toLastRouteItem(
25+
name: String,
26+
coordinate: com.stop.model.route.Coordinate
27+
): RouteItem {
2428
return this.copy(
2529
name = name,
2630
coordinate = Coordinate(coordinate.latitude, coordinate.longitude),
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.stop.ui.route
2+
3+
import android.view.LayoutInflater
4+
import android.view.ViewGroup
5+
import androidx.recyclerview.widget.DiffUtil
6+
import androidx.recyclerview.widget.ListAdapter
7+
import androidx.recyclerview.widget.RecyclerView
8+
import com.stop.databinding.RoutePathAtTimeLineItemBinding
9+
import com.stop.model.route.RouteItem
10+
11+
class RouteDetailAdapter : ListAdapter<RouteItem, RouteDetailAdapter.PathViewHolder>(diffUtil) {
12+
13+
class PathViewHolder(
14+
private val binding: RoutePathAtTimeLineItemBinding
15+
) : RecyclerView.ViewHolder(binding.root) {
16+
17+
fun bind(routeItem: RouteItem) {
18+
binding.routeItem = routeItem
19+
}
20+
}
21+
22+
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PathViewHolder {
23+
val inflater = LayoutInflater.from(parent.context)
24+
val binding = RoutePathAtTimeLineItemBinding.inflate(inflater, parent, false)
25+
26+
return PathViewHolder(binding)
27+
}
28+
29+
override fun onBindViewHolder(holder: PathViewHolder, position: Int) {
30+
holder.bind(getItem(position))
31+
}
32+
33+
companion object {
34+
private val diffUtil = object : DiffUtil.ItemCallback<RouteItem>() {
35+
override fun areItemsTheSame(oldItem: RouteItem, newItem: RouteItem): Boolean {
36+
return oldItem.name == newItem.name
37+
}
38+
39+
override fun areContentsTheSame(oldItem: RouteItem, newItem: RouteItem): Boolean {
40+
return oldItem == newItem
41+
}
42+
}
43+
}
44+
}

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

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
package com.stop.ui.route
22

3+
import android.graphics.Color
34
import android.graphics.Rect
45
import android.view.View
6+
import androidx.core.content.ContextCompat
57
import androidx.recyclerview.widget.RecyclerView
8+
import com.stop.R
69
import com.stop.databinding.RouteItemBinding
7-
import com.stop.domain.model.route.tmap.custom.Itinerary
10+
import com.stop.domain.model.route.tmap.custom.*
11+
import com.stop.model.route.RouteItem
12+
import com.stop.model.route.RouteItemType
813

914
class RouteViewHolder(
1015
private val binding: RouteItemBinding
1116
) : RecyclerView.ViewHolder(binding.root) {
1217

13-
private val adapter = TimeLineAdapter()
18+
private val adapter = RouteDetailAdapter()
19+
var routeItemColor = 0
1420

1521
init {
1622
binding.recyclerviewTimeLine.adapter = adapter
@@ -31,8 +37,67 @@ class RouteViewHolder(
3137

3238
fun bind(itinerary: Itinerary) {
3339
binding.textViewExpectedRequiredTime.text = secondToHourAndMinute(itinerary.totalTime)
40+
val routeItems = mutableListOf<RouteItem>()
3441

35-
adapter.submitList(itinerary.routes)
42+
itinerary.routes.forEach { route ->
43+
routeItems.add(
44+
RouteItem(
45+
name = route.start.name,
46+
coordinate = route.start.coordinate,
47+
mode = getRouteItemMode(route),
48+
distance = route.distance,
49+
travelTime = route.sectionTime.toInt(),
50+
lastTime = "",
51+
beforeColor = getRouteItemColor(route, false),
52+
currentColor = getRouteItemColor(route, true),
53+
type = RouteItemType.PATH,
54+
typeName = getTypeName(route),
55+
)
56+
)
57+
}
58+
adapter.submitList(routeItems)
59+
binding.timeLineContainer.submitList(itinerary.routes)
60+
}
61+
62+
private fun getTypeName(route: Route): String {
63+
return when(route) {
64+
is WalkRoute -> "도보"
65+
is TransportRoute -> getSubwayTypeName(route)
66+
else -> ""
67+
}
68+
}
69+
70+
private fun getSubwayTypeName(route: TransportRoute): String {
71+
return when(route.mode) {
72+
MoveType.SUBWAY -> route.routeInfo.replace("수도권", "")
73+
MoveType.BUS -> route.routeInfo.split(":")[1]
74+
else -> route.routeInfo
75+
}
76+
}
77+
78+
private fun getRouteItemColor(route: Route, isCurrent: Boolean): Int {
79+
return if (isCurrent) {
80+
when (route) {
81+
is TransportRoute -> Color.parseColor("#${route.routeColor}")
82+
is WalkRoute -> ContextCompat.getColor(binding.root.context, R.color.main_yellow)
83+
else -> ContextCompat.getColor(binding.root.context, R.color.main_lighter_grey)
84+
}
85+
} else {
86+
if (routeItemColor != 0) {
87+
routeItemColor
88+
} else {
89+
getRouteItemColor(route, true)
90+
}
91+
}
92+
}
93+
94+
private fun getRouteItemMode(route: Route): Int {
95+
return when (route.mode) {
96+
MoveType.WALK, MoveType.TRANSFER -> R.drawable.ic_walk_white
97+
MoveType.BUS -> R.drawable.ic_bus_white
98+
MoveType.SUBWAY -> R.drawable.ic_subway_white
99+
else -> R.drawable.ic_star_white
100+
}
36101
}
37102

38103
private fun secondToHourAndMinute(second: Int): String {
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package com.stop.ui.route
2+
3+
import android.content.Context
4+
import android.content.res.ColorStateList
5+
import android.graphics.Color
6+
import android.transition.TransitionManager
7+
import android.util.AttributeSet
8+
import android.view.LayoutInflater
9+
import android.view.View
10+
import androidx.constraintlayout.widget.ConstraintLayout
11+
import androidx.constraintlayout.widget.ConstraintSet
12+
import androidx.core.content.ContextCompat
13+
import com.stop.R
14+
import com.stop.databinding.TimeLineItem2Binding
15+
import com.stop.domain.model.route.tmap.custom.MoveType
16+
import com.stop.domain.model.route.tmap.custom.Route
17+
import com.stop.domain.model.route.tmap.custom.TransportRoute
18+
import kotlinx.coroutines.CoroutineScope
19+
20+
class TimeLineContainer(
21+
context: Context,
22+
attrs: AttributeSet? = null,
23+
) : ConstraintLayout(context, attrs) {
24+
25+
private val greyColor =
26+
ContextCompat.getColor(context, R.color.grey_for_route_walk)
27+
private var beforeViewIconId: Int? = null
28+
29+
fun submitList(routes: List<Route>) {
30+
routes.forEachIndexed { index, route ->
31+
32+
val timeLineItem2Binding = TimeLineItem2Binding.inflate(
33+
LayoutInflater.from(context),
34+
this,
35+
false,
36+
).apply {
37+
root.id = View.generateViewId()
38+
}
39+
// this.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
40+
addView(timeLineItem2Binding.root)
41+
setBindingAttribute(timeLineItem2Binding, route, index)
42+
TransitionManager.beginDelayedTransition(this@TimeLineContainer)
43+
}
44+
}
45+
46+
private fun setBindingAttribute(binding: TimeLineItem2Binding, route: Route, index: Int) {
47+
48+
val text = binding.root.resources.getString(
49+
R.string.section_time,
50+
(route.sectionTime / 60).toInt().toString()
51+
)
52+
binding.textViewSectionTime.text = text
53+
54+
val imageSrc = when (route.mode) {
55+
MoveType.BUS -> R.drawable.time_line_bus_16
56+
MoveType.SUBWAY -> R.drawable.time_line_subway_16
57+
MoveType.WALK, MoveType.TRANSFER -> {
58+
if (index != 0) {
59+
setDefaultColor(binding)
60+
binding.viewIcon.visibility = View.GONE
61+
binding.imageViewIcon.visibility = View.GONE
62+
return
63+
}
64+
R.drawable.time_line_directions_walk_16
65+
}
66+
else -> R.drawable.time_line_help_16
67+
}
68+
binding.viewIcon.visibility = View.VISIBLE
69+
binding.imageViewIcon.visibility = View.VISIBLE
70+
71+
val drawable = ContextCompat.getDrawable(binding.root.context, imageSrc)
72+
?: throw IllegalArgumentException()
73+
74+
binding.imageViewIcon.setImageDrawable(drawable)
75+
76+
when (route) {
77+
is TransportRoute -> setIdentityColor(binding, route)
78+
else -> setDefaultColor(binding)
79+
}
80+
81+
setWidth(binding, route.proportionOfSectionTime)
82+
setConstraint(binding)
83+
}
84+
85+
// viewIcon 위주로 설정하면 됨
86+
private fun setConstraint(binding: TimeLineItem2Binding) {
87+
val endId = beforeViewIconId ?: this@TimeLineContainer.id
88+
val endSide = if (beforeViewIconId == null) {
89+
ConstraintSet.START
90+
} else {
91+
ConstraintSet.END
92+
}
93+
TransitionManager.beginDelayedTransition(this@TimeLineContainer)
94+
95+
with(ConstraintSet()) {
96+
clone(binding.root)
97+
connect(binding.root.id, ConstraintSet.START, endId, endSide)
98+
connect(binding.root.id, ConstraintSet.TOP, this@TimeLineContainer.id, ConstraintSet.TOP)
99+
connect(binding.root.id, ConstraintSet.BOTTOM, this@TimeLineContainer.id, ConstraintSet.BOTTOM)
100+
applyTo(binding.root)
101+
}
102+
beforeViewIconId = binding.root.id
103+
}
104+
105+
private fun setWidth(
106+
binding: TimeLineItem2Binding,
107+
proportionOfSectionTime: Float
108+
) {
109+
this.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
110+
111+
val layoutParams = binding.root.layoutParams
112+
layoutParams.width = (this.measuredWidth * proportionOfSectionTime).toInt()
113+
}
114+
115+
private fun setIdentityColor(binding: TimeLineItem2Binding, route: TransportRoute) {
116+
val identityColor = Color.parseColor("#${route.routeColor}")
117+
binding.textViewSectionTime.setBackgroundColor(identityColor)
118+
binding.textViewSectionTime.setTextColor(Color.WHITE)
119+
binding.viewIcon.background.setTint(identityColor)
120+
binding.imageViewIcon.imageTintList = ColorStateList.valueOf(Color.WHITE)
121+
}
122+
123+
private fun setDefaultColor(binding: TimeLineItem2Binding) {
124+
binding.textViewSectionTime.setTextColor(Color.WHITE)
125+
binding.textViewSectionTime.setBackgroundColor(greyColor)
126+
127+
val drawable =
128+
ContextCompat.getDrawable(binding.root.context, R.drawable.time_stick_round_background)
129+
?: throw IllegalArgumentException()
130+
binding.viewIcon.background = drawable
131+
binding.viewIcon.background.setTintList(null)
132+
}
133+
}

presentation/src/main/java/com/stop/ui/util/DrawerStringUtils.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.stop.ui.util
22

3-
import com.stop.domain.model.route.seoul.subway.StationLastTime
43
import com.stop.domain.model.route.tmap.custom.Itinerary
54
import com.stop.model.route.RouteItem
65
import java.text.DecimalFormat

presentation/src/main/res/layout/route_item.xml

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,26 @@
2727
app:layout_constraintTop_toTopOf="@id/guideline_start_horizontal"
2828
tools:text="1시간 10분" />
2929

30+
<com.stop.ui.route.TimeLineContainer
31+
android:id="@+id/time_line_container"
32+
android:layout_width="0dp"
33+
android:layout_height="wrap_content"
34+
app:layout_constraintEnd_toEndOf="@id/guideline_end_vertical"
35+
app:layout_constraintStart_toStartOf="@id/guideline_start_vertical"
36+
app:layout_constraintTop_toBottomOf="@id/text_view_required_time_text" />
37+
3038
<androidx.recyclerview.widget.RecyclerView
3139
android:id="@+id/recyclerview_time_line"
3240
android:layout_width="0dp"
3341
android:layout_height="wrap_content"
34-
android:orientation="horizontal"
35-
tools:listitem="@layout/time_line_item"
3642
android:layout_marginBottom="16dp"
37-
app:layout_constraintBottom_toBottomOf="parent"
43+
android:orientation="vertical"
3844
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
39-
app:layout_constraintTop_toBottomOf="@id/text_view_required_time_text"
45+
app:layout_constraintBottom_toBottomOf="parent"
4046
app:layout_constraintEnd_toStartOf="@id/guideline_end_vertical"
41-
app:layout_constraintStart_toStartOf="@id/guideline_start_vertical" />
47+
app:layout_constraintStart_toStartOf="@id/guideline_start_vertical"
48+
app:layout_constraintTop_toBottomOf="@id/time_line_container"
49+
tools:listitem="@layout/route_path_at_time_line_item" />
4250

4351
<androidx.constraintlayout.widget.Guideline
4452
android:id="@+id/guideline_start_vertical"

0 commit comments

Comments
 (0)