Skip to content

Commit

Permalink
Merge branch 'element-hq:develop' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
daedric7 authored Jul 10, 2024
2 parents 5a9c48a + 0be7058 commit 9899669
Show file tree
Hide file tree
Showing 83 changed files with 339 additions and 192 deletions.
7 changes: 0 additions & 7 deletions appconfig/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,13 @@
*/
plugins {
id("io.element.android-library")
alias(libs.plugins.anvil)
}

android {
namespace = "io.element.android.appconfig"
}

anvil {
generateDaggerFactories.set(true)
}

dependencies {
implementation(libs.androidx.annotationjvm)
implementation(libs.dagger)
implementation(projects.libraries.di)
implementation(projects.libraries.matrix.api)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,44 +16,28 @@

package io.element.android.appconfig

import com.squareup.anvil.annotations.ContributesTo
import dagger.Module
import dagger.Provides
import io.element.android.libraries.di.AppScope
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds

/**
* Configuration for the lock screen feature.
* @property isPinMandatory Whether the PIN is mandatory or not.
* @property pinBlacklist Some PINs are forbidden.
* @property pinSize The size of the PIN.
* @property maxPinCodeAttemptsBeforeLogout Number of attempts before the user is logged out.
* @property gracePeriod Time period before locking the app once backgrounded.
* @property isStrongBiometricsEnabled Authentication with strong methods (fingerprint, some face/iris unlock implementations) is supported.
* @property isWeakBiometricsEnabled Authentication with weak methods (most face/iris unlock implementations) is supported.
*/
data class LockScreenConfig(
val isPinMandatory: Boolean,
val pinBlacklist: Set<String>,
val pinSize: Int,
val maxPinCodeAttemptsBeforeLogout: Int,
val gracePeriod: Duration,
val isStrongBiometricsEnabled: Boolean,
val isWeakBiometricsEnabled: Boolean,
)

@ContributesTo(AppScope::class)
@Module
object LockScreenConfigModule {
@Provides
fun providesLockScreenConfig(): LockScreenConfig = LockScreenConfig(
isPinMandatory = false,
pinBlacklist = setOf("0000", "1234"),
pinSize = 4,
maxPinCodeAttemptsBeforeLogout = 3,
gracePeriod = 0.seconds,
isStrongBiometricsEnabled = true,
isWeakBiometricsEnabled = true,
)
import kotlin.time.Duration.Companion.minutes

object LockScreenConfig {
/** Whether the PIN is mandatory or not. */
const val IS_PIN_MANDATORY: Boolean = false

/** Set of forbidden PIN codes. */
val FORBIDDEN_PIN_CODES: Set<String> = setOf("0000", "1234")

/** The size of the PIN. */
const val PIN_SIZE: Int = 4

/** Number of attempts before the user is logged out. */
const val MAX_PIN_CODE_ATTEMPTS_BEFORE_LOGOUT: Int = 3

/** Time period before locking the app once backgrounded. */
val GRACE_PERIOD: Duration = 2.minutes

/** Authentication with strong methods (fingerprint, some face/iris unlock implementations) is supported. */
const val IS_STRONG_BIOMETRICS_ENABLED: Boolean = true

/** Authentication with weak methods (most face/iris unlock implementations) is supported. */
const val IS_WEAK_BIOMETRICS_ENABLED: Boolean = true
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ open class AcceptDeclineInviteStateProvider : PreviewParameterProvider<AcceptDec
anAcceptDeclineInviteState(),
anAcceptDeclineInviteState(
invite = Optional.of(
InviteData(RoomId("!room:matrix.org"), isDirect = true, roomName = "Alice"),
InviteData(RoomId("!room:matrix.org"), isDm = true, roomName = "Alice"),
),
declineAction = AsyncAction.Confirming,
),
anAcceptDeclineInviteState(
invite = Optional.of(
InviteData(RoomId("!room:matrix.org"), isDirect = false, roomName = "Some room"),
InviteData(RoomId("!room:matrix.org"), isDm = false, roomName = "Some room"),
),
declineAction = AsyncAction.Confirming,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ import io.element.android.libraries.matrix.api.core.RoomId
data class InviteData(
val roomId: RoomId,
val roomName: String,
val isDirect: Boolean,
val isDm: Boolean,
)
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,13 @@ private fun DeclineConfirmationDialog(
onDismissClick: () -> Unit,
modifier: Modifier = Modifier
) {
val contentResource = if (invite.isDirect) {
val contentResource = if (invite.isDm) {
R.string.screen_invites_decline_direct_chat_message
} else {
R.string.screen_invites_decline_chat_message
}

val titleResource = if (invite.isDirect) {
val titleResource = if (invite.isDm) {
R.string.screen_invites_decline_direct_chat_title
} else {
R.string.screen_invites_decline_chat_title
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,12 +260,12 @@ class AcceptDeclineInvitePresenterTest {
private fun anInviteData(
roomId: RoomId = A_ROOM_ID,
name: String = A_ROOM_NAME,
isDirect: Boolean = false
isDm: Boolean = false
): InviteData {
return InviteData(
roomId = roomId,
roomName = name,
isDirect = isDirect
isDm = isDm
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
import io.element.android.libraries.matrix.api.room.RoomType
import io.element.android.libraries.matrix.api.room.isDm
import io.element.android.libraries.matrix.api.room.join.JoinRoom
import io.element.android.libraries.matrix.api.room.preview.RoomPreview
import io.element.android.libraries.matrix.ui.model.toInviteSender
Expand Down Expand Up @@ -173,7 +174,7 @@ private fun RoomPreview.toContentState(): ContentState {
topic = topic,
alias = canonicalAlias,
numberOfMembers = numberOfJoinedMembers,
isDirect = false,
isDm = false,
roomType = roomType,
roomAvatarUrl = avatarUrl,
joinAuthorisationStatus = when {
Expand All @@ -194,7 +195,7 @@ internal fun RoomDescription.toContentState(): ContentState {
topic = topic,
alias = alias,
numberOfMembers = numberOfMembers,
isDirect = false,
isDm = false,
roomType = RoomType.Room,
roomAvatarUrl = avatarUrl,
joinAuthorisationStatus = when (joinRule) {
Expand All @@ -213,7 +214,7 @@ internal fun MatrixRoomInfo.toContentState(): ContentState {
topic = topic,
alias = canonicalAlias,
numberOfMembers = activeMembersCount,
isDirect = isDirect,
isDm = isDm,
roomType = if (isSpace) RoomType.Space else RoomType.Room,
roomAvatarUrl = avatarUrl,
joinAuthorisationStatus = when {
Expand All @@ -233,7 +234,7 @@ internal fun ContentState.toInviteData(): InviteData? {
roomId = roomId,
// Note: name should not be null at this point, but use Id just in case...
roomName = name ?: roomId.value,
isDirect = isDirect
isDm = isDm
)
else -> null
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ sealed interface ContentState {
val topic: String?,
val alias: RoomAlias?,
val numberOfMembers: Long?,
val isDirect: Boolean,
val isDm: Boolean,
val roomType: RoomType,
val roomAvatarUrl: String?,
val joinAuthorisationStatus: JoinAuthorisationStatus,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
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.room.RoomType
import io.element.android.libraries.matrix.api.room.isDm
import io.element.android.libraries.matrix.ui.model.InviteSender

open class JoinRoomStateProvider : PreviewParameterProvider<JoinRoomState> {
Expand Down Expand Up @@ -84,6 +85,12 @@ open class JoinRoomStateProvider : PreviewParameterProvider<JoinRoomState> {
roomType = RoomType.Space,
)
),
aJoinRoomState(
contentState = aLoadedContentState(
name = "A DM",
isDm = true,
)
),
)
}

Expand All @@ -106,7 +113,7 @@ fun aLoadedContentState(
alias: RoomAlias? = RoomAlias("#exa:matrix.org"),
topic: String? = "Element X is a secure, private and decentralized messenger.",
numberOfMembers: Long? = null,
isDirect: Boolean = false,
isDm: Boolean = false,
roomType: RoomType = RoomType.Room,
roomAvatarUrl: String? = null,
joinAuthorisationStatus: JoinAuthorisationStatus = JoinAuthorisationStatus.Unknown
Expand All @@ -116,7 +123,7 @@ fun aLoadedContentState(
alias = alias,
topic = topic,
numberOfMembers = numberOfMembers,
isDirect = isDirect,
isDm = isDm,
roomType = roomType,
roomAvatarUrl = roomAvatarUrl,
joinAuthorisationStatus = joinAuthorisationStatus
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class JoinRoomPresenterTest {
assertThat(contentState.topic).isEqualTo(roomInfo.topic)
assertThat(contentState.alias).isEqualTo(roomInfo.canonicalAlias)
assertThat(contentState.numberOfMembers).isEqualTo(roomInfo.activeMembersCount)
assertThat(contentState.isDirect).isEqualTo(roomInfo.isDirect)
assertThat(contentState.isDm).isEqualTo(roomInfo.isDirect)
assertThat(contentState.roomAvatarUrl).isEqualTo(roomInfo.avatarUrl)
}
}
Expand Down Expand Up @@ -283,7 +283,7 @@ class JoinRoomPresenterTest {
assertThat(contentState.topic).isEqualTo(roomDescription.topic)
assertThat(contentState.alias).isEqualTo(roomDescription.alias)
assertThat(contentState.numberOfMembers).isEqualTo(roomDescription.numberOfMembers)
assertThat(contentState.isDirect).isFalse()
assertThat(contentState.isDm).isFalse()
assertThat(contentState.roomAvatarUrl).isEqualTo(roomDescription.avatarUrl)
}
}
Expand Down Expand Up @@ -398,7 +398,7 @@ class JoinRoomPresenterTest {
topic = "Room topic",
alias = RoomAlias("#alias:matrix.org"),
numberOfMembers = 2,
isDirect = false,
isDm = false,
roomType = RoomType.Room,
roomAvatarUrl = "avatarUrl",
joinAuthorisationStatus = JoinAuthorisationStatus.CanJoin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
import io.element.android.libraries.matrix.api.room.isDm
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ class DefaultLeaveRoomPresenterTest {
client = FakeMatrixClient().apply {
givenGetRoomResult(
roomId = A_ROOM_ID,
result = FakeMatrixRoom(activeMemberCount = 2, isDirect = true, isOneToOne = true),
result = FakeMatrixRoom(activeMemberCount = 2, isDirect = true),
)
}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package io.element.android.features.lockscreen.impl

import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.appconfig.LockScreenConfig
import io.element.android.features.lockscreen.api.LockScreenLockState
import io.element.android.features.lockscreen.api.LockScreenService
import io.element.android.features.lockscreen.impl.biometric.BiometricUnlockManager
Expand Down Expand Up @@ -55,7 +54,7 @@ class DefaultLockScreenService @Inject constructor(
private val coroutineScope: CoroutineScope,
private val sessionObserver: SessionObserver,
private val appForegroundStateService: AppForegroundStateService,
private val biometricUnlockManager: BiometricUnlockManager,
biometricUnlockManager: BiometricUnlockManager,
) : LockScreenService {
private val _lockState = MutableStateFlow<LockScreenLockState>(LockScreenLockState.Unlocked)
override val lockState: StateFlow<LockScreenLockState> = _lockState
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.element.android.features.lockscreen.impl

import com.squareup.anvil.annotations.ContributesTo
import dagger.Module
import dagger.Provides
import io.element.android.libraries.di.AppScope
import kotlin.time.Duration
import io.element.android.appconfig.LockScreenConfig as AppConfigLockScreenConfig

data class LockScreenConfig(
val isPinMandatory: Boolean,
val forbiddenPinCodes: Set<String>,
val pinSize: Int,
val maxPinCodeAttemptsBeforeLogout: Int,
val gracePeriod: Duration,
val isStrongBiometricsEnabled: Boolean,
val isWeakBiometricsEnabled: Boolean,
)

@ContributesTo(AppScope::class)
@Module
object LockScreenConfigModule {
@Provides
fun providesLockScreenConfig(): LockScreenConfig = LockScreenConfig(
isPinMandatory = AppConfigLockScreenConfig.IS_PIN_MANDATORY,
forbiddenPinCodes = AppConfigLockScreenConfig.FORBIDDEN_PIN_CODES,
pinSize = AppConfigLockScreenConfig.PIN_SIZE,
maxPinCodeAttemptsBeforeLogout = AppConfigLockScreenConfig.MAX_PIN_CODE_ATTEMPTS_BEFORE_LOGOUT,
gracePeriod = AppConfigLockScreenConfig.GRACE_PERIOD,
isStrongBiometricsEnabled = AppConfigLockScreenConfig.IS_STRONG_BIOMETRICS_ENABLED,
isWeakBiometricsEnabled = AppConfigLockScreenConfig.IS_WEAK_BIOMETRICS_ENABLED,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import androidx.compose.ui.res.stringResource
import androidx.core.content.getSystemService
import androidx.fragment.app.FragmentActivity
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.appconfig.LockScreenConfig
import io.element.android.features.lockscreen.impl.LockScreenConfig
import io.element.android.features.lockscreen.impl.R
import io.element.android.features.lockscreen.impl.storage.LockScreenStore
import io.element.android.libraries.cryptography.api.EncryptionDecryptionService
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import io.element.android.appconfig.LockScreenConfig
import io.element.android.features.lockscreen.impl.LockScreenConfig
import io.element.android.features.lockscreen.impl.biometric.BiometricUnlockManager
import io.element.android.features.lockscreen.impl.pin.PinCodeManager
import io.element.android.features.lockscreen.impl.storage.LockScreenStore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import io.element.android.appconfig.LockScreenConfig
import io.element.android.features.lockscreen.impl.LockScreenConfig
import io.element.android.features.lockscreen.impl.pin.PinCodeManager
import io.element.android.features.lockscreen.impl.pin.model.PinEntry
import io.element.android.features.lockscreen.impl.setup.pin.validation.PinValidator
Expand Down Expand Up @@ -76,7 +76,7 @@ class SetupPinPresenter @Inject constructor(
if (confirmPinEntry == choosePinEntry) {
pinCodeManager.createPinCode(confirmPinEntry.toText())
} else {
setupPinFailure = SetupPinFailure.PinsDontMatch
setupPinFailure = SetupPinFailure.PinsDoNotMatch
}
}
}
Expand All @@ -93,11 +93,11 @@ class SetupPinPresenter @Inject constructor(
}
SetupPinEvents.ClearFailure -> {
when (setupPinFailure) {
is SetupPinFailure.PinsDontMatch -> {
is SetupPinFailure.PinsDoNotMatch -> {
choosePinEntry = choosePinEntry.clear()
confirmPinEntry = confirmPinEntry.clear()
}
is SetupPinFailure.PinBlacklisted -> {
is SetupPinFailure.ForbiddenPin -> {
choosePinEntry = choosePinEntry.clear()
}
null -> Unit
Expand Down
Loading

0 comments on commit 9899669

Please sign in to comment.