diff --git a/CHANGES.md b/CHANGES.md index 7419401245..9d16fcaed5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,77 @@ +Changes in Element X v26.02.0 +============================= + + + +## What's Changed +### ✨ Features +* When a background SDK task fails, react in the client by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6166 +* Enable space feature flags by default by @ganfra in https://github.com/element-hq/element-x-android/pull/6171 +### 🙌 Improvements +* Improve space management with pagination and partial failure handling by @ganfra in https://github.com/element-hq/element-x-android/pull/6099 +* Iterate on QrCode login error buttons by @bmarty in https://github.com/element-hq/element-x-android/pull/6101 +* Update icon shown for world_readable rooms by @richvdh in https://github.com/element-hq/element-x-android/pull/6111 +* QRCode login: treat not found error as expired error. by @bmarty in https://github.com/element-hq/element-x-android/pull/6161 +* Iterate on Space related UI by @ganfra in https://github.com/element-hq/element-x-android/pull/6150 +### 🔒 Security +* Ensure aspect ratio of images in the timeline is restricted by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6168 +### 🐛 Bugfixes +* Ensure that Element Call activity is not closed when using an external link by @bmarty in https://github.com/element-hq/element-x-android/pull/6114 +* Refresh a Space's room list after creating a room in it by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6135 +* When creating a DM, set room history visibility to `invited` by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6138 +* Fix back navigation after creating a room in a space by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6134 +* Fix `LinkifyHelper` index out of bounds with parenthesis by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6140 +* Change role screen won't be dismissed until changes take effect by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6141 +### 🗣 Translations +* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/6122 +* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/6155 +### 🧱 Build +* Try fixing Maestro tests (again) by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6149 +* Add a stale bot for X-Needs-Info issues. by @bmarty in https://github.com/element-hq/element-x-android/pull/6153 +* [Release script] Ensure that the release version will match the next Monday date by @bmarty in https://github.com/element-hq/element-x-android/pull/6152 +### 🚧 In development 🚧 +* Add Space Filters feature for Room List by @ganfra in https://github.com/element-hq/element-x-android/pull/6136 +* Add history sharing badges to room details by @kaylendog in https://github.com/element-hq/element-x-android/pull/6132 +### Dependency upgrades +* Update dependency androidx.work:work-runtime-ktx to v2.11.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6105 +* Update metro to v0.10.2 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6106 +* Update camera to v1.5.3 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6103 +* Update activity to v1.12.3 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6104 +* Update dependency com.posthog:posthog-android to v3.30.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6120 +* Update kotlin by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6102 +* Update roborazzi to v1.58.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6124 +* Update kover by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6139 +* Update dependency com.posthog:posthog-android to v3.31.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6145 +* Update kotlin by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6142 +* Update media3 to v1.9.2 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6151 +* Update dependency org.matrix.rustcomponents:sdk-android to v26.02.6 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6144 +* Update firebaseAppDistribution to v5.2.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6146 +* Update dependency com.google.firebase:firebase-bom to v34.9.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6148 +* Update dependency io.sentry:sentry-android to v8.32.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6157 +* Update metro to v0.10.3 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6164 +* Update dependency org.matrix.rustcomponents:sdk-android to v26.2.10 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6169 +* chore(deps): update plugin paparazzi to v2.0.0-alpha04 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6048 +* fix(deps): update dependency org.jetbrains.kotlinx:kover-gradle-plugin to v0.9.7 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6173 +* fix(deps): update haze to v1.7.2 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6175 +### Others +* Improve favorite wording and icon of room by @bmarty in https://github.com/element-hq/element-x-android/pull/6097 +* Add special flow for leaving a space as the last owner by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6112 +* Remove `runBlocking` in `ThreadedMessagesNode` by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6108 +* Revert "Add "call.pro.element.io" in the list of known hosts for Element Call." by @bmarty in https://github.com/element-hq/element-x-android/pull/6118 +* Refactor room list filtering to use Rust SDK by @ganfra in https://github.com/element-hq/element-x-android/pull/6117 +* Ensure http 429 are retried 3 times before failing. by @bmarty in https://github.com/element-hq/element-x-android/pull/6119 +* Remove `JoinRule.Private` from the codebase by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6129 +* Fix voice message recording not starting after permission is granted by @kknappe in https://github.com/element-hq/element-x-android/pull/6109 +* Use correct bg color. by @bmarty in https://github.com/element-hq/element-x-android/pull/6165 +* Document "Developer options" and remove outdated instructions by @MadLittleMods in https://github.com/element-hq/element-x-android/pull/6162 +* Update SpaceFilterButton selected state color by @ganfra in https://github.com/element-hq/element-x-android/pull/6178 + +## New Contributors +* @kknappe made their first contribution in https://github.com/element-hq/element-x-android/pull/6109 +* @MadLittleMods made their first contribution in https://github.com/element-hq/element-x-android/pull/6162 + +**Full Changelog**: https://github.com/element-hq/element-x-android/compare/v26.01.2...v26.02.0 + Changes in Element X v26.01.2 ============================= diff --git a/fastlane/metadata/android/en-US/changelogs/202602000.txt b/fastlane/metadata/android/en-US/changelogs/202602000.txt new file mode 100644 index 0000000000..a4b397f1bb --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/202602000.txt @@ -0,0 +1,2 @@ +Main changes in this version: bug fixes and improvements. +Full changelog: https://github.com/element-hq/element-x-android/releases \ No newline at end of file diff --git a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpaceView.kt b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpaceView.kt index a15f9cb94d..05fb75ee5e 100644 --- a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpaceView.kt +++ b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpaceView.kt @@ -109,10 +109,12 @@ fun SpaceView( modifier: Modifier = Modifier, acceptDeclineInviteView: @Composable () -> Unit, ) { - BackHandler { + var handledBack by remember { mutableStateOf(false) } + BackHandler(enabled = !handledBack) { if (state.isManageMode) { state.eventSink(SpaceEvents.ExitManageMode) } else { + handledBack = true onBackClick() } } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManager.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManager.kt index ee72c34b9e..cd3f0faf45 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManager.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManager.kt @@ -24,9 +24,10 @@ import io.element.android.libraries.push.api.notifications.NotificationIdProvide import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent import io.element.android.libraries.push.impl.notifications.model.shouldIgnoreEventInRoom +import io.element.android.libraries.sessionstorage.api.observer.SessionListener +import io.element.android.libraries.sessionstorage.api.observer.SessionObserver import io.element.android.services.appnavstate.api.AppNavigationStateService import io.element.android.services.appnavstate.api.NavigationState -import io.element.android.services.appnavstate.api.currentSessionId import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -46,28 +47,30 @@ class DefaultNotificationDrawerManager( private val matrixClientProvider: MatrixClientProvider, private val imageLoaderHolder: ImageLoaderHolder, private val activeNotificationsProvider: ActiveNotificationsProvider, + sessionObserver: SessionObserver, ) : NotificationCleaner { // TODO EAx add a setting per user for this private var useCompleteNotificationFormat = true + private val sessionListener = object : SessionListener { + override suspend fun onSessionDeleted(userId: String, wasLastSession: Boolean) { + // User signed out, clear all notifications related to the session. + clearAllEvents(SessionId(userId)) + } + } + init { // Observe application state coroutineScope.launch { appNavigationStateService.appNavigationState .collect { onAppNavigationStateChange(it.navigationState) } } + sessionObserver.addListener(sessionListener) } - private var currentAppNavigationState: NavigationState? = null - private fun onAppNavigationStateChange(navigationState: NavigationState) { when (navigationState) { - NavigationState.Root -> { - currentAppNavigationState?.currentSessionId()?.let { sessionId -> - // User signed out, clear all notifications related to the session. - clearAllEvents(sessionId) - } - } + NavigationState.Root -> {} is NavigationState.Session -> {} is NavigationState.Space -> {} is NavigationState.Room -> { @@ -85,7 +88,6 @@ class DefaultNotificationDrawerManager( ) } } - currentAppNavigationState = navigationState } /** diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManagerTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManagerTest.kt index 608c45e9b8..500e31b1ac 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManagerTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManagerTest.kt @@ -31,7 +31,9 @@ import io.element.android.libraries.push.impl.notifications.fake.FakeRoomGroupMe import io.element.android.libraries.push.impl.notifications.fake.FakeSummaryGroupMessageCreator import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent import io.element.android.libraries.sessionstorage.api.SessionStore +import io.element.android.libraries.sessionstorage.api.observer.SessionObserver import io.element.android.libraries.sessionstorage.test.InMemorySessionStore +import io.element.android.libraries.sessionstorage.test.observer.FakeSessionObserver import io.element.android.services.appnavstate.api.AppNavigationState import io.element.android.services.appnavstate.api.AppNavigationStateService import io.element.android.services.appnavstate.api.NavigationState @@ -204,34 +206,69 @@ class DefaultNotificationDrawerManagerTest { ) } - private fun TestScope.createDefaultNotificationDrawerManager( - notificationDisplayer: NotificationDisplayer = FakeNotificationDisplayer(), - appNavigationStateService: AppNavigationStateService = FakeAppNavigationStateService(), - roomGroupMessageCreator: RoomGroupMessageCreator = FakeRoomGroupMessageCreator(), - summaryGroupMessageCreator: SummaryGroupMessageCreator = FakeSummaryGroupMessageCreator(), - activeNotificationsProvider: FakeActiveNotificationsProvider = FakeActiveNotificationsProvider(), - matrixClientProvider: FakeMatrixClientProvider = FakeMatrixClientProvider(), - sessionStore: SessionStore = InMemorySessionStore(), - enterpriseService: EnterpriseService = FakeEnterpriseService(), - ): DefaultNotificationDrawerManager { - return DefaultNotificationDrawerManager( + @Test + fun `when a session is signed out, clearAllEvent is invoked`() = runTest { + val cancelNotificationResult = lambdaRecorder { _, _ -> } + val notificationDisplayer = FakeNotificationDisplayer( + cancelNotificationResult = cancelNotificationResult, + ) + val summaryId = NotificationIdProvider.getSummaryNotificationId(A_SESSION_ID) + val activeNotificationsProvider = FakeActiveNotificationsProvider( + getNotificationsForSessionResult = { + listOf( + mockk { + every { id } returns summaryId + every { tag } returns null + }, + ) + }, + countResult = { 1 }, + ) + val sessionObserver = FakeSessionObserver() + createDefaultNotificationDrawerManager( notificationDisplayer = notificationDisplayer, - notificationRenderer = NotificationRenderer( - notificationDisplayer = FakeNotificationDisplayer(), - notificationDataFactory = DefaultNotificationDataFactory( - notificationCreator = FakeNotificationCreator(), - roomGroupMessageCreator = roomGroupMessageCreator, - summaryGroupMessageCreator = summaryGroupMessageCreator, - activeNotificationsProvider = activeNotificationsProvider, - ), - enterpriseService = enterpriseService, - sessionStore = sessionStore, - ), - appNavigationStateService = appNavigationStateService, - coroutineScope = backgroundScope, - matrixClientProvider = matrixClientProvider, - imageLoaderHolder = FakeImageLoaderHolder(), activeNotificationsProvider = activeNotificationsProvider, + sessionObserver = sessionObserver, + ) + // Simulate a session sign out + sessionObserver.onSessionDeleted(A_SESSION_ID.value) + // Verify we asked to cancel the notification with summaryId + cancelNotificationResult.assertions().isCalledExactly(1).withSequence( + listOf(value(null), value(summaryId)), ) } } + +fun TestScope.createDefaultNotificationDrawerManager( + notificationDisplayer: NotificationDisplayer = FakeNotificationDisplayer(), + notificationRenderer: NotificationRenderer? = null, + appNavigationStateService: AppNavigationStateService = FakeAppNavigationStateService(), + roomGroupMessageCreator: RoomGroupMessageCreator = FakeRoomGroupMessageCreator(), + summaryGroupMessageCreator: SummaryGroupMessageCreator = FakeSummaryGroupMessageCreator(), + activeNotificationsProvider: FakeActiveNotificationsProvider = FakeActiveNotificationsProvider(), + matrixClientProvider: FakeMatrixClientProvider = FakeMatrixClientProvider(), + sessionStore: SessionStore = InMemorySessionStore(), + enterpriseService: EnterpriseService = FakeEnterpriseService(), + sessionObserver: SessionObserver = FakeSessionObserver(), +): DefaultNotificationDrawerManager { + return DefaultNotificationDrawerManager( + notificationDisplayer = notificationDisplayer, + notificationRenderer = notificationRenderer ?: NotificationRenderer( + notificationDisplayer = FakeNotificationDisplayer(), + notificationDataFactory = DefaultNotificationDataFactory( + notificationCreator = FakeNotificationCreator(), + roomGroupMessageCreator = roomGroupMessageCreator, + summaryGroupMessageCreator = summaryGroupMessageCreator, + activeNotificationsProvider = activeNotificationsProvider, + ), + enterpriseService = enterpriseService, + sessionStore = sessionStore, + ), + appNavigationStateService = appNavigationStateService, + coroutineScope = backgroundScope, + matrixClientProvider = matrixClientProvider, + imageLoaderHolder = FakeImageLoaderHolder(), + activeNotificationsProvider = activeNotificationsProvider, + sessionObserver = sessionObserver, + ) +} diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultOnMissedCallNotificationHandlerTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultOnMissedCallNotificationHandlerTest.kt index 1a47200e12..9bba1c32d3 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultOnMissedCallNotificationHandlerTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultOnMissedCallNotificationHandlerTest.kt @@ -16,13 +16,9 @@ import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClientProvider import io.element.android.libraries.matrix.test.notification.FakeNotificationService import io.element.android.libraries.matrix.test.notification.aNotificationData -import io.element.android.libraries.matrix.ui.media.test.FakeImageLoaderHolder -import io.element.android.libraries.push.impl.notifications.fake.FakeActiveNotificationsProvider import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationDataFactory -import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationDisplayer import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent import io.element.android.libraries.push.test.notifications.FakeCallNotificationEventResolver -import io.element.android.services.appnavstate.test.FakeAppNavigationStateService import io.element.android.tests.testutils.lambda.lambdaRecorder import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runCurrent @@ -47,16 +43,10 @@ class DefaultOnMissedCallNotificationHandlerTest { }) val defaultOnMissedCallNotificationHandler = DefaultOnMissedCallNotificationHandler( matrixClientProvider = matrixClientProvider, - defaultNotificationDrawerManager = DefaultNotificationDrawerManager( - notificationDisplayer = FakeNotificationDisplayer(), + defaultNotificationDrawerManager = createDefaultNotificationDrawerManager( notificationRenderer = createNotificationRenderer( notificationDataFactory = dataFactory, ), - appNavigationStateService = FakeAppNavigationStateService(), - coroutineScope = backgroundScope, - matrixClientProvider = FakeMatrixClientProvider(), - imageLoaderHolder = FakeImageLoaderHolder(), - activeNotificationsProvider = FakeActiveNotificationsProvider(), ), callNotificationEventResolver = FakeCallNotificationEventResolver(resolveEventLambda = { _, _, _ -> Result.success(aNotifiableMessageEvent()) diff --git a/plugins/src/main/kotlin/Versions.kt b/plugins/src/main/kotlin/Versions.kt index 3c9d6d8c19..4e071e33b4 100644 --- a/plugins/src/main/kotlin/Versions.kt +++ b/plugins/src/main/kotlin/Versions.kt @@ -39,13 +39,13 @@ private const val versionYear = 26 * Month of the version on 2 digits. Value must be in [1,12]. * Do not update this value. it is updated by the release script. */ -private const val versionMonth = 1 +private const val versionMonth = 2 /** * Release number in the month. Value must be in [0,99]. * Do not update this value. it is updated by the release script. */ -private const val versionReleaseNumber = 2 +private const val versionReleaseNumber = 0 object Versions { /**