1717package com.duckduckgo.networkprotection.impl.settings.geoswitching
1818
1919import android.os.Bundle
20+ import android.view.LayoutInflater
21+ import android.widget.CompoundButton
2022import androidx.lifecycle.Lifecycle
2123import androidx.lifecycle.flowWithLifecycle
2224import androidx.lifecycle.lifecycleScope
2325import com.duckduckgo.anvil.annotations.ContributeToActivityStarter
2426import com.duckduckgo.anvil.annotations.InjectWith
2527import com.duckduckgo.common.ui.DuckDuckGoActivity
28+ import com.duckduckgo.common.ui.view.gone
29+ import com.duckduckgo.common.ui.view.show
2630import com.duckduckgo.common.ui.viewbinding.viewBinding
2731import com.duckduckgo.di.scopes.ActivityScope
2832import com.duckduckgo.navigation.api.GlobalActivityStarter
33+ import com.duckduckgo.networkprotection.impl.R
2934import com.duckduckgo.networkprotection.impl.databinding.ActivityNetpGeoswitchingBinding
35+ import com.duckduckgo.networkprotection.impl.databinding.ItemGeoswitchingCountryBinding
36+ import com.duckduckgo.networkprotection.impl.settings.geoswitching.NetpGeoSwitchingViewModel.CountryItem
3037import com.duckduckgo.networkprotection.impl.settings.geoswitching.NetpGeoSwitchingViewModel.ViewState
38+ import kotlinx.coroutines.flow.distinctUntilChanged
3139import kotlinx.coroutines.flow.launchIn
3240import kotlinx.coroutines.flow.onEach
3341
@@ -36,13 +44,12 @@ import kotlinx.coroutines.flow.onEach
3644class NetpGeoswitchingActivity : DuckDuckGoActivity () {
3745 private val binding: ActivityNetpGeoswitchingBinding by viewBinding()
3846 private val viewModel: NetpGeoSwitchingViewModel by bindViewModel()
39- private lateinit var adapter : NetpGeoswitchingAdapter
47+ private lateinit var lastSelectedButton : CompoundButton
4048
4149 override fun onCreate (savedInstanceState : Bundle ? ) {
4250 super .onCreate(savedInstanceState)
4351 setContentView(binding.root)
4452 setupToolbar(binding.includeToolbar.toolbar)
45- bindViews()
4653 observeViewModel()
4754 lifecycle.addObserver(viewModel)
4855 }
@@ -52,39 +59,118 @@ class NetpGeoswitchingActivity : DuckDuckGoActivity() {
5259 lifecycle.removeObserver(viewModel)
5360 }
5461
55- private fun bindViews () {
56- adapter = NetpGeoswitchingAdapter (
57- viewModel.getSelectedCountryCode(),
58- onItemMenuClicked = { country, cities ->
59- NetpGeoswitchingCityChoiceDialogFragment .instance(
60- country,
61- ArrayList (cities),
62- ).show(supportFragmentManager, TAG_DIALOG_CITY_CHOICE )
63- },
64- onCountrySelected = {
65- viewModel.onCountrySelected(it)
66- },
67- onNearestAvailableSelected = {
68- viewModel.onNearestAvailableCountrySelected()
69- },
70- )
71- binding.geoswitchingRecycler.adapter = adapter
62+ private fun onItemMenuClicked (
63+ country : String ,
64+ cities : List <String >,
65+ ) {
66+ NetpGeoswitchingCityChoiceDialogFragment .instance(
67+ country,
68+ ArrayList (cities),
69+ ).show(supportFragmentManager, TAG_DIALOG_CITY_CHOICE )
7270 }
7371
7472 private fun observeViewModel () {
7573 viewModel.viewState()
7674 .flowWithLifecycle(lifecycle, Lifecycle .State .STARTED )
75+ .distinctUntilChanged()
7776 .onEach { renderViewState(it) }
7877 .launchIn(lifecycleScope)
7978 }
8079
8180 private fun renderViewState (viewState : ViewState ) {
82- adapter.submitList(viewState.items)
81+ bindRecommendedItem(viewState.currentSelectedCountry)
82+
83+ if (viewState.items.isEmpty()) {
84+ binding.customListHeader.gone()
85+ } else {
86+ binding.customListHeader.show()
87+ }
88+
89+ viewState.items.forEach {
90+ val itemBinding = ItemGeoswitchingCountryBinding .inflate(
91+ LayoutInflater .from(binding.geoswitchingList.context),
92+ binding.geoswitchingList,
93+ false ,
94+ )
95+
96+ it.bindLocationItem(itemBinding, viewState.currentSelectedCountry)
97+ binding.geoswitchingList.addView(itemBinding.root)
98+ }
99+ }
100+
101+ private fun bindRecommendedItem (currentSelectedCountryCode : String? ) {
102+ with (binding.recommendedLocationItem) {
103+ // Sets initial state
104+ this .radioButton.isChecked = currentSelectedCountryCode.isNullOrEmpty()
105+
106+ if (currentSelectedCountryCode.isNullOrEmpty()) {
107+ lastSelectedButton = this .radioButton
108+ }
109+
110+ this .radioButton.setOnCheckedChangeListener { view, isChecked ->
111+ if (isChecked && view != lastSelectedButton) {
112+ lastSelectedButton.isChecked = false
113+ lastSelectedButton = view
114+ viewModel.onNearestAvailableCountrySelected()
115+ }
116+ }
117+ // Automatically selects the country when the item is clicked
118+ this .setClickListener {
119+ this .radioButton.isChecked = true
120+ }
121+ }
122+ }
123+
124+ private fun CountryItem.bindLocationItem (
125+ itemBinding : ItemGeoswitchingCountryBinding ,
126+ currentSelectedCountryCode : String? ,
127+ ) {
128+ // Sets initial state
129+ itemBinding.root.radioButton.isChecked = currentSelectedCountryCode == this .countryCode
130+ if (currentSelectedCountryCode == this .countryCode) {
131+ lastSelectedButton = itemBinding.root.radioButton
132+ }
133+
134+ itemBinding.root.setPrimaryText(this .countryName)
135+ itemBinding.root.setLeadingEmojiIcon(countryEmoji)
136+
137+ if (cities.size > 1 ) {
138+ itemBinding.root.setSecondaryText(
139+ String .format(
140+ this @NetpGeoswitchingActivity.getString(R .string.netpGeoswitchingHeaderCountrySubtitle),
141+ cities.size,
142+ ),
143+ )
144+ itemBinding.root.trailingIconContainer.show()
145+ itemBinding.root.setTrailingIconClickListener {
146+ // Automatically select the country before the user can choose the specific city
147+ itemBinding.root.radioButton.isChecked = true
148+ onItemMenuClicked(countryName, cities)
149+ }
150+ } else {
151+ itemBinding.root.secondaryText.gone()
152+ itemBinding.root.trailingIconContainer.gone()
153+ }
154+
155+ itemBinding.root.radioButton.setOnCheckedChangeListener { view, isChecked ->
156+ if (isChecked && view != lastSelectedButton) {
157+ lastSelectedButton.isChecked = false
158+ lastSelectedButton = view
159+ viewModel.onCountrySelected(this .countryCode)
160+ }
161+ }
162+
163+ // Automatically selects the country when the item is clicked
164+ itemBinding.root.setClickListener {
165+ itemBinding.root.radioButton.isChecked = true
166+ }
83167 }
84168
85169 companion object {
86170 private const val TAG_DIALOG_CITY_CHOICE = " DIALOG_CITY_CHOICE"
87171 }
88172}
89173
90- internal object NetpGeoswitchingScreenNoParams : GlobalActivityStarter.ActivityParams
174+ internal object NetpGeoswitchingScreenNoParams : GlobalActivityStarter.ActivityParams {
175+ private fun readResolve (): Any = NetpGeoswitchingScreenNoParams
176+ }
0 commit comments