Skip to content

Commit

Permalink
Merge branch 'release/0.7.3' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
bmarty committed Nov 8, 2024
2 parents d7282dd + e2275cb commit 183ffd2
Show file tree
Hide file tree
Showing 987 changed files with 8,406 additions and 4,241 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/maestro.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ jobs:
uses: actions/download-artifact@v4
with:
name: elementx-apk-maestro
- uses: mobile-dev-inc/[email protected].2
- uses: mobile-dev-inc/[email protected].4
if: (github.event_name == 'pull_request' && github.event.pull_request.fork == null) || github.event_name == 'workflow_dispatch'
with:
api-key: ${{ secrets.MAESTRO_CLOUD_API_KEY }}
Expand Down
2 changes: 1 addition & 1 deletion .idea/kotlinc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
Changes in Element X v0.7.2 (2024-10-29)
========================================

## What's Changed
### 🙌 Improvements
* Add setting to compress image and video by @bmarty in https://github.com/element-hq/element-x-android/pull/3744
### 🗣 Translations
* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/3743
### 🧱 Build
* Release script improvement by @bmarty in https://github.com/element-hq/element-x-android/pull/3741
### Dependency upgrades
* Update dependency org.maplibre.gl:android-sdk to v11.5.2 by @renovate in https://github.com/element-hq/element-x-android/pull/3720
* Update dependency io.sentry:sentry-android to v7.16.0 by @renovate in https://github.com/element-hq/element-x-android/pull/3726
* Update dependencyAnalysis to v2.3.0 by @renovate in https://github.com/element-hq/element-x-android/pull/3740
* Update dependency org.matrix.rustcomponents:sdk-android to v0.2.58 by @renovate in https://github.com/element-hq/element-x-android/pull/3749

Changes in Element X v0.7.1 (2024-10-25)
========================================

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

# Element X Android

Element X Android is a [Matrix](https://matrix.org/) Android Client provided by [element.io](https://element.io/). This app is currently in a pre-alpha release stage with only basic functionalities.
Element X Android is a [Matrix](https://matrix.org/) Android Client provided by [element.io](https://element.io/).

The application is a total rewrite of [Element-Android](https://github.com/element-hq/element-android) using the [Matrix Rust SDK](https://github.com/matrix-org/matrix-rust-sdk) underneath and targeting devices running Android 7+. The UI layer is written using [Jetpack Compose](https://developer.android.com/jetpack/compose), and the navigation is managed using [Appyx](https://github.com/bumble-tech/appyx).

Expand Down Expand Up @@ -71,7 +71,7 @@ We're doing this as a way to share code between platforms and while we've seen p

## Status

This project is in work in progress. The app does not cover yet all functionalities we expect. The list of supported features can be found in [this issue](https://github.com/element-hq/element-x-android/issues/911).
This project is in an early rollout and migration phase.

## Contributing

Expand Down
6 changes: 3 additions & 3 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ android {
} else {
"io.element.android.x"
}
targetSdk = Versions.targetSdk
versionCode = Versions.versionCode
versionName = Versions.versionName
targetSdk = Versions.TARGET_SDK
versionCode = Versions.VERSION_CODE
versionName = Versions.VERSION_NAME

// Keep abiFilter for the universalApk
ndk {
Expand Down
3 changes: 1 addition & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@
<!-- To be able to install APK from the application -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

<!-- Do not enable enableOnBackInvokedCallback until https://issuetracker.google.com/issues/271303558 is fixed -->
<application
android:name=".ElementXApplication"
android:allowBackup="false"
android:dataExtractionRules="@xml/data_extraction_rules"
android:enableOnBackInvokedCallback="false"
android:enableOnBackInvokedCallback="true"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
import com.bumble.appyx.core.plugin.plugins
import com.bumble.appyx.navmodel.backstack.BackStack
import com.bumble.appyx.navmodel.backstack.operation.pop
import com.bumble.appyx.navmodel.backstack.operation.push
import com.bumble.appyx.navmodel.backstack.operation.replace
import com.bumble.appyx.navmodel.backstack.operation.singleTop
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import im.vector.app.features.analytics.plan.JoinedRoom
Expand All @@ -50,6 +52,7 @@ import io.element.android.features.roomlist.api.RoomListEntryPoint
import io.element.android.features.securebackup.api.SecureBackupEntryPoint
import io.element.android.features.share.api.ShareEntryPoint
import io.element.android.features.userprofile.api.UserProfileEntryPoint
import io.element.android.features.verifysession.api.IncomingVerificationEntryPoint
import io.element.android.libraries.architecture.BackstackView
import io.element.android.libraries.architecture.BaseFlowNode
import io.element.android.libraries.architecture.createNode
Expand All @@ -66,6 +69,8 @@ import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
import io.element.android.libraries.matrix.api.permalink.PermalinkData
import io.element.android.libraries.matrix.api.sync.SyncState
import io.element.android.libraries.matrix.api.verification.SessionVerificationRequestDetails
import io.element.android.libraries.matrix.api.verification.SessionVerificationServiceListener
import io.element.android.libraries.preferences.api.store.EnableNativeSlidingSyncUseCase
import io.element.android.services.appnavstate.api.AppNavigationStateService
import kotlinx.coroutines.CoroutineScope
Expand Down Expand Up @@ -99,6 +104,7 @@ class LoggedInFlowNode @AssistedInject constructor(
private val matrixClient: MatrixClient,
private val sendingQueue: SendQueues,
private val logoutEntryPoint: LogoutEntryPoint,
private val incomingVerificationEntryPoint: IncomingVerificationEntryPoint,
private val enableNativeSlidingSyncUseCase: EnableNativeSlidingSyncUseCase,
snackbarDispatcher: SnackbarDispatcher,
) : BaseFlowNode<LoggedInFlowNode.NavTarget>(
Expand All @@ -123,6 +129,12 @@ class LoggedInFlowNode @AssistedInject constructor(
matrixClient.roomMembershipObserver(),
)

private val verificationListener = object : SessionVerificationServiceListener {
override fun onIncomingSessionRequest(sessionVerificationRequestDetails: SessionVerificationRequestDetails) {
backstack.singleTop(NavTarget.IncomingVerificationRequest(sessionVerificationRequestDetails))
}
}

override fun onBuilt() {
super.onBuilt()
lifecycle.subscribe(
Expand All @@ -131,6 +143,7 @@ class LoggedInFlowNode @AssistedInject constructor(
// TODO We do not support Space yet, so directly navigate to main space
appNavigationStateService.onNavigateToSpace(id, MAIN_SPACE)
loggedInFlowProcessor.observeEvents(coroutineScope)
matrixClient.sessionVerificationService().setListener(verificationListener)

ftueService.state
.onEach { ftueState ->
Expand All @@ -152,6 +165,7 @@ class LoggedInFlowNode @AssistedInject constructor(
appNavigationStateService.onLeavingSpace(id)
appNavigationStateService.onLeavingSession(id)
loggedInFlowProcessor.stopObserving()
matrixClient.sessionVerificationService().setListener(null)
}
)
observeSyncStateAndNetworkStatus()
Expand Down Expand Up @@ -232,6 +246,9 @@ class LoggedInFlowNode @AssistedInject constructor(

@Parcelize
data object LogoutForNativeSlidingSyncMigrationNeeded : NavTarget

@Parcelize
data class IncomingVerificationRequest(val data: SessionVerificationRequestDetails) : NavTarget
}

override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
Expand Down Expand Up @@ -260,7 +277,7 @@ class LoggedInFlowNode @AssistedInject constructor(
}

override fun onSetUpRecoveryClick() {
backstack.push(NavTarget.SecureBackup(initialElement = SecureBackupEntryPoint.InitialTarget.SetUpRecovery))
backstack.push(NavTarget.SecureBackup(initialElement = SecureBackupEntryPoint.InitialTarget.Root))
}

override fun onSessionConfirmRecoveryKeyClick() {
Expand Down Expand Up @@ -432,6 +449,16 @@ class LoggedInFlowNode @AssistedInject constructor(
.callback(callback)
.build()
}
is NavTarget.IncomingVerificationRequest -> {
incomingVerificationEntryPoint.nodeBuilder(this, buildContext)
.params(IncomingVerificationEntryPoint.Params(navTarget.data))
.callback(object : IncomingVerificationEntryPoint.Callback {
override fun onDone() {
backstack.pop()
}
})
.build()
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,18 @@ private const val SAVE_INSTANCE_KEY = "io.element.android.x.di.MatrixClientsHold

@SingleIn(AppScope::class)
@ContributesBinding(AppScope::class)
class MatrixClientsHolder @Inject constructor(private val authenticationService: MatrixAuthenticationService) : MatrixClientProvider {
class MatrixClientsHolder @Inject constructor(
private val authenticationService: MatrixAuthenticationService,
) : MatrixClientProvider {
private val sessionIdsToMatrixClient = ConcurrentHashMap<SessionId, MatrixClient>()
private val restoreMutex = Mutex()

init {
authenticationService.listenToNewMatrixClients { matrixClient ->
sessionIdsToMatrixClient[matrixClient.sessionId] = matrixClient
}
}

fun removeAll() {
sessionIdsToMatrixClient.clear()
}
Expand Down
5 changes: 5 additions & 0 deletions appnav/src/main/res/values-nl/translations.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="banner_migrate_to_native_sliding_sync_action">"Uitloggen &amp; Upgraden"</string>
<string name="banner_migrate_to_native_sliding_sync_force_logout_title">"Je homeserver ondersteunt het oude protocol niet meer. Log uit en log opnieuw in om de app te blijven gebruiken."</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,17 @@ class MatrixClientsHolderTest {
matrixClientsHolder.restoreWithSavedState(savedStateMap)
assertThat(matrixClientsHolder.getOrNull(A_SESSION_ID)).isEqualTo(fakeMatrixClient)
}

@Test
fun `test AuthenticationService listenToNewMatrixClients emits a Client value and we save it`() = runTest {
val fakeAuthenticationService = FakeMatrixAuthenticationService()
val matrixClientsHolder = MatrixClientsHolder(fakeAuthenticationService)
assertThat(matrixClientsHolder.getOrNull(A_SESSION_ID)).isNull()

fakeAuthenticationService.givenMatrixClient(FakeMatrixClient(sessionId = A_SESSION_ID))
val loginSucceeded = fakeAuthenticationService.login("user", "pass")

assertThat(loginSucceeded.isSuccess).isTrue()
assertThat(matrixClientsHolder.getOrNull(A_SESSION_ID)).isNotNull()
}
}
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ allprojects {
config.from(files("$rootDir/tools/detekt/detekt.yml"))
}
dependencies {
detektPlugins("io.nlopez.compose.rules:detekt:0.4.16")
detektPlugins("io.nlopez.compose.rules:detekt:0.4.17")
}

// KtLint
Expand Down
2 changes: 2 additions & 0 deletions fastlane/metadata/android/en-US/changelogs/40007030.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Main changes in this version: TODO.
Full changelog: https://github.com/element-hq/element-x-android/releases
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only
* Please see LICENSE in the repository root for full details.
*/

package io.element.android.features.call.api

import io.element.android.libraries.matrix.api.core.RoomId

/**
* Value for the local current call.
*/
sealed interface CurrentCall {
data object None : CurrentCall

data class RoomCall(
val roomId: RoomId,
) : CurrentCall

data class ExternalUrl(
val url: String,
) : CurrentCall
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only
* Please see LICENSE in the repository root for full details.
*/

package io.element.android.features.call.api

import kotlinx.coroutines.flow.StateFlow

interface CurrentCallService {
/**
* The current call state flow, which will be updated when the active call changes.
* This value reflect the local state of the call. It is not updated if the user answers
* a call from another session.
*/
val currentCall: StateFlow<CurrentCall>
}
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ private fun WebView.setup(
allowFileAccess = true
domStorageEnabled = true
mediaPlaybackRequiresUserGesture = false
@Suppress("DEPRECATION")
databaseEnabled = true
loadsImagesAutomatically = true
userAgentString = userAgent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import androidx.core.content.IntentCompat
import androidx.core.util.Consumer
import androidx.lifecycle.Lifecycle
import io.element.android.features.call.api.CallType
import io.element.android.features.call.api.CallType.ExternalUrl
import io.element.android.features.call.impl.DefaultElementCallEntryPoint
import io.element.android.features.call.impl.di.CallBindings
import io.element.android.features.call.impl.pip.PictureInPictureEvents
Expand All @@ -44,11 +45,14 @@ import io.element.android.features.call.impl.pip.PipView
import io.element.android.features.call.impl.services.CallForegroundService
import io.element.android.features.call.impl.utils.CallIntentDataParser
import io.element.android.libraries.architecture.bindings
import io.element.android.libraries.core.log.logger.LoggerTag
import io.element.android.libraries.designsystem.theme.ElementThemeApp
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
import timber.log.Timber
import javax.inject.Inject

private val loggerTag = LoggerTag("ElementCallActivity")

class ElementCallActivity :
AppCompatActivity(),
CallScreenNavigator,
Expand Down Expand Up @@ -132,7 +136,7 @@ class ElementCallActivity :
DisposableEffect(Unit) {
val listener = Runnable {
if (requestPermissionCallback != null) {
Timber.w("Ignoring onUserLeaveHint event because user is asked to grant permissions")
Timber.tag(loggerTag.value).w("Ignoring onUserLeaveHint event because user is asked to grant permissions")
} else {
pipEventSink(PictureInPictureEvents.EnterPictureInPicture)
}
Expand All @@ -146,7 +150,7 @@ class ElementCallActivity :
val onPictureInPictureModeChangedListener = Consumer { _: PictureInPictureModeChangedInfo ->
pipEventSink(PictureInPictureEvents.OnPictureInPictureModeChanged(isInPictureInPictureMode))
if (!isInPictureInPictureMode && !lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
Timber.d("Exiting PiP mode: Hangup the call")
Timber.tag(loggerTag.value).d("Exiting PiP mode: Hangup the call")
eventSink?.invoke(CallScreenEvents.Hangup)
}
}
Expand Down Expand Up @@ -185,23 +189,23 @@ class ElementCallActivity :

private fun setCallType(intent: Intent?) {
val callType = intent?.let {
IntentCompat.getParcelableExtra(it, DefaultElementCallEntryPoint.EXTRA_CALL_TYPE, CallType::class.java)
IntentCompat.getParcelableExtra(intent, DefaultElementCallEntryPoint.EXTRA_CALL_TYPE, CallType::class.java)
?: intent.dataString?.let(::parseUrl)?.let(::ExternalUrl)
}
val intentUrl = intent?.dataString?.let(::parseUrl)
when {
// Re-opened the activity but we have no url to load or a cached one, finish the activity
intent?.dataString == null && callType == null && webViewTarget.value == null -> finish()
callType != null -> {
webViewTarget.value = callType
presenter = presenterFactory.create(callType, this)
}
intentUrl != null -> {
val fallbackInputs = CallType.ExternalUrl(intentUrl)
webViewTarget.value = fallbackInputs
presenter = presenterFactory.create(fallbackInputs, this)
}
// Coming back from notification, do nothing
else -> return
val currentCallType = webViewTarget.value
if (currentCallType == null && callType == null) {
Timber.tag(loggerTag.value).d("Re-opened the activity but we have no url to load or a cached one, finish the activity")
finish()
} else if (currentCallType == null) {
Timber.tag(loggerTag.value).d("Set the call type and create the presenter")
webViewTarget.value = callType
presenter = presenterFactory.create(callType!!, this)
} else if (callType != currentCallType) {
Timber.tag(loggerTag.value).d("User starts another call, restart the Activity")
setIntent(intent)
recreate()
} else {
Timber.tag(loggerTag.value).d("Coming back from notification, do nothing")
}
}

Expand Down
Loading

0 comments on commit 183ffd2

Please sign in to comment.