Skip to content

Commit a5d0de2

Browse files
authored
Merge pull request #60 from woowacourse-teams/feature/#57
[feat] ๊ด‘์—ญ์‹œ / ๋„ ๋‘˜๋Ÿฌ๋ณด๊ธฐ ๋„๋ฉ”์ธ ๋ฐ ๋ทฐ ๊ตฌํ˜„
2 parents 06ede22 + 5aaa30f commit a5d0de2

13 files changed

Lines changed: 264 additions & 11 deletions

File tree

โ€Žandroid/app/build.gradle.ktsโ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ dependencies {
5555
implementation(libs.androidx.activity)
5656
implementation(libs.androidx.constraintlayout)
5757
testImplementation(libs.junit)
58+
testImplementation(libs.assertj.core)
5859
androidTestImplementation(libs.androidx.junit)
5960
androidTestImplementation(libs.androidx.espresso.core)
6061
// coroutine

โ€Žandroid/app/src/main/java/com/on/turip/domain/.gitkeepโ€Ž

Whitespace-only changes.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.on.turip.domain.region
2+
3+
enum class Region(
4+
private val regionType: RegionType,
5+
) {
6+
SEOUL(RegionType.METROPOLITAN_CITY),
7+
BUSAN(RegionType.METROPOLITAN_CITY),
8+
DAEGU(RegionType.METROPOLITAN_CITY),
9+
INCHEON(RegionType.METROPOLITAN_CITY),
10+
GWANGJU(RegionType.METROPOLITAN_CITY),
11+
DAEJEON(RegionType.METROPOLITAN_CITY),
12+
ULSAN(RegionType.METROPOLITAN_CITY),
13+
SEJONG(RegionType.METROPOLITAN_CITY),
14+
GYEONGGI(RegionType.PROVINCE),
15+
GANGWON(RegionType.PROVINCE),
16+
CHUNGCHEONGBUK(RegionType.PROVINCE),
17+
CHUNGCHEONGNAM(RegionType.PROVINCE),
18+
JEOLLABUK(RegionType.PROVINCE),
19+
JEOLLANAM(RegionType.PROVINCE),
20+
GYEONGSANGBUK(RegionType.PROVINCE),
21+
GYEONGSANGNAM(RegionType.PROVINCE),
22+
JEJU(RegionType.METROPOLITAN_CITY),
23+
;
24+
25+
companion object {
26+
fun from(regionType: RegionType): List<Region> = Region.entries.filter { it.regionType == regionType }
27+
}
28+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.on.turip.domain.region
2+
3+
enum class RegionType {
4+
METROPOLITAN_CITY,
5+
PROVINCE,
6+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.on.turip.ui.common.model
2+
3+
import com.on.turip.domain.region.Region
4+
5+
enum class RegionModel(
6+
val korean: String,
7+
val english: String,
8+
private val origin: Region,
9+
) {
10+
SEOUL("์„œ์šธ", "seoul", Region.SEOUL),
11+
BUSAN("๋ถ€์‚ฐ", "busan", Region.BUSAN),
12+
DAEGU("๋Œ€๊ตฌ", "daegu", Region.DAEGU),
13+
INCHEON("์ธ์ฒœ", "incheon", Region.INCHEON),
14+
GWANGJU("๊ด‘์ฃผ", "gwangju", Region.GWANGJU),
15+
DAEJEON("๋Œ€์ „", "daejeon", Region.DAEJEON),
16+
ULSAN("์šธ์‚ฐ", "ulsan", Region.ULSAN),
17+
SEJONG("์„ธ์ข…", "sejong", Region.SEJONG),
18+
GYEONGGI("๊ฒฝ๊ธฐ", "gyeonggi", Region.GYEONGGI),
19+
GANGWON("๊ฐ•์›", "gangwon", Region.GANGWON),
20+
CHUNGCHEONGBUK("์ถฉ๋ถ", "chungcheongbuk", Region.CHUNGCHEONGBUK),
21+
CHUNGCHEONGNAM("์ถฉ๋‚จ", "chungcheongnam", Region.CHUNGCHEONGNAM),
22+
JEOLLABUK("์ „๋ถ", "jeollabuk", Region.JEOLLABUK),
23+
JEOLLANAM("์ „๋‚จ", "jeollanam", Region.JEOLLANAM),
24+
GYEONGSANGBUK("๊ฒฝ๋ถ", "gyeongsangbuk", Region.GYEONGSANGBUK),
25+
GYEONGSANGNAM("๊ฒฝ๋‚จ", "gyeongsangnam", Region.GYEONGSANGNAM),
26+
JEJU("์ œ์ฃผ", "jeju", Region.JEJU),
27+
;
28+
29+
companion object {
30+
fun find(region: Region): RegionModel =
31+
RegionModel.entries.find { it.origin == region }
32+
?: throw IllegalArgumentException("ํ•ด๋‹น $region ์— ์ผ์น˜ํ•˜๋Š” Model์ด ์—†์Šต๋‹ˆ๋‹ค.")
33+
}
34+
}

โ€Žandroid/app/src/main/java/com/on/turip/ui/main/MainActivity.ktโ€Ž

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import androidx.core.content.ContextCompat
99
import com.on.turip.R
1010
import com.on.turip.databinding.ActivityMainBinding
1111
import com.on.turip.ui.common.base.BaseActivity
12+
import com.on.turip.ui.common.model.RegionModel
1213

1314
class MainActivity : BaseActivity<MainViewModel, ActivityMainBinding>() {
1415
override val viewModel: MainViewModel by viewModels()
@@ -17,10 +18,29 @@ class MainActivity : BaseActivity<MainViewModel, ActivityMainBinding>() {
1718
ActivityMainBinding.inflate(layoutInflater)
1819
}
1920

21+
private val metropolitanCitiesAdapter: RegionAdapter =
22+
RegionAdapter(
23+
object : RegionViewHolder.OnRegionListener {
24+
override fun onRegionClick(region: RegionModel) {
25+
// TODO: ์ง€์—ญ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ๋ทฐ๋กœ ์ด๋™
26+
}
27+
},
28+
)
29+
private val provincesAdapter: RegionAdapter =
30+
RegionAdapter(
31+
object : RegionViewHolder.OnRegionListener {
32+
override fun onRegionClick(region: RegionModel) {
33+
// TODO: ์ง€์—ญ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ๋ทฐ๋กœ ์ด๋™
34+
}
35+
},
36+
)
37+
2038
override fun onCreate(savedInstanceState: Bundle?) {
2139
super.onCreate(savedInstanceState)
2240

2341
setupTextHighlighting()
42+
setupAdapters()
43+
setupObservers()
2444
}
2545

2646
private fun setupTextHighlighting() {
@@ -46,4 +66,19 @@ class MainActivity : BaseActivity<MainViewModel, ActivityMainBinding>() {
4666

4767
binding.tvMainWhereShouldWeGoTitle.text = spannableText
4868
}
69+
70+
private fun setupAdapters() {
71+
binding.rvMainMetropolitanCity.adapter = metropolitanCitiesAdapter
72+
binding.rvMainProvince.adapter = provincesAdapter
73+
}
74+
75+
private fun setupObservers() {
76+
viewModel.metropolitanCities.observe(this) { metropolitanCities: List<RegionModel> ->
77+
metropolitanCitiesAdapter.submitList(metropolitanCities)
78+
}
79+
80+
viewModel.provinces.observe(this) { provinces: List<RegionModel> ->
81+
provincesAdapter.submitList(provinces)
82+
}
83+
}
4984
}
Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
package com.on.turip.ui.main
22

3+
import androidx.lifecycle.LiveData
34
import androidx.lifecycle.ViewModel
5+
import androidx.lifecycle.liveData
6+
import com.on.turip.domain.region.Region
7+
import com.on.turip.domain.region.RegionType
8+
import com.on.turip.ui.common.model.RegionModel
49

5-
class MainViewModel : ViewModel()
10+
class MainViewModel : ViewModel() {
11+
val metropolitanCities: LiveData<List<RegionModel>> =
12+
liveData {
13+
val metropolitans: List<Region> = Region.from(RegionType.METROPOLITAN_CITY)
14+
emit(metropolitans.map(RegionModel::find))
15+
}
16+
17+
val provinces: LiveData<List<RegionModel>> =
18+
liveData {
19+
val provinces: List<Region> = Region.from(RegionType.PROVINCE)
20+
emit(provinces.map(RegionModel::find))
21+
}
22+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.on.turip.ui.main
2+
3+
import android.view.ViewGroup
4+
import androidx.recyclerview.widget.DiffUtil
5+
import androidx.recyclerview.widget.ListAdapter
6+
import com.on.turip.ui.common.model.RegionModel
7+
8+
class RegionAdapter(
9+
private val onRegionListener: RegionViewHolder.OnRegionListener,
10+
) : ListAdapter<RegionModel, RegionViewHolder>(
11+
RegionDiffUtil,
12+
) {
13+
override fun onCreateViewHolder(
14+
parent: ViewGroup,
15+
viewType: Int,
16+
): RegionViewHolder = RegionViewHolder.of(parent, onRegionListener)
17+
18+
override fun onBindViewHolder(
19+
holder: RegionViewHolder,
20+
position: Int,
21+
): Unit = holder.bind(getItem(position))
22+
23+
private object RegionDiffUtil : DiffUtil.ItemCallback<RegionModel>() {
24+
override fun areItemsTheSame(
25+
oldItem: RegionModel,
26+
newItem: RegionModel,
27+
): Boolean = oldItem.english == newItem.english
28+
29+
override fun areContentsTheSame(
30+
oldItem: RegionModel,
31+
newItem: RegionModel,
32+
): Boolean = oldItem == newItem
33+
}
34+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.on.turip.ui.main
2+
3+
import android.view.LayoutInflater
4+
import android.view.ViewGroup
5+
import androidx.recyclerview.widget.RecyclerView
6+
import com.on.turip.databinding.ItemSearchingRegionBinding
7+
import com.on.turip.ui.common.model.RegionModel
8+
9+
class RegionViewHolder(
10+
private val binding: ItemSearchingRegionBinding,
11+
onRegionListener: OnRegionListener,
12+
) : RecyclerView.ViewHolder(binding.root) {
13+
private var region: RegionModel? = null
14+
15+
init {
16+
binding.root.setOnClickListener {
17+
region?.let { onRegionListener.onRegionClick(it) }
18+
}
19+
}
20+
21+
fun bind(region: RegionModel) {
22+
this.region = region
23+
binding.tvSearchingRegion.text = region.korean
24+
}
25+
26+
companion object {
27+
fun of(
28+
parent: ViewGroup,
29+
onRegionListener: OnRegionListener,
30+
): RegionViewHolder {
31+
val inflater: LayoutInflater = LayoutInflater.from(parent.context)
32+
val binding: ItemSearchingRegionBinding =
33+
ItemSearchingRegionBinding.inflate(inflater, parent, false)
34+
return RegionViewHolder(binding, onRegionListener)
35+
}
36+
}
37+
38+
fun interface OnRegionListener {
39+
fun onRegionClick(region: RegionModel)
40+
}
41+
}

โ€Žandroid/app/src/main/res/layout/activity_main.xmlโ€Ž

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
android:layout_height="wrap_content"
2626
android:layout_marginTop="30dp"
2727
android:text="@string/main_where_should_we_go_title"
28-
android:textAppearance="@style/title1"
28+
android:textAppearance="@style/display"
2929
android:textColor="@color/gray_500_1e1e1e"
3030
app:layout_constraintStart_toStartOf="@id/iv_main_logo"
3131
app:layout_constraintTop_toBottomOf="@id/iv_main_logo" />
@@ -36,7 +36,7 @@
3636
android:layout_height="wrap_content"
3737
android:layout_marginTop="28dp"
3838
android:text="@string/main_searching_metropolitan_city"
39-
android:textAppearance="@style/title2"
39+
android:textAppearance="@style/title1"
4040
android:textColor="@color/gray_400_2b2b2b"
4141
app:layout_constraintStart_toStartOf="@id/tv_main_where_should_we_go_title"
4242
app:layout_constraintTop_toBottomOf="@id/tv_main_where_should_we_go_title" />
@@ -49,34 +49,38 @@
4949
android:clipToPadding="false"
5050
android:orientation="horizontal"
5151
android:paddingVertical="20dp"
52+
android:paddingStart="20dp"
5253
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
5354
app:layout_constraintEnd_toEndOf="parent"
54-
app:layout_constraintStart_toStartOf="@id/tv_main_searching_metropolitan_city"
55+
app:layout_constraintStart_toStartOf="parent"
5556
app:layout_constraintTop_toBottomOf="@id/tv_main_searching_metropolitan_city"
56-
tools:listitem="@layout/item_searching_region" />
57+
tools:listitem="@layout/item_searching_region"
58+
tools:ignore="RtlSymmetry" />
5759

5860
<TextView
5961
android:id="@+id/tv_main_searching_province"
6062
android:layout_width="wrap_content"
6163
android:layout_height="wrap_content"
6264
android:layout_marginTop="2dp"
6365
android:text="@string/main_searching_province"
64-
android:textAppearance="@style/title2"
66+
android:textAppearance="@style/title1"
6567
android:textColor="@color/gray_400_2b2b2b"
66-
app:layout_constraintStart_toStartOf="@id/rv_main_metropolitan_city"
68+
app:layout_constraintStart_toStartOf="@id/tv_main_searching_metropolitan_city"
6769
app:layout_constraintTop_toBottomOf="@id/rv_main_metropolitan_city" />
6870

6971
<androidx.recyclerview.widget.RecyclerView
70-
android:id="@+id/rv_main_searching_province"
72+
android:id="@+id/rv_main_province"
7173
android:layout_width="0dp"
7274
android:layout_height="wrap_content"
7375
android:layout_marginTop="2dp"
7476
android:clipToPadding="false"
7577
android:orientation="horizontal"
7678
android:paddingVertical="20dp"
79+
android:paddingStart="20dp"
7780
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
7881
app:layout_constraintEnd_toEndOf="parent"
79-
app:layout_constraintStart_toStartOf="@id/tv_main_searching_province"
82+
app:layout_constraintStart_toStartOf="parent"
8083
app:layout_constraintTop_toBottomOf="@id/tv_main_searching_province"
84+
tools:ignore="RtlSymmetry"
8185
tools:listitem="@layout/item_searching_region" />
8286
</androidx.constraintlayout.widget.ConstraintLayout>

0 commit comments

Comments
ย (0)