Skip to content

Commit 70223bf

Browse files
authored
Merge branch 'develop' into renovate/com.posthog-posthog-android-3.x
2 parents c47a572 + cd8cb32 commit 70223bf

File tree

883 files changed

+1927
-1818
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

883 files changed

+1927
-1818
lines changed

.github/workflows/quality.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ jobs:
138138
- name: Build Fdroid Debug
139139
run: ./gradlew :app:compileFdroidDebugKotlin $CI_GRADLE_ARG_PROPERTIES
140140
- name: Run lint
141-
run: ./gradlew :app:lintGplayDebug :app:lintFdroidDebug $CI_GRADLE_ARG_PROPERTIES
141+
run: ./gradlew :app:lintGplayDebug :app:lintFdroidDebug lintDebug $CI_GRADLE_ARG_PROPERTIES --continue
142142
- name: Upload reports
143143
if: always()
144144
uses: actions/upload-artifact@v4

appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt

+8
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import io.element.android.libraries.core.meta.BuildMeta
2626
import io.element.android.libraries.matrix.api.MatrixClient
2727
import io.element.android.libraries.matrix.api.encryption.EncryptionService
2828
import io.element.android.libraries.matrix.api.encryption.RecoveryState
29+
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
2930
import io.element.android.libraries.matrix.api.roomlist.RoomListService
3031
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
3132
import io.element.android.libraries.matrix.api.sync.SyncService
@@ -35,6 +36,7 @@ import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatu
3536
import io.element.android.libraries.push.api.PushService
3637
import io.element.android.libraries.pushproviders.api.RegistrationFailure
3738
import io.element.android.services.analytics.api.AnalyticsService
39+
import kotlinx.coroutines.CoroutineScope
3840
import kotlinx.coroutines.flow.combine
3941
import kotlinx.coroutines.flow.launchIn
4042
import kotlinx.coroutines.flow.onEach
@@ -60,6 +62,7 @@ class LoggedInPresenter @Inject constructor(
6062
pushService.ignoreRegistrationError(matrixClient.sessionId)
6163
}.collectAsState(initial = false)
6264
val pusherRegistrationState = remember<MutableState<AsyncData<Unit>>> { mutableStateOf(AsyncData.Uninitialized) }
65+
LaunchedEffect(Unit) { preloadAccountManagementUrl() }
6366
LaunchedEffect(Unit) {
6467
sessionVerificationService.sessionVerifiedStatus
6568
.onEach { sessionVerifiedStatus ->
@@ -202,4 +205,9 @@ class LoggedInPresenter @Inject constructor(
202205
analyticsService.capture(CryptoSessionStateChange(changeRecoveryState, changeVerificationState))
203206
}
204207
}
208+
209+
private fun CoroutineScope.preloadAccountManagementUrl() = launch {
210+
matrixClient.getAccountManagementUrl(AccountManagementAction.Profile)
211+
matrixClient.getAccountManagementUrl(AccountManagementAction.SessionsList)
212+
}
205213
}

appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt

+80-75
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@
55
* Please see LICENSE files in the repository root for full details.
66
*/
77

8+
@file:OptIn(ExperimentalCoroutinesApi::class)
9+
810
package io.element.android.appnav.loggedin
911

10-
import app.cash.molecule.RecompositionMode
11-
import app.cash.molecule.moleculeFlow
1212
import app.cash.turbine.ReceiveTurbine
13-
import app.cash.turbine.test
1413
import com.google.common.truth.Truth.assertThat
1514
import im.vector.app.features.analytics.plan.CryptoSessionStateChange
1615
import im.vector.app.features.analytics.plan.UserProperties
@@ -19,6 +18,7 @@ import io.element.android.libraries.matrix.api.MatrixClient
1918
import io.element.android.libraries.matrix.api.core.SessionId
2019
import io.element.android.libraries.matrix.api.encryption.EncryptionService
2120
import io.element.android.libraries.matrix.api.encryption.RecoveryState
21+
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
2222
import io.element.android.libraries.matrix.api.roomlist.RoomListService
2323
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
2424
import io.element.android.libraries.matrix.api.sync.SyncState
@@ -45,8 +45,8 @@ import io.element.android.tests.testutils.lambda.any
4545
import io.element.android.tests.testutils.lambda.lambdaError
4646
import io.element.android.tests.testutils.lambda.lambdaRecorder
4747
import io.element.android.tests.testutils.lambda.value
48+
import io.element.android.tests.testutils.test
4849
import kotlinx.coroutines.ExperimentalCoroutinesApi
49-
import kotlinx.coroutines.test.TestScope
5050
import kotlinx.coroutines.test.advanceUntilIdle
5151
import kotlinx.coroutines.test.runTest
5252
import org.junit.Rule
@@ -58,24 +58,40 @@ class LoggedInPresenterTest {
5858

5959
@Test
6060
fun `present - initial state`() = runTest {
61-
val presenter = createLoggedInPresenter()
62-
moleculeFlow(RecompositionMode.Immediate) {
63-
presenter.present()
64-
}.test {
61+
createLoggedInPresenter().test {
6562
val initialState = awaitItem()
6663
assertThat(initialState.showSyncSpinner).isFalse()
6764
assertThat(initialState.pusherRegistrationState.isUninitialized()).isTrue()
6865
assertThat(initialState.ignoreRegistrationError).isFalse()
6966
}
7067
}
7168

69+
@Test
70+
fun `present - ensure that account urls are preloaded`() = runTest {
71+
val accountManagementUrlResult = lambdaRecorder<AccountManagementAction?, Result<String?>> { Result.success("aUrl") }
72+
val matrixClient = FakeMatrixClient(
73+
accountManagementUrlResult = accountManagementUrlResult,
74+
)
75+
createLoggedInPresenter(
76+
matrixClient = matrixClient,
77+
).test {
78+
awaitItem()
79+
advanceUntilIdle()
80+
accountManagementUrlResult.assertions().isCalledExactly(2)
81+
.withSequence(
82+
listOf(value(AccountManagementAction.Profile)),
83+
listOf(value(AccountManagementAction.SessionsList)),
84+
)
85+
}
86+
}
87+
7288
@Test
7389
fun `present - show sync spinner`() = runTest {
7490
val roomListService = FakeRoomListService()
75-
val presenter = createLoggedInPresenter(roomListService, SyncState.Running)
76-
moleculeFlow(RecompositionMode.Immediate) {
77-
presenter.present()
78-
}.test {
91+
createLoggedInPresenter(
92+
syncState = SyncState.Running,
93+
matrixClient = FakeMatrixClient(roomListService = roomListService),
94+
).test {
7995
val initialState = awaitItem()
8096
assertThat(initialState.showSyncSpinner).isFalse()
8197
roomListService.postSyncIndicator(RoomListService.SyncIndicator.Show)
@@ -92,18 +108,18 @@ class LoggedInPresenterTest {
92108
val verificationService = FakeSessionVerificationService()
93109
val encryptionService = FakeEncryptionService()
94110
val buildMeta = aBuildMeta()
95-
val presenter = LoggedInPresenter(
96-
matrixClient = FakeMatrixClient(roomListService = roomListService, encryptionService = encryptionService),
111+
LoggedInPresenter(
112+
matrixClient = FakeMatrixClient(
113+
roomListService = roomListService,
114+
encryptionService = encryptionService,
115+
),
97116
syncService = FakeSyncService(initialSyncState = SyncState.Running),
98117
pushService = FakePushService(),
99118
sessionVerificationService = verificationService,
100119
analyticsService = analyticsService,
101120
encryptionService = encryptionService,
102121
buildMeta = buildMeta,
103-
)
104-
moleculeFlow(RecompositionMode.Immediate) {
105-
presenter.present()
106-
}.test {
122+
).test {
107123
encryptionService.emitRecoveryState(RecoveryState.UNKNOWN)
108124
encryptionService.emitRecoveryState(RecoveryState.INCOMPLETE)
109125
verificationService.emitVerifiedStatus(SessionVerifiedStatus.Verified)
@@ -129,13 +145,10 @@ class LoggedInPresenterTest {
129145
val verificationService = FakeSessionVerificationService(
130146
initialSessionVerifiedStatus = SessionVerifiedStatus.NotVerified
131147
)
132-
val presenter = createLoggedInPresenter(
148+
createLoggedInPresenter(
133149
pushService = pushService,
134150
sessionVerificationService = verificationService,
135-
)
136-
moleculeFlow(RecompositionMode.Immediate) {
137-
presenter.present()
138-
}.test {
151+
).test {
139152
val finalState = awaitFirstItem()
140153
assertThat(finalState.pusherRegistrationState.errorOrNull())
141154
.isInstanceOf(PusherRegistrationFailure.AccountNotVerified::class.java)
@@ -155,13 +168,13 @@ class LoggedInPresenterTest {
155168
val pushService = createFakePushService(
156169
registerWithLambda = lambda,
157170
)
158-
val presenter = createLoggedInPresenter(
171+
createLoggedInPresenter(
159172
pushService = pushService,
160173
sessionVerificationService = sessionVerificationService,
161-
)
162-
moleculeFlow(RecompositionMode.Immediate) {
163-
presenter.present()
164-
}.test {
174+
matrixClient = FakeMatrixClient(
175+
accountManagementUrlResult = { Result.success(null) },
176+
),
177+
).test {
165178
val finalState = awaitFirstItem()
166179
assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue()
167180
lambda.assertions()
@@ -188,13 +201,13 @@ class LoggedInPresenterTest {
188201
val pushService = createFakePushService(
189202
registerWithLambda = lambda,
190203
)
191-
val presenter = createLoggedInPresenter(
204+
createLoggedInPresenter(
192205
pushService = pushService,
193206
sessionVerificationService = sessionVerificationService,
194-
)
195-
moleculeFlow(RecompositionMode.Immediate) {
196-
presenter.present()
197-
}.test {
207+
matrixClient = FakeMatrixClient(
208+
accountManagementUrlResult = { Result.success(null) },
209+
),
210+
).test {
198211
val finalState = awaitFirstItem()
199212
assertThat(finalState.pusherRegistrationState.isFailure()).isTrue()
200213
lambda.assertions()
@@ -233,13 +246,13 @@ class LoggedInPresenterTest {
233246
currentPushProvider = { pushProvider },
234247
registerWithLambda = lambda,
235248
)
236-
val presenter = createLoggedInPresenter(
249+
createLoggedInPresenter(
237250
pushService = pushService,
238251
sessionVerificationService = sessionVerificationService,
239-
)
240-
moleculeFlow(RecompositionMode.Immediate) {
241-
presenter.present()
242-
}.test {
252+
matrixClient = FakeMatrixClient(
253+
accountManagementUrlResult = { Result.success(null) },
254+
),
255+
).test {
243256
val finalState = awaitFirstItem()
244257
assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue()
245258
lambda.assertions()
@@ -277,13 +290,13 @@ class LoggedInPresenterTest {
277290
currentPushProvider = { pushProvider },
278291
registerWithLambda = lambda,
279292
)
280-
val presenter = createLoggedInPresenter(
293+
createLoggedInPresenter(
281294
pushService = pushService,
282295
sessionVerificationService = sessionVerificationService,
283-
)
284-
moleculeFlow(RecompositionMode.Immediate) {
285-
presenter.present()
286-
}.test {
296+
matrixClient = FakeMatrixClient(
297+
accountManagementUrlResult = { Result.success(null) },
298+
),
299+
).test {
287300
val finalState = awaitFirstItem()
288301
assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue()
289302
lambda.assertions()
@@ -317,13 +330,10 @@ class LoggedInPresenterTest {
317330
currentPushProvider = { pushProvider },
318331
registerWithLambda = lambda,
319332
)
320-
val presenter = createLoggedInPresenter(
333+
createLoggedInPresenter(
321334
pushService = pushService,
322335
sessionVerificationService = sessionVerificationService,
323-
)
324-
moleculeFlow(RecompositionMode.Immediate) {
325-
presenter.present()
326-
}.test {
336+
).test {
327337
val finalState = awaitFirstItem()
328338
assertThat(finalState.pusherRegistrationState.errorOrNull())
329339
.isInstanceOf(PusherRegistrationFailure.NoDistributorsAvailable::class.java)
@@ -345,13 +355,10 @@ class LoggedInPresenterTest {
345355
registerWithLambda = lambda,
346356
setIgnoreRegistrationErrorLambda = setIgnoreRegistrationErrorLambda,
347357
)
348-
val presenter = createLoggedInPresenter(
358+
createLoggedInPresenter(
349359
pushService = pushService,
350360
sessionVerificationService = sessionVerificationService,
351-
)
352-
moleculeFlow(RecompositionMode.Immediate) {
353-
presenter.present()
354-
}.test {
361+
).test {
355362
val finalState = awaitFirstItem()
356363
assertThat(finalState.pusherRegistrationState.errorOrNull())
357364
.isInstanceOf(PusherRegistrationFailure.NoProvidersAvailable::class.java)
@@ -394,13 +401,10 @@ class LoggedInPresenterTest {
394401
registerWithLambda = lambda,
395402
selectPushProviderLambda = selectPushProviderLambda,
396403
)
397-
val presenter = createLoggedInPresenter(
404+
createLoggedInPresenter(
398405
pushService = pushService,
399406
sessionVerificationService = sessionVerificationService,
400-
)
401-
moleculeFlow(RecompositionMode.Immediate) {
402-
presenter.present()
403-
}.test {
407+
).test {
404408
val finalState = awaitFirstItem()
405409
assertThat(finalState.pusherRegistrationState.errorOrNull())
406410
.isInstanceOf(PusherRegistrationFailure.NoDistributorsAvailable::class.java)
@@ -445,13 +449,13 @@ class LoggedInPresenterTest {
445449
pushProvider1 = pushProvider1,
446450
registerWithLambda = lambda,
447451
)
448-
val presenter = createLoggedInPresenter(
452+
createLoggedInPresenter(
449453
pushService = pushService,
450454
sessionVerificationService = sessionVerificationService,
451-
)
452-
moleculeFlow(RecompositionMode.Immediate) {
453-
presenter.present()
454-
}.test {
455+
matrixClient = FakeMatrixClient(
456+
accountManagementUrlResult = { Result.success(null) },
457+
),
458+
).test {
455459
val finalState = awaitFirstItem()
456460
assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue()
457461
lambda.assertions().isCalledOnce()
@@ -505,10 +509,9 @@ class LoggedInPresenterTest {
505509
currentSlidingSyncVersionLambda = { Result.success(SlidingSyncVersion.Proxy) },
506510
availableSlidingSyncVersionsLambda = { Result.success(listOf(SlidingSyncVersion.Native)) },
507511
)
508-
val presenter = createLoggedInPresenter(matrixClient = matrixClient)
509-
moleculeFlow(RecompositionMode.Immediate) {
510-
presenter.present()
511-
}.test {
512+
createLoggedInPresenter(
513+
matrixClient = matrixClient,
514+
).test {
512515
val initialState = awaitItem()
513516
assertThat(initialState.forceNativeSlidingSyncMigration).isFalse()
514517

@@ -525,13 +528,14 @@ class LoggedInPresenterTest {
525528
assertThat(userInitiated).isTrue()
526529
assertThat(ignoreSdkError).isTrue()
527530
}
528-
val matrixClient = FakeMatrixClient().apply {
531+
val matrixClient = FakeMatrixClient(
532+
accountManagementUrlResult = { Result.success(null) },
533+
).apply {
529534
this.logoutLambda = logoutLambda
530535
}
531-
val presenter = createLoggedInPresenter(matrixClient = matrixClient)
532-
moleculeFlow(RecompositionMode.Immediate) {
533-
presenter.present()
534-
}.test {
536+
createLoggedInPresenter(
537+
matrixClient = matrixClient,
538+
).test {
535539
val initialState = awaitItem()
536540

537541
initialState.eventSink(LoggedInEvents.LogoutAndMigrateToNativeSlidingSync)
@@ -547,14 +551,15 @@ class LoggedInPresenterTest {
547551
return awaitItem()
548552
}
549553

550-
private fun TestScope.createLoggedInPresenter(
551-
roomListService: RoomListService = FakeRoomListService(),
554+
private fun createLoggedInPresenter(
552555
syncState: SyncState = SyncState.Running,
553556
analyticsService: AnalyticsService = FakeAnalyticsService(),
554557
sessionVerificationService: SessionVerificationService = FakeSessionVerificationService(),
555558
encryptionService: EncryptionService = FakeEncryptionService(),
556559
pushService: PushService = FakePushService(),
557-
matrixClient: MatrixClient = FakeMatrixClient(roomListService = roomListService),
560+
matrixClient: MatrixClient = FakeMatrixClient(
561+
accountManagementUrlResult = { Result.success(null) },
562+
),
558563
buildMeta: BuildMeta = aBuildMeta(),
559564
): LoggedInPresenter {
560565
return LoggedInPresenter(

build.gradle.kts

+5-2
Original file line numberDiff line numberDiff line change
@@ -166,14 +166,17 @@ allprojects {
166166
// Register quality check tasks.
167167
tasks.register("runQualityChecks") {
168168
dependsOn(":tests:konsist:testDebugUnitTest")
169+
dependsOn(":app:lintGplayDebug")
169170
project.subprojects {
170-
// For some reason `findByName("lint")` doesn't work
171-
tasks.findByPath("$path:lint")?.let { dependsOn(it) }
171+
tasks.findByPath("$path:lintDebug")?.let { dependsOn(it) }
172172
tasks.findByName("detekt")?.let { dependsOn(it) }
173173
tasks.findByName("ktlintCheck")?.let { dependsOn(it) }
174174
// tasks.findByName("buildHealth")?.let { dependsOn(it) }
175175
}
176176
dependsOn(":app:knitCheck")
177+
178+
// Make sure all checks run even if some fail
179+
gradle.startParameter.isContinueOnFailure = true
177180
}
178181

179182
// Make sure to delete old screenshots before recording new ones

features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/IncomingCallScreen.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ internal fun IncomingCallScreen(
100100
ActionButton(
101101
size = 64.dp,
102102
onClick = { onAnswer(notificationData) },
103-
icon = CompoundIcons.VoiceCall(),
103+
icon = CompoundIcons.VoiceCallSolid(),
104104
title = stringResource(CommonStrings.action_accept),
105105
backgroundColor = ElementTheme.colors.iconSuccessPrimary,
106106
borderColor = ElementTheme.colors.borderSuccessSubtle

features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/qrcode/scan/QrCodeScanView.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ private fun ColumnScope.Buttons(
136136
verticalAlignment = Alignment.CenterVertically,
137137
) {
138138
Icon(
139-
imageVector = CompoundIcons.Error(),
139+
imageVector = CompoundIcons.ErrorSolid(),
140140
tint = ElementTheme.colors.iconCriticalPrimary,
141141
contentDescription = null,
142142
modifier = Modifier.size(24.dp)

0 commit comments

Comments
 (0)