Skip to content

Commit ef7a52f

Browse files
Merge pull request #16 from PopStackHack/release/4.1.5
Release/4.1.5
2 parents c4f2def + c102274 commit ef7a52f

15 files changed

Lines changed: 124 additions & 74 deletions

File tree

app/src/main/java/com/popstack/mvoter2015/feature/about/AboutController.kt

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@ package com.popstack.mvoter2015.feature.about
22

33
import android.annotation.SuppressLint
44
import android.content.Intent
5-
import android.graphics.text.LineBreaker
65
import android.net.Uri
76
import android.os.Bundle
8-
import android.text.Layout
97
import android.view.LayoutInflater
108
import androidx.lifecycle.lifecycleScope
119
import com.bluelinelabs.conductor.RouterTransaction
@@ -20,6 +18,7 @@ import com.popstack.mvoter2015.helper.conductor.requireActivity
2018
import com.popstack.mvoter2015.helper.conductor.requireContext
2119
import com.popstack.mvoter2015.helper.conductor.setSupportActionBar
2220
import com.popstack.mvoter2015.helper.conductor.supportActionBar
21+
import com.popstack.mvoter2015.helper.extensions.justify
2322
import com.popstack.mvoter2015.logging.HasTag
2423
import kotlinx.coroutines.launch
2524
import javax.inject.Inject
@@ -78,13 +77,7 @@ class AboutController : LifeCycleAwareController<ControllerAboutBinding>(), Inje
7877
openAppWebsite()
7978
}
8079

81-
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
82-
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
83-
binding.tvCandidatePrivacyInstruction.justificationMode = LineBreaker.JUSTIFICATION_MODE_INTER_WORD
84-
} else {
85-
binding.tvCandidatePrivacyInstruction.justificationMode = Layout.JUSTIFICATION_MODE_INTER_WORD
86-
}
87-
}
80+
binding.tvCandidatePrivacyInstruction.justify()
8881

8982
binding.tvVersion.text = requireContext().getString(R.string.version, BuildConfig.VERSION_NAME)
9083
}

app/src/main/java/com/popstack/mvoter2015/feature/candidate/listing/CandidateListController.kt

Lines changed: 34 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package com.popstack.mvoter2015.feature.candidate.listing
22

33
import android.annotation.SuppressLint
4-
import android.graphics.text.LineBreaker
54
import android.os.Bundle
6-
import android.text.Layout
75
import android.view.LayoutInflater
86
import android.view.View
97
import androidx.core.view.isVisible
@@ -20,10 +18,12 @@ import com.popstack.mvoter2015.feature.analytics.screen.ScreenTrackAnalyticsProv
2018
import com.popstack.mvoter2015.feature.candidate.search.CandidateSearchController
2119
import com.popstack.mvoter2015.feature.location.LocationUpdateController
2220
import com.popstack.mvoter2015.helper.ConstituencyTab
21+
import com.popstack.mvoter2015.helper.asyncviewstate.AsyncViewState
2322
import com.popstack.mvoter2015.helper.conductor.requireActivity
2423
import com.popstack.mvoter2015.helper.conductor.requireContext
2524
import com.popstack.mvoter2015.helper.conductor.setSupportActionBar
2625
import com.popstack.mvoter2015.helper.conductor.supportActionBar
26+
import com.popstack.mvoter2015.helper.extensions.justify
2727
import com.popstack.mvoter2015.logging.HasTag
2828
import kotlinx.coroutines.flow.collectLatest
2929
import kotlinx.coroutines.launch
@@ -57,8 +57,6 @@ class CandidateListController :
5757

5858
selectedTab = savedViewState?.getInt(VIEW_STATE_SELECTED_TAB)
5959

60-
viewModel.viewEventLiveData.observe(this, Observer(::observeViewEvent))
61-
6260
setSupportActionBar(binding.toolBar)
6361
supportActionBar()?.title = requireContext().getString(R.string.title_candidates)
6462

@@ -122,24 +120,46 @@ class CandidateListController :
122120

123121
CandidateListPagerParentRouter.setParentRouter(router)
124122

125-
showCandidatePrivacyInstructionIfNeeded()
123+
viewModel.houseViewItemListResultLiveData.observe(this, Observer(::observeHouseViewItemListResult))
124+
125+
if (viewModel.houseViewItemListResultLiveData.value == null) {
126+
viewModel.loadHouses()
127+
}
128+
}
126129

127-
viewModel.houseViewItemListLiveData.observe(lifecycleOwner, Observer(::observeHouseViewItem))
128-
viewModel.loadHouses()
130+
private fun observeHouseViewItemListResult(viewState: AsyncViewState<CandidateListViewModel.HouseViewItemListResult>) {
131+
if (viewState is AsyncViewState.Loading) binding.progressIndicator.show()
132+
else binding.progressIndicator.hide()
133+
134+
if (viewState is AsyncViewState.Success) {
135+
val result = viewState.value
136+
binding.tabLayout.isVisible = result is CandidateListViewModel.HouseViewItemListResult.HouseViewItemList
137+
binding.viewPager.isVisible = result is CandidateListViewModel.HouseViewItemListResult.HouseViewItemList
138+
binding.groupChooseCandidateComponent.isVisible = result is CandidateListViewModel.HouseViewItemListResult.RequestUserLocation
139+
if (result is CandidateListViewModel.HouseViewItemListResult.HouseViewItemList) {
140+
showCandidatePrivacyInstructionIfNeeded()
141+
pagerAdapter.setItems(result.itemList)
142+
binding.tabLayout.removeAllTabs()
143+
result.itemList.forEach {
144+
binding.tabLayout.addTab(
145+
binding.tabLayout.newTab().setCustomView(
146+
ConstituencyTab(requireActivity()).apply {
147+
setText(it.houseName)
148+
}
149+
)
150+
)
151+
}
152+
changeSelectedTabIfNeeded()
153+
}
154+
}
129155
}
130156

131157
@Inject
132158
lateinit var viewCache: CandidateListViewCache
133159

134160
@SuppressLint("WrongConstant")
135161
private fun showCandidatePrivacyInstructionIfNeeded() {
136-
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
137-
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
138-
binding.tvCandidatePrivacyInstruction.justificationMode = LineBreaker.JUSTIFICATION_MODE_INTER_WORD
139-
} else {
140-
binding.tvCandidatePrivacyInstruction.justificationMode = Layout.JUSTIFICATION_MODE_INTER_WORD
141-
}
142-
}
162+
binding.tvCandidatePrivacyInstruction.justify()
143163

144164
lifecycleScope.launch {
145165
viewCache.shouldShowCandidatePrivacyInstruction().collectLatest {
@@ -178,29 +198,6 @@ class CandidateListController :
178198
binding.viewPager.isVisible = false
179199
}
180200

181-
private fun observeViewEvent(viewEvent: CandidateListViewModel.ViewEvent) {
182-
if (viewEvent is CandidateListViewModel.ViewEvent.RequestUserLocation) {
183-
binding.tabLayout.isVisible = false
184-
binding.groupChooseCandidateComponent.isVisible = true
185-
}
186-
}
187-
188-
private fun observeHouseViewItem(houseViewItemList: List<CandidateListHouseViewItem>) {
189-
binding.groupChooseCandidateComponent.isVisible = false
190-
pagerAdapter.setItems(houseViewItemList)
191-
binding.tabLayout.removeAllTabs()
192-
houseViewItemList.forEach {
193-
binding.tabLayout.addTab(
194-
binding.tabLayout.newTab().setCustomView(
195-
ConstituencyTab(requireActivity()).apply {
196-
setText(it.houseName)
197-
}
198-
)
199-
)
200-
}
201-
changeSelectedTabIfNeeded()
202-
}
203-
204201
private fun changeSelectedTabIfNeeded() {
205202
selectedTab?.let {
206203
binding.viewPager.post {

app/src/main/java/com/popstack/mvoter2015/feature/candidate/listing/CandidateListViewModel.kt

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,49 @@ package com.popstack.mvoter2015.feature.candidate.listing
33
import androidx.lifecycle.ViewModel
44
import androidx.lifecycle.viewModelScope
55
import com.popstack.mvoter2015.domain.constituency.model.HouseType
6-
import com.popstack.mvoter2015.domain.location.usecase.GetUserStateRegion
76
import com.popstack.mvoter2015.domain.location.usecase.GetUserWard
8-
import com.popstack.mvoter2015.helper.livedata.SingleLiveEvent
7+
import com.popstack.mvoter2015.domain.location.usecase.UpdateWardDetails
8+
import com.popstack.mvoter2015.helper.asyncviewstate.AsyncViewStateLiveData
99
import kotlinx.coroutines.launch
1010
import javax.inject.Inject
1111

1212
class CandidateListViewModel @Inject constructor(
1313
private val houseViewItemMapper: CandidateListHouseViewItemMapper,
14-
private val getUserStateRegion: GetUserStateRegion,
14+
private val updateWardDetails: UpdateWardDetails,
1515
private val getUserWard: GetUserWard
1616
) : ViewModel() {
1717

18-
sealed class ViewEvent {
19-
object RequestUserLocation : ViewEvent()
20-
}
18+
sealed class HouseViewItemListResult {
19+
object RequestUserLocation : HouseViewItemListResult()
2120

22-
val viewEventLiveData = SingleLiveEvent<ViewEvent>()
21+
data class HouseViewItemList(
22+
val itemList: List<CandidateListHouseViewItem>
23+
) : HouseViewItemListResult()
24+
}
2325

24-
val houseViewItemListLiveData =
25-
SingleLiveEvent<List<CandidateListHouseViewItem>>()
26+
val houseViewItemListResultLiveData =
27+
AsyncViewStateLiveData<HouseViewItemListResult>()
2628

2729
fun loadHouses() {
2830
viewModelScope.launch {
29-
val houseTypes = HouseType.values()
30-
3131
val userWard = getUserWard.execute(Unit) ?: run {
32-
viewEventLiveData.postValue(ViewEvent.RequestUserLocation)
32+
houseViewItemListResultLiveData.postSuccess(HouseViewItemListResult.RequestUserLocation)
3333
return@launch
3434
}
35-
val viewItems = houseTypes.map { houseType ->
36-
houseViewItemMapper.mapFromHouseType(houseType, userWard)
35+
36+
houseViewItemListResultLiveData.postLoading()
37+
38+
try {
39+
updateWardDetails.execute(Unit)
40+
} catch (exception: Exception) {
41+
//Ignore exception, allow update to fail
42+
} finally {
43+
val houseTypes = HouseType.values()
44+
val viewItems = houseTypes.map { houseType ->
45+
houseViewItemMapper.mapFromHouseType(houseType, userWard)
46+
}
47+
houseViewItemListResultLiveData.postSuccess(HouseViewItemListResult.HouseViewItemList(viewItems))
3748
}
38-
houseViewItemListLiveData.postValue(viewItems)
3949
}
4050
}
4151
}

app/src/main/java/com/popstack/mvoter2015/feature/candidate/listing/lowerhouse/LowerHouseCandidateListController.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.os.Bundle
44
import android.view.LayoutInflater
55
import androidx.core.view.isVisible
66
import androidx.lifecycle.Observer
7+
import androidx.lifecycle.lifecycleScope
78
import androidx.recyclerview.widget.GridLayoutManager
89
import androidx.recyclerview.widget.LinearLayoutManager
910
import com.bluelinelabs.conductor.RouterTransaction
@@ -21,6 +22,8 @@ import com.popstack.mvoter2015.helper.conductor.requireContext
2122
import com.popstack.mvoter2015.helper.extensions.isLandScape
2223
import com.popstack.mvoter2015.helper.extensions.isTablet
2324
import com.popstack.mvoter2015.logging.HasTag
25+
import kotlinx.coroutines.delay
26+
import kotlinx.coroutines.launch
2427

2528
class LowerHouseCandidateListController : MvvmController<ControllerLowerHouseCandidateListBinding>(), HasTag {
2629

@@ -65,7 +68,7 @@ class LowerHouseCandidateListController : MvvmController<ControllerLowerHouseCan
6568
}
6669

6770
if (viewModel.viewItemLiveData.value == null) {
68-
loadCandidates()
71+
loadCandidates()
6972
}
7073
}
7174

@@ -83,7 +86,6 @@ class LowerHouseCandidateListController : MvvmController<ControllerLowerHouseCan
8386

8487
private fun observeViewItem(viewState: AsyncViewState<CandidateListResult>) = with(binding) {
8588
progressBar.isVisible = viewState is AsyncViewState.Loading
86-
rvCandidate.isVisible = viewState is AsyncViewState.Success
8789
tvErrorMessage.isVisible = viewState is AsyncViewState.Error
8890
btnRetry.isVisible = viewState is AsyncViewState.Error
8991

app/src/main/java/com/popstack/mvoter2015/feature/candidate/listing/regionalhouse/RegionalHouseCandidateListController.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ class RegionalHouseCandidateListController() : MvvmController<ControllerRegional
8585

8686
private fun observeViewItem(viewState: AsyncViewState<CandidateListResult>) = with(binding) {
8787
progressBar.isVisible = viewState is AsyncViewState.Loading
88-
rvCandidate.isVisible = viewState is AsyncViewState.Success
8988
tvErrorMessage.isVisible = viewState is AsyncViewState.Error
9089
btnRetry.isVisible = viewState is AsyncViewState.Error
9190
groupRemark.isVisible = false

app/src/main/java/com/popstack/mvoter2015/feature/candidate/listing/upperhouse/UpperHouseCandidateListController.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ class UpperHouseCandidateListController : MvvmController<ControllerUpperHouseCan
8282

8383
private fun observeViewItem(viewState: AsyncViewState<CandidateListResult>) = with(binding) {
8484
progressBar.isVisible = viewState is AsyncViewState.Loading
85-
rvCandidate.isVisible = viewState is AsyncViewState.Success
8685
tvErrorMessage.isVisible = viewState is AsyncViewState.Error
8786
btnRetry.isVisible = viewState is AsyncViewState.Error
8887

app/src/main/java/com/popstack/mvoter2015/helper/extensions/TextViewExtensions.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.popstack.mvoter2015.helper.extensions
22

3+
import android.annotation.SuppressLint
34
import android.graphics.drawable.Drawable
5+
import android.text.Layout
46
import android.widget.TextView
57

68
fun TextView.setCompoundDrawablesKt(
@@ -19,4 +21,11 @@ fun TextView.setCompoundDrawableWithIntrinsicBoundsKt(
1921
bottom: Drawable? = null
2022
) {
2123
this.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom)
24+
}
25+
26+
@SuppressLint("WrongConstant")
27+
fun TextView.justify() {
28+
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
29+
justificationMode = Layout.JUSTIFICATION_MODE_INTER_WORD
30+
}
2231
}

app/src/main/res/layout/controller_candidate_list.xml

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
33
xmlns:app="http://schemas.android.com/apk/res-auto"
4+
xmlns:tools="http://schemas.android.com/tools"
45
android:layout_width="match_parent"
56
android:layout_height="match_parent"
6-
xmlns:tools="http://schemas.android.com/tools"
77
android:animateLayoutChanges="true">
88

99
<com.google.android.material.appbar.AppBarLayout
@@ -50,6 +50,19 @@
5050
android:layout_width="match_parent"
5151
android:layout_height="match_parent">
5252

53+
<com.google.android.material.progressindicator.ProgressIndicator
54+
android:id="@+id/progressIndicator"
55+
style="@style/Widget.MaterialComponents.ProgressIndicator.Linear.Indeterminate"
56+
android:layout_width="match_parent"
57+
android:layout_height="wrap_content"
58+
android:visibility="gone"
59+
app:indicatorColor="@color/accent"
60+
app:layout_constraintBottom_toBottomOf="parent"
61+
app:layout_constraintEnd_toEndOf="parent"
62+
app:layout_constraintStart_toStartOf="parent"
63+
app:minHideDelay="500"
64+
tools:visibility="visible" />
65+
5366
<ImageView
5467
android:id="@+id/ivCandidateIndicator"
5568
android:layout_width="100dp"
@@ -117,10 +130,10 @@
117130
android:layout_width="match_parent"
118131
android:layout_height="wrap_content"
119132
android:layout_gravity="bottom"
120-
android:visibility="gone"
121-
tools:visibility="visible"
122133
android:layout_marginBottom="-8dp"
123-
app:cardBackgroundColor="@color/accent">
134+
android:visibility="gone"
135+
app:cardBackgroundColor="@color/accent"
136+
tools:visibility="visible">
124137

125138
<androidx.constraintlayout.widget.ConstraintLayout
126139
android:layout_width="match_parent"
@@ -156,5 +169,4 @@
156169

157170
</com.google.android.material.card.MaterialCardView>
158171

159-
160172
</androidx.coordinatorlayout.widget.CoordinatorLayout>

app/src/main/res/layout/controller_lower_house_candidate_list.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
android:layout_height="0dp"
3434
android:layout_marginTop="8dp"
3535
app:layout_constraintBottom_toBottomOf="parent"
36+
app:layout_constraintEnd_toEndOf="parent"
3637
app:layout_constraintStart_toStartOf="parent"
3738
app:layout_constraintTop_toBottomOf="@+id/tvConstituencyName" />
3839

app/src/main/res/layout/controller_regional_candidate_list.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
android:layout_height="0dp"
1212
android:clipToPadding="false"
1313
app:layout_constraintBottom_toBottomOf="parent"
14+
app:layout_constraintEnd_toEndOf="parent"
1415
app:layout_constraintStart_toStartOf="parent"
1516
app:layout_constraintTop_toTopOf="parent" />
1617

0 commit comments

Comments
 (0)