Skip to content

Commit

Permalink
feat: Inform user about enabling Ent-to-End Identity (WPB-308) (#1903)
Browse files Browse the repository at this point in the history
* feat: Inform user about enabling End to End identity

* feat: Inform user about enabling End to End identity: updated kalium

* feat: Inform user about enabling End to End identity: ready for review

* feat: Inform user about enabling Ent-to-End Identity: code style fix

* feat: Inform user about enabling Ent-to-End Identity: tests fix

* feat: Inform user about enabling Ent-to-End Identity: review

* feat: Inform user about enabling Ent-to-End Identity: updated kalium

* feat: Inform user about enabling Ent-to-End Identity: review
  • Loading branch information
borichellow authored Jul 5, 2023
1 parent 8438b3e commit 30a7692
Show file tree
Hide file tree
Showing 8 changed files with 269 additions and 3 deletions.
12 changes: 11 additions & 1 deletion app/src/main/kotlin/com/wire/android/ui/home/FeatureFlagState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
package com.wire.android.ui.home

import com.wire.android.ui.home.messagecomposer.state.SelfDeletionDuration
import kotlin.time.Duration

data class FeatureFlagState(
val showFileSharingDialog: Boolean = false,
Expand All @@ -30,9 +31,18 @@ data class FeatureFlagState(
val isGuestRoomLinkEnabled: Boolean = true,
val shouldShowSelfDeletingMessagesDialog: Boolean = false,
val enforcedTimeoutDuration: SelfDeletionDuration = SelfDeletionDuration.None,
val areSelfDeletedMessagesEnabled: Boolean = true
val areSelfDeletedMessagesEnabled: Boolean = true,
val e2EIRequired: E2EIRequired? = null,
val e2EISnoozeInfo: E2EISnooze? = null
) {
enum class SharingRestrictedState {
NONE, NO_USER, RESTRICTED_IN_TEAM
}

data class E2EISnooze(val timeLeft: Duration)

sealed class E2EIRequired {
data class WithGracePeriod(val timeLeft: Duration) : E2EIRequired()
object NoGracePeriod : E2EIRequired()
}
}
111 changes: 111 additions & 0 deletions app/src/main/kotlin/com/wire/android/ui/home/HomeDialogs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,24 @@
*
*/

@file:Suppress("TooManyFunctions")
package com.wire.android.ui.home

import android.content.Context
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.window.DialogProperties
import com.wire.android.R
import com.wire.android.ui.common.WireDialog
import com.wire.android.ui.common.WireDialogButtonProperties
import com.wire.android.ui.common.WireDialogButtonType
import com.wire.android.ui.home.messagecomposer.state.SelfDeletionDuration
import com.wire.android.ui.theme.WireTheme
import com.wire.android.util.CustomTabsHelper
import com.wire.android.util.toTimeLongLabelUiText
import com.wire.android.util.ui.PreviewMultipleThemes
import kotlin.time.Duration.Companion.seconds

@Composable
fun FileRestrictionDialog(
Expand Down Expand Up @@ -131,6 +135,113 @@ fun WelcomeNewUserDialog(
)
}

@Composable
fun E2EIRequiredDialog(
result: FeatureFlagState.E2EIRequired,
getCertificate: () -> Unit,
snoozeDialog: (FeatureFlagState.E2EIRequired.WithGracePeriod) -> Unit,
) {
when (result) {
FeatureFlagState.E2EIRequired.NoGracePeriod -> E2EIdRequiredNoSnoozeDialog(getCertificate = getCertificate)
is FeatureFlagState.E2EIRequired.WithGracePeriod -> E2EIdRequiredWithSnoozeDialog(
result = result,
getCertificate = getCertificate,
snoozeDialog = snoozeDialog
)
}
}

@Composable
fun E2EIdRequiredWithSnoozeDialog(
result: FeatureFlagState.E2EIRequired.WithGracePeriod,
getCertificate: () -> Unit,
snoozeDialog: (FeatureFlagState.E2EIRequired.WithGracePeriod) -> Unit
) {
WireDialog(
title = stringResource(id = R.string.end_to_end_identity_required_dialog_title),
text = stringResource(id = R.string.end_to_end_identity_required_dialog_text),
onDismiss = { snoozeDialog(result) },
optionButton1Properties = WireDialogButtonProperties(
onClick = getCertificate,
text = stringResource(id = R.string.end_to_end_identity_required_dialog_positive_button),
type = WireDialogButtonType.Primary,
),
optionButton2Properties = WireDialogButtonProperties(
onClick = { snoozeDialog(result) },
text = stringResource(id = R.string.end_to_end_identity_required_dialog_snooze_button),
type = WireDialogButtonType.Secondary,
),
buttonsHorizontalAlignment = false,
properties = DialogProperties(
usePlatformDefaultWidth = false,
dismissOnBackPress = false,
dismissOnClickOutside = false
)
)
}

@Composable
fun E2EIdRequiredNoSnoozeDialog(getCertificate: () -> Unit) {
WireDialog(
title = stringResource(id = R.string.end_to_end_identity_required_dialog_title),
text = stringResource(id = R.string.end_to_end_identity_required_dialog_text_no_snooze),
onDismiss = getCertificate,
optionButton1Properties = WireDialogButtonProperties(
onClick = getCertificate,
text = stringResource(id = R.string.end_to_end_identity_required_dialog_positive_button),
type = WireDialogButtonType.Primary,
),
buttonsHorizontalAlignment = false,
properties = DialogProperties(
usePlatformDefaultWidth = false,
dismissOnBackPress = false,
dismissOnClickOutside = false
)
)
}

@Composable
fun E2EIdSnoozeDialog(
state: FeatureFlagState.E2EISnooze,
dismissDialog: () -> Unit
) {
val timeText = state.timeLeft.toTimeLongLabelUiText().asString()
WireDialog(
title = stringResource(id = R.string.end_to_end_identity_required_dialog_title),
text = stringResource(id = R.string.end_to_end_identity_snooze_dialog_text, timeText),
onDismiss = dismissDialog,
optionButton1Properties = WireDialogButtonProperties(
onClick = dismissDialog,
text = stringResource(id = R.string.label_ok),
type = WireDialogButtonType.Primary,
)
)
}

@PreviewMultipleThemes
@Composable
fun previewE2EIdRequiredWithSnoozeDialog() {
WireTheme {
E2EIdRequiredWithSnoozeDialog(FeatureFlagState.E2EIRequired.WithGracePeriod(2.seconds), {}) {}
}
}

@PreviewMultipleThemes
@Composable
fun previewE2EIdRequiredNoSnoozeDialog() {
WireTheme {
E2EIdRequiredNoSnoozeDialog {}
}
}

@PreviewMultipleThemes
@Composable
fun previewE2EIdSnoozeDialog() {
WireTheme {
E2EIdSnoozeDialog(FeatureFlagState.E2EISnooze(2.seconds)) {}
}
}

@PreviewMultipleThemes
@Composable
fun previewFileRestrictionDialog() {
Expand Down
17 changes: 16 additions & 1 deletion app/src/main/kotlin/com/wire/android/ui/home/HomeScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ fun HomeScreen(
with(featureFlagNotificationViewModel.featureFlagState) {
if (showFileSharingDialog) {
FileRestrictionDialog(
isFileSharingEnabled = featureFlagNotificationViewModel.featureFlagState.showFileSharingDialog,
isFileSharingEnabled = showFileSharingDialog,
hideDialogStatus = featureFlagNotificationViewModel::dismissFileSharingDialog
)
}
Expand All @@ -127,6 +127,21 @@ fun HomeScreen(
hideDialogStatus = featureFlagNotificationViewModel::dismissSelfDeletingMessagesDialog
)
}

e2EIRequired?.let {
E2EIRequiredDialog(
result = e2EIRequired,
getCertificate = featureFlagNotificationViewModel::getE2EICertificate,
snoozeDialog = featureFlagNotificationViewModel::snoozeE2EIdRequiredDialog
)
}

e2EISnoozeInfo?.let {
E2EIdSnoozeDialog(
state = e2EISnoozeInfo,
dismissDialog = featureFlagNotificationViewModel::dismissSnoozeE2EIdRequiredDialog
)
}
}

HomeContent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import com.wire.kalium.logic.data.user.UserId
import com.wire.kalium.logic.feature.selfDeletingMessages.TeamSelfDeleteTimer
import com.wire.kalium.logic.feature.session.CurrentSessionResult
import com.wire.kalium.logic.feature.session.CurrentSessionUseCase
import com.wire.kalium.logic.feature.user.E2EIRequiredResult
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.launch
Expand Down Expand Up @@ -82,6 +83,7 @@ class FeatureFlagNotificationViewModel @Inject constructor(
setFileSharingState(userId)
observeTeamSettingsSelfDeletionStatus(userId)
setGuestRoomLinkFeatureFlag(userId)
setE2EIRequiredState(userId)
}
}
}
Expand Down Expand Up @@ -147,6 +149,16 @@ class FeatureFlagNotificationViewModel @Inject constructor(
}
}

private fun setE2EIRequiredState(userId: UserId) = viewModelScope.launch {
coreLogic.getSessionScope(userId).observeE2EIRequired().collect { result ->
val state = when (result) {
is E2EIRequiredResult.WithGracePeriod -> FeatureFlagState.E2EIRequired.WithGracePeriod(result.gracePeriod)
E2EIRequiredResult.NoGracePeriod -> FeatureFlagState.E2EIRequired.NoGracePeriod
}
featureFlagState = featureFlagState.copy(e2EIRequired = state)
}
}

fun dismissSelfDeletingMessagesDialog() {
featureFlagState = featureFlagState.copy(shouldShowSelfDeletingMessagesDialog = false)
viewModelScope.launch {
Expand All @@ -167,4 +179,25 @@ class FeatureFlagNotificationViewModel @Inject constructor(
}
featureFlagState = featureFlagState.copy(shouldShowGuestRoomLinkDialog = false)
}

fun getE2EICertificate() {
// TODO do the magic
featureFlagState = featureFlagState.copy(e2EIRequired = null)
}

fun snoozeE2EIdRequiredDialog(result: FeatureFlagState.E2EIRequired.WithGracePeriod) {
featureFlagState = featureFlagState.copy(
e2EIRequired = null,
e2EISnoozeInfo = FeatureFlagState.E2EISnooze(result.timeLeft)
)
currentUserId?.let { userId ->
viewModelScope.launch {
coreLogic.getSessionScope(userId).markE2EIRequiredAsNotified()
}
}
}

fun dismissSnoozeE2EIdRequiredDialog() {
featureFlagState = featureFlagState.copy(e2EISnoozeInfo = null)
}
}
36 changes: 36 additions & 0 deletions app/src/main/kotlin/com/wire/android/util/DurationUtil.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Wire
* Copyright (C) 2023 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.android.util

import com.wire.android.R
import com.wire.android.util.ui.UIText
import kotlin.time.Duration

fun Duration.toTimeLongLabelUiText(): UIText.PluralResource = when {
inWholeDays >= DAYS_IN_WEEK -> {
val weeks = inWholeDays.toInt() / DAYS_IN_WEEK
UIText.PluralResource(R.plurals.weeks_long_label, weeks, weeks)
}

inWholeDays >= 1 -> UIText.PluralResource(R.plurals.days_long_label, inWholeDays.toInt(), inWholeDays)
inWholeHours >= 1 -> UIText.PluralResource(R.plurals.hours_long_label, inWholeHours.toInt(), inWholeHours)
inWholeMinutes >= 1 -> UIText.PluralResource(R.plurals.minutes_long_label, inWholeMinutes.toInt(), inWholeMinutes)
else -> UIText.PluralResource(R.plurals.seconds_long_label, inWholeSeconds.toInt(), inWholeSeconds)
}

private const val DAYS_IN_WEEK = 7
7 changes: 7 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1091,4 +1091,11 @@
<string name="app_not_found_for_action">No Application has been found to do Action</string>
<string name="delete_acount_dialog_title">Delete Account</string>
<string name="delete_acount_dialog_text">If you continue, will send a message via email. Follow the link to permanetly delete your account.</string>

<string name="end_to_end_identity_required_dialog_title">End-to-end identity certificate</string>
<string name="end_to_end_identity_required_dialog_text">As of today, your team uses end-to-end identity to make Wire’s usage more secure and practicable. The device verification takes place automatically using a certificate and replaces the previous manual process. This way, you communicate with the highest security standard.\n\nEnter the credentials of your identity provider in the next step to automatically get a verification certificate for this device.</string>
<string name="end_to_end_identity_required_dialog_text_no_snooze">Your team now uses end-to-end identity to make Wire’s usage more secure. The device verification takes place automatically using a certificate.\n\nEnter the credentials of your identity provider in the next step to automatically get a verification certificate for this device.</string>
<string name="end_to_end_identity_required_dialog_positive_button">Get certificate</string>
<string name="end_to_end_identity_required_dialog_snooze_button">Remind me later</string>
<string name="end_to_end_identity_snooze_dialog_text">You can get the certificate in your Wire settings during the next %1$s. Open Devices and select Get Certificate for your current device.\nTo continue using Wire without interruption, retrieve it in time – it doesn’t take long.</string>
</resources>
Loading

0 comments on commit 30a7692

Please sign in to comment.