Skip to content

Commit cfc0fc9

Browse files
committed
Merge branch 'release/0.6.2' into main
2 parents da57b04 + 3ec38a1 commit cfc0fc9

File tree

46 files changed

+1166
-23
lines changed

Some content is hidden

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

46 files changed

+1166
-23
lines changed

CHANGES.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,29 @@
1+
Changes in Element X v0.6.1 (2024-09-17)
2+
========================================
3+
4+
### ✨ Features
5+
* Add forced logout flow when the proxy is no longer available by @jmartinesp in https://github.com/element-hq/element-x-android/pull/3458
6+
* Temporary account creation using Element Web. by @bmarty in https://github.com/element-hq/element-x-android/pull/3467
7+
8+
### 🙌 Improvements
9+
* Feature/valere/invisible crypto feature flag by @BillCarsonFr in https://github.com/element-hq/element-x-android/pull/3451
10+
* 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
11+
* Update pinned message actions by @ganfra in https://github.com/element-hq/element-x-android/pull/3438
12+
13+
### 🐛 Bugfixes
14+
* Fix events blinking at the beginning of DM by @bmarty in https://github.com/element-hq/element-x-android/pull/3449
15+
* 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
16+
17+
### 🗣 Translations
18+
* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/3464
19+
* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/3469
20+
* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/3476
21+
* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/3477
22+
23+
### Others
24+
* Upgrade Rust sdk to 0.2.45 by @bmarty in https://github.com/element-hq/element-x-android/pull/3472
25+
* SDK 0.2.46 by @bmarty in https://github.com/element-hq/element-x-android/pull/3475
26+
127
Changes in Element X v0.6.0 (2024-09-12)
228
========================================
329

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
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.
2+
Full changelog: https://github.com/element-hq/element-x-android/releases
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* Copyright 2024 New Vector Ltd.
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only
5+
* Please see LICENSE in the repository root for full details.
6+
*/
7+
plugins {
8+
id("io.element.android-compose-library")
9+
}
10+
11+
android {
12+
namespace = "io.element.android.features.deactivation.api"
13+
}
14+
15+
dependencies {
16+
implementation(projects.libraries.architecture)
17+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*
2+
* Copyright 2024 New Vector Ltd.
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only
5+
* Please see LICENSE in the repository root for full details.
6+
*/
7+
8+
package io.element.android.features.deactivation.api
9+
10+
import io.element.android.libraries.architecture.SimpleFeatureEntryPoint
11+
12+
interface AccountDeactivationEntryPoint : SimpleFeatureEntryPoint
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2024 New Vector Ltd.
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only
5+
* Please see LICENSE in the repository root for full details.
6+
*/
7+
8+
plugins {
9+
id("io.element.android-compose-library")
10+
alias(libs.plugins.anvil)
11+
id("kotlin-parcelize")
12+
}
13+
14+
android {
15+
namespace = "io.element.android.features.deactivation.impl"
16+
17+
testOptions {
18+
unitTests {
19+
isIncludeAndroidResources = true
20+
}
21+
}
22+
}
23+
24+
anvil {
25+
generateDaggerFactories.set(true)
26+
}
27+
28+
dependencies {
29+
implementation(projects.anvilannotations)
30+
anvil(projects.anvilcodegen)
31+
implementation(projects.libraries.androidutils)
32+
implementation(projects.libraries.core)
33+
implementation(projects.libraries.architecture)
34+
implementation(projects.libraries.matrix.api)
35+
implementation(projects.libraries.designsystem)
36+
implementation(projects.libraries.uiStrings)
37+
api(projects.features.deactivation.api)
38+
39+
testImplementation(libs.test.junit)
40+
testImplementation(libs.coroutines.test)
41+
testImplementation(libs.molecule.runtime)
42+
testImplementation(libs.test.truth)
43+
testImplementation(libs.test.turbine)
44+
testImplementation(libs.test.robolectric)
45+
testImplementation(libs.androidx.compose.ui.test.junit)
46+
testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
47+
testImplementation(projects.libraries.matrix.test)
48+
testImplementation(projects.tests.testutils)
49+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
* Copyright 2024 New Vector Ltd.
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only
5+
* Please see LICENSE in the repository root for full details.
6+
*/
7+
8+
package io.element.android.features.logout.impl
9+
10+
sealed interface AccountDeactivationEvents {
11+
data class SetEraseData(val eraseData: Boolean) : AccountDeactivationEvents
12+
data class SetPassword(val password: String) : AccountDeactivationEvents
13+
data class DeactivateAccount(val isRetry: Boolean) : AccountDeactivationEvents
14+
data object CloseDialogs : AccountDeactivationEvents
15+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright 2024 New Vector Ltd.
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only
5+
* Please see LICENSE in the repository root for full details.
6+
*/
7+
8+
package io.element.android.features.logout.impl
9+
10+
import androidx.compose.runtime.Composable
11+
import androidx.compose.ui.Modifier
12+
import com.bumble.appyx.core.modality.BuildContext
13+
import com.bumble.appyx.core.node.Node
14+
import com.bumble.appyx.core.plugin.Plugin
15+
import dagger.assisted.Assisted
16+
import dagger.assisted.AssistedInject
17+
import io.element.android.anvilannotations.ContributesNode
18+
import io.element.android.libraries.di.SessionScope
19+
20+
@ContributesNode(SessionScope::class)
21+
class AccountDeactivationNode @AssistedInject constructor(
22+
@Assisted buildContext: BuildContext,
23+
@Assisted plugins: List<Plugin>,
24+
private val presenter: AccountDeactivationPresenter,
25+
) : Node(buildContext, plugins = plugins) {
26+
@Composable
27+
override fun View(modifier: Modifier) {
28+
val state = presenter.present()
29+
AccountDeactivationView(
30+
state = state,
31+
onBackClick = ::navigateUp,
32+
modifier = modifier,
33+
)
34+
}
35+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright 2024 New Vector Ltd.
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only
5+
* Please see LICENSE in the repository root for full details.
6+
*/
7+
8+
package io.element.android.features.logout.impl
9+
10+
import androidx.compose.runtime.Composable
11+
import androidx.compose.runtime.MutableState
12+
import androidx.compose.runtime.mutableStateOf
13+
import androidx.compose.runtime.remember
14+
import androidx.compose.runtime.rememberCoroutineScope
15+
import io.element.android.libraries.architecture.AsyncAction
16+
import io.element.android.libraries.architecture.Presenter
17+
import io.element.android.libraries.architecture.runCatchingUpdatingState
18+
import io.element.android.libraries.matrix.api.MatrixClient
19+
import kotlinx.coroutines.CoroutineScope
20+
import kotlinx.coroutines.launch
21+
import javax.inject.Inject
22+
23+
class AccountDeactivationPresenter @Inject constructor(
24+
private val matrixClient: MatrixClient,
25+
) : Presenter<AccountDeactivationState> {
26+
@Composable
27+
override fun present(): AccountDeactivationState {
28+
val localCoroutineScope = rememberCoroutineScope()
29+
val action: MutableState<AsyncAction<Unit>> = remember {
30+
mutableStateOf(AsyncAction.Uninitialized)
31+
}
32+
33+
val formState = remember { mutableStateOf(DeactivateFormState.Default) }
34+
35+
fun handleEvents(event: AccountDeactivationEvents) {
36+
when (event) {
37+
is AccountDeactivationEvents.SetEraseData -> {
38+
updateFormState(formState) {
39+
copy(eraseData = event.eraseData)
40+
}
41+
}
42+
is AccountDeactivationEvents.SetPassword -> {
43+
updateFormState(formState) {
44+
copy(password = event.password)
45+
}
46+
}
47+
is AccountDeactivationEvents.DeactivateAccount ->
48+
if (action.value.isConfirming() || event.isRetry) {
49+
localCoroutineScope.deactivateAccount(
50+
formState = formState.value,
51+
action
52+
)
53+
} else {
54+
action.value = AsyncAction.Confirming
55+
}
56+
AccountDeactivationEvents.CloseDialogs -> {
57+
action.value = AsyncAction.Uninitialized
58+
}
59+
}
60+
}
61+
62+
return AccountDeactivationState(
63+
deactivateFormState = formState.value,
64+
accountDeactivationAction = action.value,
65+
eventSink = ::handleEvents
66+
)
67+
}
68+
69+
private fun updateFormState(formState: MutableState<DeactivateFormState>, updateLambda: DeactivateFormState.() -> DeactivateFormState) {
70+
formState.value = updateLambda(formState.value)
71+
}
72+
73+
private fun CoroutineScope.deactivateAccount(
74+
formState: DeactivateFormState,
75+
action: MutableState<AsyncAction<Unit>>,
76+
) = launch {
77+
suspend {
78+
matrixClient.deactivateAccount(
79+
password = formState.password,
80+
eraseData = formState.eraseData,
81+
).getOrThrow()
82+
}.runCatchingUpdatingState(action)
83+
}
84+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright 2024 New Vector Ltd.
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only
5+
* Please see LICENSE in the repository root for full details.
6+
*/
7+
8+
package io.element.android.features.logout.impl
9+
10+
import android.os.Parcelable
11+
import io.element.android.libraries.architecture.AsyncAction
12+
import kotlinx.parcelize.Parcelize
13+
14+
data class AccountDeactivationState(
15+
val deactivateFormState: DeactivateFormState,
16+
val accountDeactivationAction: AsyncAction<Unit>,
17+
val eventSink: (AccountDeactivationEvents) -> Unit,
18+
) {
19+
val submitEnabled: Boolean
20+
get() = accountDeactivationAction is AsyncAction.Uninitialized &&
21+
deactivateFormState.password.isNotEmpty()
22+
}
23+
24+
@Parcelize
25+
data class DeactivateFormState(
26+
val eraseData: Boolean,
27+
val password: String
28+
) : Parcelable {
29+
companion object {
30+
val Default = DeactivateFormState(false, "")
31+
}
32+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2024 New Vector Ltd.
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only
5+
* Please see LICENSE in the repository root for full details.
6+
*/
7+
8+
package io.element.android.features.logout.impl
9+
10+
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
11+
import io.element.android.libraries.architecture.AsyncAction
12+
13+
open class AccountDeactivationStateProvider : PreviewParameterProvider<AccountDeactivationState> {
14+
private val filledForm = aDeactivateFormState(eraseData = true, password = "password")
15+
override val values: Sequence<AccountDeactivationState>
16+
get() = sequenceOf(
17+
anAccountDeactivationState(),
18+
anAccountDeactivationState(
19+
deactivateFormState = filledForm
20+
),
21+
anAccountDeactivationState(
22+
deactivateFormState = filledForm,
23+
accountDeactivationAction = AsyncAction.Confirming,
24+
),
25+
anAccountDeactivationState(
26+
deactivateFormState = filledForm,
27+
accountDeactivationAction = AsyncAction.Loading
28+
),
29+
anAccountDeactivationState(
30+
deactivateFormState = filledForm,
31+
accountDeactivationAction = AsyncAction.Failure(Exception("Failed to deactivate account"))
32+
),
33+
)
34+
}
35+
36+
internal fun aDeactivateFormState(
37+
eraseData: Boolean = false,
38+
password: String = "",
39+
) = DeactivateFormState(
40+
eraseData = eraseData,
41+
password = password,
42+
)
43+
44+
internal fun anAccountDeactivationState(
45+
deactivateFormState: DeactivateFormState = aDeactivateFormState(),
46+
accountDeactivationAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
47+
eventSink: (AccountDeactivationEvents) -> Unit = {},
48+
) = AccountDeactivationState(
49+
deactivateFormState = deactivateFormState,
50+
accountDeactivationAction = accountDeactivationAction,
51+
eventSink = eventSink,
52+
)

0 commit comments

Comments
 (0)