Skip to content

Commit 9961852

Browse files
committed
Merge branch 'release/0.7.5' into main
2 parents e567776 + 8f074d3 commit 9961852

File tree

761 files changed

+7124
-3327
lines changed

Some content is hidden

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

761 files changed

+7124
-3327
lines changed

.github/workflows/maestro.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ jobs:
7979
uses: actions/download-artifact@v4
8080
with:
8181
name: elementx-apk-maestro
82-
- uses: mobile-dev-inc/[email protected].6
82+
- uses: mobile-dev-inc/[email protected].7
8383
if: (github.event_name == 'pull_request' && github.event.pull_request.fork == null) || github.event_name == 'workflow_dispatch'
8484
with:
8585
api-key: ${{ secrets.MAESTRO_CLOUD_API_KEY }}

CHANGES.md

+50
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,53 @@
1+
Changes in Element X v0.7.4 (2024-11-20)
2+
========================================
3+
4+
## What's Changed
5+
### 🙌 Improvements
6+
* Update the strings for unsupported calls by @bmarty in https://github.com/element-hq/element-x-android/pull/3857
7+
### 🐛 Bugfixes
8+
* Stop incoming call ringing if answered on another device. by @bmarty in https://github.com/element-hq/element-x-android/pull/3842
9+
* Use formatted captions for images and video by @jmartinesp in https://github.com/element-hq/element-x-android/pull/3864
10+
* Fix unified push unregister by @bmarty in https://github.com/element-hq/element-x-android/pull/3877
11+
* Hide the keyboard when navigating from the chat room screen by @jmartinesp in https://github.com/element-hq/element-x-android/pull/3878
12+
* Fix long click not working for media timeline items by @jmartinesp in https://github.com/element-hq/element-x-android/pull/3879
13+
* Instantiate the verification controller ASAP by @jmartinesp in https://github.com/element-hq/element-x-android/pull/3893
14+
* fix : display security banner for room list empty state by @ganfra in https://github.com/element-hq/element-x-android/pull/3892
15+
### 🗣 Translations
16+
* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/3852
17+
* Sync Strings - add translations to Finnish by @ElementBot in https://github.com/element-hq/element-x-android/pull/3883
18+
### 🚧 In development 🚧
19+
* Create room : improve handling of room address by @ganfra in https://github.com/element-hq/element-x-android/pull/3868
20+
### Dependency upgrades
21+
* Update anvil to v0.4.0 by @renovate in https://github.com/element-hq/element-x-android/pull/3792
22+
* Update kotlin to v2.0.21-1.0.27 by @renovate in https://github.com/element-hq/element-x-android/pull/3836
23+
* Update dependency org.maplibre.gl:android-sdk to v11.6.1 by @renovate in https://github.com/element-hq/element-x-android/pull/3793
24+
* Update android.gradle.plugin to v8.7.2 by @renovate in https://github.com/element-hq/element-x-android/pull/3785
25+
* Update lifecycle to v2.8.7 by @renovate in https://github.com/element-hq/element-x-android/pull/3763
26+
* Update plugin dependencycheck to v11 by @renovate in https://github.com/element-hq/element-x-android/pull/3723
27+
* Update dependency org.matrix.rustcomponents:sdk-android to v0.2.61 by @renovate in https://github.com/element-hq/element-x-android/pull/3841
28+
* Update mobile-dev-inc/action-maestro-cloud action to v1.9.6 by @renovate in https://github.com/element-hq/element-x-android/pull/3846
29+
* Update dependency com.posthog:posthog-android to v3.9.1 by @renovate in https://github.com/element-hq/element-x-android/pull/3856
30+
* Update core to v1.15.0 by @renovate in https://github.com/element-hq/element-x-android/pull/3766
31+
* Update dependency com.android.tools:desugar_jdk_libs to v2.1.3 by @renovate in https://github.com/element-hq/element-x-android/pull/3825
32+
* Update dependency io.nlopez.compose.rules:detekt to v0.4.18 by @renovate in https://github.com/element-hq/element-x-android/pull/3860
33+
* Update dependency com.posthog:posthog-android to v3.9.2 by @renovate in https://github.com/element-hq/element-x-android/pull/3861
34+
* Update dependency io.sentry:sentry-android to v7.17.0 by @renovate in https://github.com/element-hq/element-x-android/pull/3862
35+
* Update dependency androidx.compose:compose-bom to v2024.11.00 by @renovate in https://github.com/element-hq/element-x-android/pull/3869
36+
* Update telephoto to v0.14.0 by @renovate in https://github.com/element-hq/element-x-android/pull/3870
37+
* Update SDK bindings version to `0.2.62` and fix `SendHandle` usages by @jmartinesp in https://github.com/element-hq/element-x-android/pull/3876
38+
* Update codecov/codecov-action action to v5 by @renovate in https://github.com/element-hq/element-x-android/pull/3874
39+
* Update dependency com.google.firebase:firebase-bom to v33.6.0 by @renovate in https://github.com/element-hq/element-x-android/pull/3880
40+
* Update kotlin to v2.0.21-1.0.28 by @renovate in https://github.com/element-hq/element-x-android/pull/3881
41+
* Update dependency org.robolectric:robolectric to v4.14 by @renovate in https://github.com/element-hq/element-x-android/pull/3882
42+
* Update appyx to v1.5.1 by @renovate in https://github.com/element-hq/element-x-android/pull/3889
43+
* Update dependency io.nlopez.compose.rules:detekt to v0.4.19 by @renovate in https://github.com/element-hq/element-x-android/pull/3900
44+
* Update dependency org.matrix.rustcomponents:sdk-android to v0.2.63 by @renovate in https://github.com/element-hq/element-x-android/pull/3898
45+
### Others
46+
* Design system : implement new TextField by @ganfra in https://github.com/element-hq/element-x-android/pull/3834
47+
* Remove :samples:minimal module by @bmarty in https://github.com/element-hq/element-x-android/pull/3871
48+
* Replace `textPlaceholder` color usages with `textSecondary` by @jmartinesp in https://github.com/element-hq/element-x-android/pull/3873
49+
* Room Preview API changes by @ganfra in https://github.com/element-hq/element-x-android/pull/3875
50+
151
Changes in Element X v0.7.3 (2024-11-08)
252
========================================
353

appconfig/src/main/kotlin/io/element/android/appconfig/ElementCallConfig.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ object ElementCallConfig {
1616
/**
1717
* The default duration of a ringing call in seconds before it's automatically dismissed.
1818
*/
19-
const val RINGING_CALL_DURATION_SECONDS = 15
19+
const val RINGING_CALL_DURATION_SECONDS = 90
2020
}

appconfig/src/main/kotlin/io/element/android/appconfig/NotificationConfig.kt

+12-6
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,20 @@ import android.graphics.Color
1111
import androidx.annotation.ColorInt
1212

1313
object NotificationConfig {
14-
// TODO EAx Implement and set to true at some point
15-
const val SUPPORT_MARK_AS_READ_ACTION = false
14+
/**
15+
* If set to true, the notification will have a "Mark as read" action.
16+
*/
17+
const val SHOW_MARK_AS_READ_ACTION = true
1618

17-
// TODO EAx Implement and set to true at some point
18-
const val SUPPORT_JOIN_DECLINE_INVITE = false
19+
/**
20+
* If set to true, the notification for invitation will have two actions to accept or decline the invite.
21+
*/
22+
const val SHOW_ACCEPT_AND_DECLINE_INVITE_ACTIONS = true
1923

20-
// TODO EAx Implement and set to true at some point
21-
const val SUPPORT_QUICK_REPLY_ACTION = false
24+
/**
25+
* If set to true, the notification will have a "Quick reply" action, allow to compose and send a message to the room.
26+
*/
27+
const val SHOW_QUICK_REPLY_ACTION = true
2228

2329
@ColorInt
2430
val NOTIFICATION_ACCENT_COLOR: Int = Color.parseColor("#FF0DBD8B")

appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt

+51-9
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,20 @@ import androidx.lifecycle.repeatOnLifecycle
2020
import com.bumble.appyx.core.composable.PermanentChild
2121
import com.bumble.appyx.core.lifecycle.subscribe
2222
import com.bumble.appyx.core.modality.BuildContext
23+
import com.bumble.appyx.core.navigation.NavElements
24+
import com.bumble.appyx.core.navigation.NavKey
2325
import com.bumble.appyx.core.navigation.model.permanent.PermanentNavModel
2426
import com.bumble.appyx.core.node.Node
2527
import com.bumble.appyx.core.plugin.Plugin
2628
import com.bumble.appyx.core.plugin.plugins
2729
import com.bumble.appyx.navmodel.backstack.BackStack
30+
import com.bumble.appyx.navmodel.backstack.BackStack.State.ACTIVE
31+
import com.bumble.appyx.navmodel.backstack.BackStack.State.CREATED
32+
import com.bumble.appyx.navmodel.backstack.BackStack.State.STASHED
33+
import com.bumble.appyx.navmodel.backstack.BackStackElement
34+
import com.bumble.appyx.navmodel.backstack.BackStackElements
35+
import com.bumble.appyx.navmodel.backstack.operation.BackStackOperation
36+
import com.bumble.appyx.navmodel.backstack.operation.Push
2837
import com.bumble.appyx.navmodel.backstack.operation.pop
2938
import com.bumble.appyx.navmodel.backstack.operation.push
3039
import com.bumble.appyx.navmodel.backstack.operation.replace
@@ -312,7 +321,7 @@ class LoggedInFlowNode @AssistedInject constructor(
312321
}
313322

314323
override fun onForwardedToSingleRoom(roomId: RoomId) {
315-
coroutineScope.launch { attachRoom(roomId.toRoomIdOrAlias()) }
324+
coroutineScope.launch { attachRoom(roomId.toRoomIdOrAlias(), clearBackstack = false) }
316325
}
317326

318327
override fun onPermalinkClick(data: PermalinkData, pushToBackstack: Boolean) {
@@ -400,6 +409,11 @@ class LoggedInFlowNode @AssistedInject constructor(
400409
is NavTarget.SecureBackup -> {
401410
secureBackupEntryPoint.nodeBuilder(this, buildContext)
402411
.params(SecureBackupEntryPoint.Params(initialElement = navTarget.initialElement))
412+
.callback(object : SecureBackupEntryPoint.Callback {
413+
override fun onDone() {
414+
backstack.pop()
415+
}
416+
})
403417
.build()
404418
}
405419
NavTarget.Ftue -> {
@@ -467,21 +481,21 @@ class LoggedInFlowNode @AssistedInject constructor(
467481
serverNames: List<String> = emptyList(),
468482
trigger: JoinedRoom.Trigger? = null,
469483
eventId: EventId? = null,
484+
clearBackstack: Boolean,
470485
) {
471486
waitForNavTargetAttached { navTarget ->
472487
navTarget is NavTarget.RoomList
473488
}
474489
attachChild<RoomFlowNode> {
475-
backstack.push(
476-
NavTarget.Room(
477-
roomIdOrAlias = roomIdOrAlias,
478-
serverNames = serverNames,
479-
trigger = trigger,
480-
initialElement = RoomNavigationTarget.Messages(
481-
focusedEventId = eventId
482-
)
490+
val roomNavTarget = NavTarget.Room(
491+
roomIdOrAlias = roomIdOrAlias,
492+
serverNames = serverNames,
493+
trigger = trigger,
494+
initialElement = RoomNavigationTarget.Messages(
495+
focusedEventId = eventId
483496
)
484497
)
498+
backstack.accept(AttachRoomOperation(roomNavTarget, clearBackstack))
485499
}
486500
}
487501

@@ -526,3 +540,31 @@ class LoggedInFlowNode @AssistedInject constructor(
526540
@Assisted plugins: List<Plugin>,
527541
) : Node(buildContext, plugins = plugins)
528542
}
543+
544+
@Parcelize
545+
private class AttachRoomOperation(
546+
val roomTarget: LoggedInFlowNode.NavTarget.Room,
547+
val clearBackstack: Boolean,
548+
) : BackStackOperation<LoggedInFlowNode.NavTarget> {
549+
override fun isApplicable(elements: NavElements<LoggedInFlowNode.NavTarget, BackStack.State>) = true
550+
551+
override fun invoke(elements: BackStackElements<LoggedInFlowNode.NavTarget>): BackStackElements<LoggedInFlowNode.NavTarget> {
552+
return if (clearBackstack) {
553+
// Makes sure the room list target is alone in the backstack and stashed
554+
elements.mapNotNull { element ->
555+
if (element.key.navTarget == LoggedInFlowNode.NavTarget.RoomList) {
556+
element.transitionTo(STASHED, this)
557+
} else {
558+
null
559+
}
560+
} + BackStackElement(
561+
key = NavKey(roomTarget),
562+
fromState = CREATED,
563+
targetState = ACTIVE,
564+
operation = this
565+
)
566+
} else {
567+
Push<LoggedInFlowNode.NavTarget>(roomTarget).invoke(elements)
568+
}
569+
}
570+
}

appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ class RootFlowNode @AssistedInject constructor(
303303
trigger = JoinedRoom.Trigger.MobilePermalink,
304304
serverNames = permalinkData.viaParameters,
305305
eventId = permalinkData.eventId,
306+
clearBackstack = true
306307
)
307308
}
308309
is PermalinkData.UserLink -> {
@@ -318,7 +319,7 @@ class RootFlowNode @AssistedInject constructor(
318319
.apply {
319320
when (deeplinkData) {
320321
is DeeplinkData.Root -> Unit // The room list will always be shown, observing FtueState
321-
is DeeplinkData.Room -> attachRoom(deeplinkData.roomId.toRoomIdOrAlias())
322+
is DeeplinkData.Room -> attachRoom(deeplinkData.roomId.toRoomIdOrAlias(), clearBackstack = true)
322323
}
323324
}
324325
}

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

+14-4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import io.element.android.libraries.matrix.api.MatrixClient
2828
import io.element.android.libraries.matrix.api.encryption.EncryptionService
2929
import io.element.android.libraries.matrix.api.encryption.RecoveryState
3030
import io.element.android.libraries.matrix.api.roomlist.RoomListService
31+
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
3132
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
3233
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
3334
import io.element.android.libraries.preferences.api.store.EnableNativeSlidingSyncUseCase
@@ -102,10 +103,7 @@ class LoggedInPresenter @Inject constructor(
102103
}
103104
}
104105
LoggedInEvents.CheckSlidingSyncProxyAvailability -> coroutineScope.launch {
105-
// Force the user to log out if they were using the proxy sliding sync and it's no longer available, but native sliding sync is.
106-
forceNativeSlidingSyncMigration = !matrixClient.isUsingNativeSlidingSync() &&
107-
matrixClient.isNativeSlidingSyncSupported() &&
108-
!matrixClient.isSlidingSyncProxySupported()
106+
forceNativeSlidingSyncMigration = matrixClient.forceNativeSlidingSyncMigration().getOrDefault(false)
109107
}
110108
LoggedInEvents.LogoutAndMigrateToNativeSlidingSync -> coroutineScope.launch {
111109
// Enable native sliding sync if it wasn't already the case
@@ -125,6 +123,18 @@ class LoggedInPresenter @Inject constructor(
125123
)
126124
}
127125

126+
// Force the user to log out if they were using the proxy sliding sync and it's no longer available, but native sliding sync is.
127+
private suspend fun MatrixClient.forceNativeSlidingSyncMigration(): Result<Boolean> = runCatching {
128+
val currentSlidingSyncVersion = currentSlidingSyncVersion().getOrThrow()
129+
if (currentSlidingSyncVersion == SlidingSyncVersion.Proxy) {
130+
val availableSlidingSyncVersions = availableSlidingSyncVersions().getOrThrow()
131+
availableSlidingSyncVersions.contains(SlidingSyncVersion.Native) &&
132+
!availableSlidingSyncVersions.contains(SlidingSyncVersion.Proxy)
133+
} else {
134+
false
135+
}
136+
}
137+
128138
private suspend fun ensurePusherIsRegistered(pusherRegistrationState: MutableState<AsyncData<Unit>>) {
129139
Timber.tag(pusherTag.value).d("Ensure pusher is registered")
130140
val currentPushProvider = pushService.getCurrentPushProvider()

appnav/src/main/kotlin/io/element/android/appnav/room/RoomFlowNode.kt

+12-4
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,11 @@ import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
4848
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
4949
import io.element.android.libraries.matrix.api.getRoomInfoFlow
5050
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
51+
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
5152
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
5253
import kotlinx.coroutines.flow.combine
5354
import kotlinx.coroutines.flow.distinctUntilChanged
55+
import kotlinx.coroutines.flow.first
5456
import kotlinx.coroutines.flow.launchIn
5557
import kotlinx.coroutines.flow.map
5658
import kotlinx.coroutines.launch
@@ -67,6 +69,7 @@ class RoomFlowNode @AssistedInject constructor(
6769
private val joinRoomEntryPoint: JoinRoomEntryPoint,
6870
private val roomAliasResolverEntryPoint: RoomAliasResolverEntryPoint,
6971
private val networkMonitor: NetworkMonitor,
72+
private val membershipObserver: RoomMembershipObserver,
7073
) : BaseFlowNode<RoomFlowNode.NavTarget>(
7174
backstack = BackStack(
7275
initialElement = NavTarget.Loading,
@@ -145,10 +148,6 @@ class RoomFlowNode @AssistedInject constructor(
145148
backstack.newRoot(NavTarget.JoinedRoom(roomId))
146149
}
147150
}
148-
CurrentUserMembership.LEFT -> {
149-
// Left the room, navigate out of this flow
150-
navigateUp()
151-
}
152151
else -> {
153152
// Was invited or the room is not known, display the join room screen
154153
backstack.newRoot(
@@ -161,6 +160,15 @@ class RoomFlowNode @AssistedInject constructor(
161160
}
162161
}
163162
}.launchIn(lifecycleScope)
163+
164+
// If the user leaves the room from this client, close the room flow.
165+
lifecycleScope.launch {
166+
membershipObserver.updates
167+
.first { it.roomId == roomId && !it.isUserInRoom }
168+
.run {
169+
navigateUp()
170+
}
171+
}
164172
}
165173

166174
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {

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

+5-6
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import io.element.android.libraries.matrix.api.core.SessionId
2121
import io.element.android.libraries.matrix.api.encryption.EncryptionService
2222
import io.element.android.libraries.matrix.api.encryption.RecoveryState
2323
import io.element.android.libraries.matrix.api.roomlist.RoomListService
24+
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
2425
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
2526
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
2627
import io.element.android.libraries.matrix.test.AN_EXCEPTION
@@ -501,9 +502,8 @@ class LoggedInPresenterTest {
501502
// - The sliding sync proxy is no longer supported
502503
// - The native sliding sync is supported
503504
val matrixClient = FakeMatrixClient(
504-
isUsingNativeSlidingSyncLambda = { false },
505-
isSlidingSyncProxySupportedLambda = { false },
506-
isNativeSlidingSyncSupportedLambda = { true },
505+
currentSlidingSyncVersionLambda = { Result.success(SlidingSyncVersion.Proxy) },
506+
availableSlidingSyncVersionsLambda = { Result.success(listOf(SlidingSyncVersion.Native)) },
507507
)
508508
val presenter = createLoggedInPresenter(matrixClient = matrixClient)
509509
moleculeFlow(RecompositionMode.Immediate) {
@@ -521,9 +521,8 @@ class LoggedInPresenterTest {
521521
@Test
522522
fun `present - CheckSlidingSyncProxyAvailability will not force the migration if native sliding sync is not supported too`() = runTest {
523523
val matrixClient = FakeMatrixClient(
524-
isUsingNativeSlidingSyncLambda = { false },
525-
isSlidingSyncProxySupportedLambda = { false },
526-
isNativeSlidingSyncSupportedLambda = { false },
524+
currentSlidingSyncVersionLambda = { Result.success(SlidingSyncVersion.Proxy) },
525+
availableSlidingSyncVersionsLambda = { Result.success(emptyList()) },
527526
)
528527
val presenter = createLoggedInPresenter(matrixClient = matrixClient)
529528
moleculeFlow(RecompositionMode.Immediate) {

build.gradle.kts

+5
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ allprojects {
5252
detektPlugins("io.nlopez.compose.rules:detekt:0.4.19")
5353
}
5454

55+
tasks.withType<io.gitlab.arturbosch.detekt.Detekt>().configureEach {
56+
exclude("io/element/android/tests/konsist/failures/**")
57+
}
58+
5559
// KtLint
5660
apply {
5761
plugin("org.jlleitschuh.gradle.ktlint")
@@ -75,6 +79,7 @@ allprojects {
7579
val generatedPath = "${layout.buildDirectory.asFile.get()}/generated/"
7680
filter {
7781
exclude { element -> element.file.path.contains(generatedPath) }
82+
exclude("io/element/android/tests/konsist/failures/**")
7883
}
7984
}
8085
// Dependency check
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Main changes in this version: bug fixes and improvements.
2+
Full changelog: https://github.com/element-hq/element-x-android/releases

0 commit comments

Comments
 (0)