Skip to content

Commit

Permalink
Merge branch 'release/0.6.2' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
bmarty committed Sep 17, 2024
2 parents da57b04 + 3ec38a1 commit cfc0fc9
Show file tree
Hide file tree
Showing 46 changed files with 1,166 additions and 23 deletions.
26 changes: 26 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,29 @@
Changes in Element X v0.6.1 (2024-09-17)
========================================

### ✨ Features
* Add forced logout flow when the proxy is no longer available by @jmartinesp in https://github.com/element-hq/element-x-android/pull/3458
* Temporary account creation using Element Web. by @bmarty in https://github.com/element-hq/element-x-android/pull/3467

### 🙌 Improvements
* Feature/valere/invisible crypto feature flag by @BillCarsonFr in https://github.com/element-hq/element-x-android/pull/3451
* Require acknowledgement to send to a verified user if their identity changed or if a device is unverified. by @ganfra in https://github.com/element-hq/element-x-android/pull/3461
* Update pinned message actions by @ganfra in https://github.com/element-hq/element-x-android/pull/3438

### 🐛 Bugfixes
* Fix events blinking at the beginning of DM by @bmarty in https://github.com/element-hq/element-x-android/pull/3449
* Fix not being able to decline an invite from the room list by @jmartinesp in https://github.com/element-hq/element-x-android/pull/3466

### 🗣 Translations
* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/3464
* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/3469
* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/3476
* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/3477

### Others
* Upgrade Rust sdk to 0.2.45 by @bmarty in https://github.com/element-hq/element-x-android/pull/3472
* SDK 0.2.46 by @bmarty in https://github.com/element-hq/element-x-android/pull/3475

Changes in Element X v0.6.0 (2024-09-12)
========================================

Expand Down
2 changes: 2 additions & 0 deletions fastlane/metadata/android/en-US/changelogs/40006020.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Element X is the new generation of Element for professional and personal use on mobile. It’s the fastest Matrix client with a seamless & intuitive user interface.
Full changelog: https://github.com/element-hq/element-x-android/releases
17 changes: 17 additions & 0 deletions features/deactivation/api/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only
* Please see LICENSE in the repository root for full details.
*/
plugins {
id("io.element.android-compose-library")
}

android {
namespace = "io.element.android.features.deactivation.api"
}

dependencies {
implementation(projects.libraries.architecture)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* 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.deactivation.api

import io.element.android.libraries.architecture.SimpleFeatureEntryPoint

interface AccountDeactivationEntryPoint : SimpleFeatureEntryPoint
49 changes: 49 additions & 0 deletions features/deactivation/impl/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only
* Please see LICENSE in the repository root for full details.
*/

plugins {
id("io.element.android-compose-library")
alias(libs.plugins.anvil)
id("kotlin-parcelize")
}

android {
namespace = "io.element.android.features.deactivation.impl"

testOptions {
unitTests {
isIncludeAndroidResources = true
}
}
}

anvil {
generateDaggerFactories.set(true)
}

dependencies {
implementation(projects.anvilannotations)
anvil(projects.anvilcodegen)
implementation(projects.libraries.androidutils)
implementation(projects.libraries.core)
implementation(projects.libraries.architecture)
implementation(projects.libraries.matrix.api)
implementation(projects.libraries.designsystem)
implementation(projects.libraries.uiStrings)
api(projects.features.deactivation.api)

testImplementation(libs.test.junit)
testImplementation(libs.coroutines.test)
testImplementation(libs.molecule.runtime)
testImplementation(libs.test.truth)
testImplementation(libs.test.turbine)
testImplementation(libs.test.robolectric)
testImplementation(libs.androidx.compose.ui.test.junit)
testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.tests.testutils)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* 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.logout.impl

sealed interface AccountDeactivationEvents {
data class SetEraseData(val eraseData: Boolean) : AccountDeactivationEvents
data class SetPassword(val password: String) : AccountDeactivationEvents
data class DeactivateAccount(val isRetry: Boolean) : AccountDeactivationEvents
data object CloseDialogs : AccountDeactivationEvents
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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.logout.impl

import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode
import io.element.android.libraries.di.SessionScope

@ContributesNode(SessionScope::class)
class AccountDeactivationNode @AssistedInject constructor(
@Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>,
private val presenter: AccountDeactivationPresenter,
) : Node(buildContext, plugins = plugins) {
@Composable
override fun View(modifier: Modifier) {
val state = presenter.present()
AccountDeactivationView(
state = state,
onBackClick = ::navigateUp,
modifier = modifier,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* 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.logout.impl

import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.runCatchingUpdatingState
import io.element.android.libraries.matrix.api.MatrixClient
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import javax.inject.Inject

class AccountDeactivationPresenter @Inject constructor(
private val matrixClient: MatrixClient,
) : Presenter<AccountDeactivationState> {
@Composable
override fun present(): AccountDeactivationState {
val localCoroutineScope = rememberCoroutineScope()
val action: MutableState<AsyncAction<Unit>> = remember {
mutableStateOf(AsyncAction.Uninitialized)
}

val formState = remember { mutableStateOf(DeactivateFormState.Default) }

fun handleEvents(event: AccountDeactivationEvents) {
when (event) {
is AccountDeactivationEvents.SetEraseData -> {
updateFormState(formState) {
copy(eraseData = event.eraseData)
}
}
is AccountDeactivationEvents.SetPassword -> {
updateFormState(formState) {
copy(password = event.password)
}
}
is AccountDeactivationEvents.DeactivateAccount ->
if (action.value.isConfirming() || event.isRetry) {
localCoroutineScope.deactivateAccount(
formState = formState.value,
action
)
} else {
action.value = AsyncAction.Confirming
}
AccountDeactivationEvents.CloseDialogs -> {
action.value = AsyncAction.Uninitialized
}
}
}

return AccountDeactivationState(
deactivateFormState = formState.value,
accountDeactivationAction = action.value,
eventSink = ::handleEvents
)
}

private fun updateFormState(formState: MutableState<DeactivateFormState>, updateLambda: DeactivateFormState.() -> DeactivateFormState) {
formState.value = updateLambda(formState.value)
}

private fun CoroutineScope.deactivateAccount(
formState: DeactivateFormState,
action: MutableState<AsyncAction<Unit>>,
) = launch {
suspend {
matrixClient.deactivateAccount(
password = formState.password,
eraseData = formState.eraseData,
).getOrThrow()
}.runCatchingUpdatingState(action)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* 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.logout.impl

import android.os.Parcelable
import io.element.android.libraries.architecture.AsyncAction
import kotlinx.parcelize.Parcelize

data class AccountDeactivationState(
val deactivateFormState: DeactivateFormState,
val accountDeactivationAction: AsyncAction<Unit>,
val eventSink: (AccountDeactivationEvents) -> Unit,
) {
val submitEnabled: Boolean
get() = accountDeactivationAction is AsyncAction.Uninitialized &&
deactivateFormState.password.isNotEmpty()
}

@Parcelize
data class DeactivateFormState(
val eraseData: Boolean,
val password: String
) : Parcelable {
companion object {
val Default = DeactivateFormState(false, "")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* 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.logout.impl

import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.architecture.AsyncAction

open class AccountDeactivationStateProvider : PreviewParameterProvider<AccountDeactivationState> {
private val filledForm = aDeactivateFormState(eraseData = true, password = "password")
override val values: Sequence<AccountDeactivationState>
get() = sequenceOf(
anAccountDeactivationState(),
anAccountDeactivationState(
deactivateFormState = filledForm
),
anAccountDeactivationState(
deactivateFormState = filledForm,
accountDeactivationAction = AsyncAction.Confirming,
),
anAccountDeactivationState(
deactivateFormState = filledForm,
accountDeactivationAction = AsyncAction.Loading
),
anAccountDeactivationState(
deactivateFormState = filledForm,
accountDeactivationAction = AsyncAction.Failure(Exception("Failed to deactivate account"))
),
)
}

internal fun aDeactivateFormState(
eraseData: Boolean = false,
password: String = "",
) = DeactivateFormState(
eraseData = eraseData,
password = password,
)

internal fun anAccountDeactivationState(
deactivateFormState: DeactivateFormState = aDeactivateFormState(),
accountDeactivationAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
eventSink: (AccountDeactivationEvents) -> Unit = {},
) = AccountDeactivationState(
deactivateFormState = deactivateFormState,
accountDeactivationAction = accountDeactivationAction,
eventSink = eventSink,
)
Loading

0 comments on commit cfc0fc9

Please sign in to comment.