Skip to content

Commit

Permalink
feat: legal hold UI - create all related dialogs [WPB-5446] (#2421)
Browse files Browse the repository at this point in the history
  • Loading branch information
saleniuk authored Nov 14, 2023
1 parent 12a31d6 commit bc967ac
Show file tree
Hide file tree
Showing 11 changed files with 690 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* 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.ui.legalhold.dialog.common

import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import com.wire.android.R
import com.wire.android.ui.theme.WireTheme
import com.wire.android.ui.theme.wireTypography
import com.wire.android.util.CustomTabsHelper
import com.wire.android.util.ui.PreviewMultipleThemes

@Composable
fun LearnMoreAboutLegalHoldButton(modifier: Modifier = Modifier) {
val context = LocalContext.current
val learnMoreUrl = stringResource(id = R.string.url_legal_hold_learn_more)
Text(
text = stringResource(R.string.legal_hold_learn_more_button),
style = MaterialTheme.wireTypography.body02,
textDecoration = TextDecoration.Underline,
textAlign = TextAlign.Center,
modifier = modifier.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null,
onClick = remember { { CustomTabsHelper.launchUrl(context, learnMoreUrl) } }
)
)
}

@Composable
@PreviewMultipleThemes
fun PreviewLearnMoreAboutLegalHoldButton() {
WireTheme {
LearnMoreAboutLegalHoldButton()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* 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.ui.legalhold.dialog.deactivated

import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
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.legalhold.dialog.common.LearnMoreAboutLegalHoldButton
import com.wire.android.ui.theme.WireTheme
import com.wire.android.ui.theme.wireDimensions
import com.wire.android.util.ui.PreviewMultipleThemes

@Composable
fun LegalHoldDeactivatedDialog(dialogDismissed: () -> Unit) {
WireDialog(
title = stringResource(id = R.string.legal_hold_deactivated_dialog_title),
text = stringResource(id = R.string.legal_hold_deactivated_dialog_description),
onDismiss = dialogDismissed,
optionButton1Properties = WireDialogButtonProperties(
onClick = dialogDismissed,
text = stringResource(id = R.string.label_ok),
type = WireDialogButtonType.Primary,
)
) {
LearnMoreAboutLegalHoldButton(modifier = Modifier.padding(bottom = MaterialTheme.wireDimensions.dialogTextsSpacing))
}
}

@Composable
@PreviewMultipleThemes
fun PreviewLegalHoldDeactivatedDialog() {
WireTheme {
LegalHoldDeactivatedDialog {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/*
* 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.ui.legalhold.dialog.requested

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.platform.SoftwareKeyboardController
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.window.DialogProperties
import androidx.hilt.navigation.compose.hiltViewModel
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.common.button.WireButtonState
import com.wire.android.ui.common.textfield.WirePasswordTextField
import com.wire.android.ui.common.textfield.WireTextFieldState
import com.wire.android.ui.legalhold.dialog.common.LearnMoreAboutLegalHoldButton
import com.wire.android.ui.theme.WireTheme
import com.wire.android.ui.theme.wireDimensions
import com.wire.android.ui.theme.wireTypography
import com.wire.android.util.extension.formatAsFingerPrint
import com.wire.android.util.ui.PreviewMultipleThemes

@Composable
fun LegalHoldRequestedDialog(
viewModel: LegalHoldRequestedViewModel = hiltViewModel()
) {
LegalHoldRequestedDialogContent(
state = viewModel.state,
passwordChanged = viewModel::passwordChanged,
notNowClicked = viewModel::notNowClicked,
acceptClicked = viewModel::acceptClicked,
)
}

@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun LegalHoldRequestedDialogContent(
state: LegalHoldRequestedState,
passwordChanged: (TextFieldValue) -> Unit,
notNowClicked: () -> Unit,
acceptClicked: () -> Unit,
) {
var keyboardController: SoftwareKeyboardController? = null
WireDialog(
title = stringResource(R.string.legal_hold_requested_dialog_title),
properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false, usePlatformDefaultWidth = false),
onDismiss = { keyboardController?.hide() },
dismissButtonProperties = WireDialogButtonProperties(
onClick = notNowClicked,
text = stringResource(id = R.string.legal_hold_requested_dialog_not_now_button),
state = WireButtonState.Default
),
optionButton1Properties = WireDialogButtonProperties(
onClick = {
keyboardController?.hide()
acceptClicked()
},
text = stringResource(R.string.legal_hold_requested_dialog_accept_button),
type = WireDialogButtonType.Primary,
loading = state.loading,
state = if (state.acceptEnabled) WireButtonState.Error else WireButtonState.Disabled
),
content = {
Column(
verticalArrangement = Arrangement.spacedBy(MaterialTheme.wireDimensions.dialogTextsSpacing),
modifier = Modifier.padding(vertical = MaterialTheme.wireDimensions.dialogTextsSpacing)
) {
Text(
text = stringResource(id = R.string.legal_hold_requested_dialog_description_device),
style = MaterialTheme.wireTypography.body01,
modifier = Modifier.fillMaxWidth()
)
Text(
text = state.legalHoldDeviceFingerprint.formatAsFingerPrint(),
style = MaterialTheme.wireTypography.body01,
fontFamily = FontFamily.Monospace,
modifier = Modifier.fillMaxWidth()
)
Text(
text = stringResource(id = R.string.legal_hold_requested_dialog_description_includes),
style = MaterialTheme.wireTypography.body01,
modifier = Modifier.fillMaxWidth()
)
LearnMoreAboutLegalHoldButton()
if (state.requiresPassword) {
Text(
text = stringResource(id = R.string.legal_hold_requested_dialog_enter_password),
style = MaterialTheme.wireTypography.body01,
modifier = Modifier.fillMaxWidth()
)
// keyboard controller from outside the Dialog doesn't work inside its content so we have to pass the state
// to the dialog's content and use keyboard controller from there
keyboardController = LocalSoftwareKeyboardController.current
val focusRequester = remember { FocusRequester() }
WirePasswordTextField(
value = state.password,
onValueChange = passwordChanged,
state = when {
state.error is LegalHoldRequestedError.InvalidCredentialsError ->
WireTextFieldState.Error(stringResource(id = R.string.remove_device_invalid_password))

state.loading -> WireTextFieldState.Disabled
else -> WireTextFieldState.Default
},
imeAction = ImeAction.Done,
keyboardActions = KeyboardActions(onDone = { keyboardController?.hide() }),
modifier = Modifier
.focusRequester(focusRequester)
.padding(bottom = MaterialTheme.wireDimensions.spacing8x)
.testTag("remove device password field"),
autofill = true
)
}
}
}
)
}

@Composable
@PreviewMultipleThemes
fun PreviewLegalHoldRequestedDialogWithPassword() {
WireTheme {
LegalHoldRequestedDialogContent(
LegalHoldRequestedState(legalHoldDeviceFingerprint = "0123456789ABCDEF", requiresPassword = true), {}, {}, {}
)
}
}

@Composable
@PreviewMultipleThemes
fun PreviewLegalHoldRequestedDialogWithoutPassword() {
WireTheme {
LegalHoldRequestedDialogContent(
LegalHoldRequestedState(legalHoldDeviceFingerprint = "0123456789ABCDEF", requiresPassword = false), {}, {}, {}
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* 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.ui.legalhold.dialog.requested

import androidx.compose.ui.text.input.TextFieldValue
import com.wire.kalium.logic.CoreFailure

data class LegalHoldRequestedState(
val done: Boolean = false,
val legalHoldDeviceFingerprint: String = "",
val password: TextFieldValue = TextFieldValue(""),
val requiresPassword: Boolean = false,
val loading: Boolean = false,
val acceptEnabled: Boolean = false,
val error: LegalHoldRequestedError = LegalHoldRequestedError.None,
)

sealed class LegalHoldRequestedError {
data object None : LegalHoldRequestedError()
data object InvalidCredentialsError : LegalHoldRequestedError()
data class GenericError(val coreFailure: CoreFailure) : LegalHoldRequestedError()
}
Loading

0 comments on commit bc967ac

Please sign in to comment.