Skip to content

Commit aa19cb9

Browse files
committed
chore: further linter fixes
fix: addressed regression with the navbar chore: updated Google Age Signals API and handling
1 parent 76dd6d2 commit aa19cb9

13 files changed

Lines changed: 212 additions & 61 deletions

File tree

app/src/main/java/com/advice/schedule/presentation/viewmodel/FeedbackViewModel.kt

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,30 +45,34 @@ class FeedbackViewModel :
4545
val state = _state.value as? FeedbackState.Content ?: return
4646

4747
val items =
48-
state.feedback.items.map {
49-
if (it.id == item.id) {
50-
when (val type = it.type) {
51-
FeedbackType.DisplayOnly -> it
48+
state.feedback.items.map { feedbackItem ->
49+
if (feedbackItem.id == item.id) {
50+
when (val type = feedbackItem.type) {
51+
FeedbackType.DisplayOnly -> feedbackItem
5252
is FeedbackType.MultiSelect -> {
5353
val selections =
5454
if (value.toLong() in type.selections) {
5555
type.selections.filter { it != value.toLong() }
5656
} else {
5757
type.selections + value.toLong()
5858
}
59-
it.copy(type = FeedbackType.MultiSelect(type.options, selections))
59+
feedbackItem.copy(
60+
type = FeedbackType.MultiSelect(type.options, selections),
61+
)
6062
}
6163

6264
is FeedbackType.SelectOne -> {
63-
it.copy(type = FeedbackType.SelectOne(type.options, value.toLong()))
65+
feedbackItem.copy(
66+
type = FeedbackType.SelectOne(type.options, value.toLong()),
67+
)
6468
}
6569

6670
is FeedbackType.TextBox -> {
67-
it.copy(type = FeedbackType.TextBox(value))
71+
feedbackItem.copy(type = FeedbackType.TextBox(value))
6872
}
6973
}
7074
} else {
71-
it
75+
feedbackItem
7276
}
7377
}
7478

app/src/main/java/com/advice/schedule/ui/viewmodels/MainViewModel.kt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.advice.schedule.ui.viewmodels
22

3-
import android.content.Context
3+
import android.app.Activity
44
import android.os.Bundle
55
import android.widget.Toast
66
import androidx.activity.result.ActivityResultLauncher
@@ -109,19 +109,22 @@ class MainViewModel :
109109
private var hasStarted = false
110110

111111
fun onAppStart(
112-
context: Context,
112+
activity: Activity,
113113
appUpdateLauncher: ActivityResultLauncher<IntentSenderRequest>,
114114
) {
115115
if (hasStarted) return
116116
hasStarted = true
117117

118+
// Play Age Signals 0.0.4 requires an Activity for the sharing-access prompt.
119+
userSession.resolveAudienceContext(activity)
120+
118121
// Only showing the prompt once per version.
119122
if (storage.updateVersion != BuildConfig.VERSION_CODE) {
120123
appManager.checkForUpdate(appUpdateLauncher)
121124
}
122125
val format =
123126
if (android.text.format.DateFormat
124-
.is24HourFormat(context)
127+
.is24HourFormat(activity)
125128
) {
126129
"24h"
127130
} else {
@@ -132,7 +135,7 @@ class MainViewModel :
132135
viewModelScope.launch {
133136
toastManager.messages.collect {
134137
if (it != null) {
135-
Toast.makeText(context, it.text, it.duration).show()
138+
Toast.makeText(activity, it.text, it.duration).show()
136139
toastManager.clear()
137140
}
138141
}
Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
package com.advice.core.audience
22

3-
enum class AudienceStatus(
4-
val value: Int,
5-
) {
6-
Verified(0),
7-
Supervised(1),
8-
Declared(5),
9-
Pending(2),
10-
Denied(3),
11-
Unknown(4),
12-
;
13-
14-
companion object {
15-
fun getByValue(value: Int?) = entries.firstOrNull { it.value == value }
16-
}
3+
/**
4+
* Domain mapping of Play Age Signals response fields.
5+
*
6+
* [Declared]/[Supervised]/[Verified] come from `ageRangeSource` (TIER_A–D).
7+
* [Pending]/[Denied] come from `significantChangeStatus` when present.
8+
*/
9+
enum class AudienceStatus {
10+
Declared,
11+
Supervised,
12+
Verified,
13+
Pending,
14+
Denied,
15+
Unknown,
1716
}

data/src/main/java/com/advice/data/session/UserSession.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.advice.data.session
22

3+
import android.app.Activity
34
import com.advice.core.audience.AudienceContext
45
import com.advice.core.local.Conference
56
import com.advice.core.local.FlowResult
@@ -20,4 +21,10 @@ interface UserSession {
2021
fun getConferenceFlow(): Flow<FlowResult<Conference>>
2122

2223
fun setConference(conference: Conference)
24+
25+
/**
26+
* Resolves Play Age Signals using [activity] so Play can show the sharing prompt when required.
27+
* Safe to call multiple times; only the first successful resolve replaces [AudienceContext.Unresolved].
28+
*/
29+
fun resolveAudienceContext(activity: Activity)
2330
}

feature-firebase/src/main/java/com/advice/firebase/data/sources/FirebaseFAQDataSource.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class FirebaseFAQDataSource(
3434
.snapshotFlow()
3535
.closeOnConferenceChange(userSession.getConference())
3636
.mapSnapshot {
37-
it.toObjectsOrEmpty(FirebaseFAQ::class.java).map { it.toFAQ() }
37+
it.toObjectsOrEmpty(FirebaseFAQ::class.java).map { faq -> faq.toFAQ() }
3838
}.onStart { emit(FlowResult.Loading) }
3939
}.shareIn(
4040
applicationScope,

feature-firebase/src/main/java/com/advice/firebase/session/FirebaseUserSession.kt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.advice.firebase.session
22

3+
import android.app.Activity
34
import com.advice.core.audience.AudienceContext
45
import com.advice.core.local.Conference
56
import com.advice.core.local.FlowResult
@@ -9,6 +10,7 @@ import com.advice.data.sources.ConferencesDataSource
910
import com.advice.play.AgeSignalsRepository
1011
import com.google.firebase.auth.FirebaseAuth
1112
import com.google.firebase.crashlytics.FirebaseCrashlytics
13+
import kotlinx.coroutines.CompletableDeferred
1214
import kotlinx.coroutines.CoroutineScope
1315
import kotlinx.coroutines.flow.Flow
1416
import kotlinx.coroutines.flow.MutableStateFlow
@@ -33,6 +35,9 @@ class FirebaseUserSession(
3335
private val _conferenceFlow: MutableStateFlow<FlowResult<Conference>> =
3436
MutableStateFlow(FlowResult.Loading)
3537

38+
/** Completes true once anonymous auth succeeds; false if auth failed. */
39+
private val authReady = CompletableDeferred<Boolean>()
40+
3641
override var isDeveloper: Boolean = false
3742

3843
init {
@@ -73,19 +78,31 @@ class FirebaseUserSession(
7378
val user = it.user
7479
if (user != null) {
7580
Timber.d("User uid: ${user.uid}")
76-
_audienceContext.value = ageSignals.get()
81+
authReady.complete(true)
7782
} else {
7883
crashlytics.log("user cannot be signed in")
7984
Timber.e("User could not be signed in")
8085
_audienceContext.value = AudienceContext.Unavailable
86+
authReady.complete(false)
8187
}
8288
} catch (ex: Exception) {
8389
Timber.e(ex, "Could not sign in anonymously")
8490
_audienceContext.value = AudienceContext.Unavailable
91+
authReady.complete(false)
8592
}
8693
}
8794
}
8895

96+
override fun resolveAudienceContext(activity: Activity) {
97+
if (_audienceContext.value !is AudienceContext.Unresolved) return
98+
99+
applicationScope.launch {
100+
if (!authReady.await()) return@launch
101+
if (_audienceContext.value !is AudienceContext.Unresolved) return@launch
102+
_audienceContext.value = ageSignals.get(activity)
103+
}
104+
}
105+
89106
private fun getActiveConference(
90107
previous: Conference?,
91108
conferences: List<Conference>,
Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,36 @@
11
package com.advice.play
22

33
import android.content.Context
4+
import com.google.android.play.agesignals.AgeSignalsAccessResult
45
import com.google.android.play.agesignals.AgeSignalsManager
56
import com.google.android.play.agesignals.AgeSignalsResult
6-
import com.google.android.play.agesignals.model.AgeSignalsVerificationStatus
7+
import com.google.android.play.agesignals.model.AgeRangeSource
8+
import com.google.android.play.agesignals.model.AgeSignalsStatus
79
import com.google.android.play.agesignals.testing.FakeAgeSignalsManager
810

911
/**
1012
* Supervised 13–17 persona for on-device DEBUG testing.
11-
* Change [debugPersona] to try a different Age Signals response.
13+
* Change [debugPersona] / [debugAccessStatus] to try a different Age Signals response.
1214
*/
15+
private val debugAccessStatus: Int = AgeSignalsStatus.SHARED
16+
1317
private val debugPersona: AgeSignalsResult =
14-
AgeSignalsResult.builder()
15-
.setUserStatus(AgeSignalsVerificationStatus.SUPERVISED)
18+
AgeSignalsResult
19+
.builder()
20+
.setAgeRangeSource(AgeRangeSource.TIER_B)
1621
.setAgeLower(13)
1722
.setAgeUpper(17)
1823
.setInstallId("fake_install_id")
1924
.build()
2025

2126
fun createAgeSignalsManager(context: Context): AgeSignalsManager {
2227
return FakeAgeSignalsManager().apply {
28+
setNextAgeSignalsAccessResult(
29+
AgeSignalsAccessResult
30+
.builder()
31+
.setAgeSignalsStatus(debugAccessStatus)
32+
.build(),
33+
)
2334
setNextAgeSignalsResult(debugPersona)
2435
}
2536
}

0 commit comments

Comments
 (0)