Skip to content

Commit

Permalink
feat: create password protected conv invite link (#2099)
Browse files Browse the repository at this point in the history
  • Loading branch information
MohamadJaara committed Aug 18, 2023
1 parent 3a65370 commit 65fc8c7
Show file tree
Hide file tree
Showing 25 changed files with 1,262 additions and 130 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* 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.feature

import androidx.annotation.VisibleForTesting
import dagger.hilt.android.scopes.ViewModelScoped
import java.security.SecureRandom
import javax.inject.Inject

@ViewModelScoped
class GenerateRandomPasswordUseCase @Inject constructor() {

operator fun invoke(): String {

val secureRandom = SecureRandom()

val passwordLength = secureRandom.nextInt(MAX_LENGTH - MIN_LENGTH + 1) + MIN_LENGTH

return buildList<Char> {
add(lowercase[secureRandom.nextInt(lowercase.size)])
add(uppercase[secureRandom.nextInt(uppercase.size)])
add(digits[secureRandom.nextInt(digits.size)])
add(specialChars[secureRandom.nextInt(specialChars.size)])

repeat(passwordLength - FIXED_CHAR_COUNT) {
add(allCharacters[secureRandom.nextInt(allCharacters.size)])
}
}.shuffled(secureRandom).joinToString("")
}

@VisibleForTesting
companion object {
val lowercase: List<Char> = ('a'..'z').shuffled()
val uppercase: List<Char> = ('A'..'Z').shuffled()
val digits: List<Char> = ('0'..'9').shuffled()
val specialChars: List<Char> = "!@#$%^&*()_+[]{}|;:,.<>?-".toList().shuffled()

val allCharacters: List<Char> = (lowercase + uppercase + digits + specialChars).shuffled()

const val MIN_LENGTH = 15
const val MAX_LENGTH = 20
const val FIXED_CHAR_COUNT = 4
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,21 @@ import io.github.esentsov.PackagePrivate
@Composable
fun MenuBottomSheetItem(
title: String,
icon: @Composable () -> Unit,
icon: (@Composable () -> Unit)? = null,
action: (@Composable () -> Unit)? = null,
clickBlockParams: ClickBlockParams = ClickBlockParams(),
itemProvidedColor: Color = MaterialTheme.colorScheme.secondary,
onItemClick: () -> Unit = {}
onItemClick: () -> Unit = {},
enabled: Boolean = true,
) {
CompositionLocalProvider(LocalContentColor provides itemProvidedColor) {
val clickable = remember(onItemClick, clickBlockParams) { Clickable(clickBlockParams = clickBlockParams, onClick = onItemClick) }
val clickable = remember(onItemClick, clickBlockParams) {
Clickable(
clickBlockParams = clickBlockParams,
onClick = onItemClick,
enabled = enabled
)
}
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
Expand All @@ -73,8 +80,10 @@ fun MenuBottomSheetItem(
.clickable(clickable)
.padding(MaterialTheme.wireDimensions.conversationBottomSheetItemPadding)
) {
icon()
Spacer(modifier = Modifier.width(12.dp))
if (icon != null) {
icon()
Spacer(modifier = Modifier.width(12.dp))
}
MenuItemTitle(title = title)
if (action != null) {
Spacer(modifier = Modifier.width(MaterialTheme.wireDimensions.spacing12x))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,23 +56,40 @@ fun wireSendPrimaryButtonColors() = wirePrimaryButtonColors().copy(
)

@Composable
fun wireSecondaryButtonColors() = wireButtonColors(
enabled = MaterialTheme.wireColorScheme.secondaryButtonEnabled,
onEnabled = MaterialTheme.wireColorScheme.onSecondaryButtonEnabled,
enabledOutline = MaterialTheme.wireColorScheme.secondaryButtonEnabledOutline,
disabled = MaterialTheme.wireColorScheme.secondaryButtonDisabled,
onDisabled = MaterialTheme.wireColorScheme.onSecondaryButtonDisabled,
disabledOutline = MaterialTheme.wireColorScheme.secondaryButtonDisabledOutline,
selected = MaterialTheme.wireColorScheme.secondaryButtonSelected,
onSelected = MaterialTheme.wireColorScheme.onSecondaryButtonSelected,
selectedOutline = MaterialTheme.wireColorScheme.secondaryButtonSelectedOutline,
error = MaterialTheme.wireColorScheme.secondaryButtonEnabled,
onError = MaterialTheme.wireColorScheme.error,
errorOutline = MaterialTheme.wireColorScheme.secondaryButtonEnabledOutline,
positive = MaterialTheme.wireColorScheme.secondaryButtonEnabled,
onPositive = MaterialTheme.wireColorScheme.positive,
positiveOutline = MaterialTheme.wireColorScheme.secondaryButtonEnabledOutline,
ripple = MaterialTheme.wireColorScheme.secondaryButtonRipple
fun wireSecondaryButtonColors(
enabled: Color = MaterialTheme.wireColorScheme.secondaryButtonEnabled,
onEnabled: Color = MaterialTheme.wireColorScheme.onSecondaryButtonEnabled,
enabledOutline: Color = MaterialTheme.wireColorScheme.secondaryButtonEnabledOutline,
disabled: Color = MaterialTheme.wireColorScheme.secondaryButtonDisabled,
onDisabled: Color = MaterialTheme.wireColorScheme.onSecondaryButtonDisabled,
disabledOutline: Color = MaterialTheme.wireColorScheme.secondaryButtonDisabledOutline,
selected: Color = MaterialTheme.wireColorScheme.secondaryButtonSelected,
onSelected: Color = MaterialTheme.wireColorScheme.onSecondaryButtonSelected,
selectedOutline: Color = MaterialTheme.wireColorScheme.secondaryButtonSelectedOutline,
error: Color = MaterialTheme.wireColorScheme.secondaryButtonEnabled,
onError: Color = MaterialTheme.wireColorScheme.error,
errorOutline: Color = MaterialTheme.wireColorScheme.secondaryButtonEnabledOutline,
positive: Color = MaterialTheme.wireColorScheme.secondaryButtonEnabled,
onPositive: Color = MaterialTheme.wireColorScheme.positive,
positiveOutline: Color = MaterialTheme.wireColorScheme.secondaryButtonEnabledOutline,
ripple: Color = MaterialTheme.wireColorScheme.secondaryButtonRipple
) = wireButtonColors(
enabled = enabled,
onEnabled = onEnabled,
enabledOutline = enabledOutline,
disabled = disabled,
onDisabled = onDisabled,
disabledOutline = disabledOutline,
selected = selected,
onSelected = onSelected,
selectedOutline = selectedOutline,
error = error,
onError = onError,
errorOutline = errorOutline,
positive = positive,
onPositive = onPositive,
positiveOutline = positiveOutline,
ripple = ripple
)

@Composable
Expand All @@ -97,34 +114,44 @@ fun wireTertiaryButtonColors() = wireButtonColors(

@Composable
private fun wireButtonColors(
enabled: Color, onEnabled: Color, enabledOutline: Color,
disabled: Color, onDisabled: Color, disabledOutline: Color,
selected: Color, onSelected: Color, selectedOutline: Color,
error: Color, onError: Color, errorOutline: Color,
positive: Color, onPositive: Color, positiveOutline: Color,
enabled: Color, onEnabled: Color, enabledOutline: Color,
disabled: Color, onDisabled: Color, disabledOutline: Color,
selected: Color, onSelected: Color, selectedOutline: Color,
error: Color, onError: Color, errorOutline: Color,
positive: Color, onPositive: Color, positiveOutline: Color,
ripple: Color
) = WireButtonColors(
enabled, onEnabled, enabledOutline,
disabled, onDisabled, disabledOutline,
selected, onSelected, selectedOutline,
error, onError, errorOutline,
positive, onPositive, positiveOutline,
enabled, onEnabled, enabledOutline,
disabled, onDisabled, disabledOutline,
selected, onSelected, selectedOutline,
error, onError, errorOutline,
positive, onPositive, positiveOutline,
ripple
)

@Stable
data class WireButtonColors(
val enabled: Color, val onEnabled: Color, val enabledOutline: Color,
val disabled: Color, val onDisabled: Color, val disabledOutline: Color,
val selected: Color, val onSelected: Color, val selectedOutline: Color,
val error: Color, val onError: Color, val errorOutline: Color,
val positive: Color, val onPositive: Color, val positiveOutline: Color,
val enabled: Color,
val onEnabled: Color,
val enabledOutline: Color,
val disabled: Color,
val onDisabled: Color,
val disabledOutline: Color,
val selected: Color,
val onSelected: Color,
val selectedOutline: Color,
val error: Color,
val onError: Color,
val errorOutline: Color,
val positive: Color,
val onPositive: Color,
val positiveOutline: Color,
val ripple: Color
) {

@Composable
fun containerColor(state: WireButtonState, interactionSource: InteractionSource): State<Color> = animateColorAsState(
when(state) {
when (state) {
WireButtonState.Default -> enabled
WireButtonState.Disabled -> disabled
WireButtonState.Selected -> selected
Expand All @@ -134,8 +161,8 @@ data class WireButtonColors(
)

@Composable
fun outlineColor(state: WireButtonState, interactionSource: InteractionSource): State<Color> = animateColorAsState(
when(state) {
fun outlineColor(state: WireButtonState, interactionSource: InteractionSource): State<Color> = animateColorAsState(
when (state) {
WireButtonState.Default -> enabledOutline
WireButtonState.Disabled -> disabledOutline
WireButtonState.Selected -> selectedOutline
Expand All @@ -146,7 +173,7 @@ data class WireButtonColors(

@Composable
fun contentColor(state: WireButtonState, interactionSource: InteractionSource): State<Color> = animateColorAsState(
when(state) {
when (state) {
WireButtonState.Default -> onEnabled
WireButtonState.Disabled -> onDisabled
WireButtonState.Selected -> onSelected
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ fun MessageStatusIndicator(

is MessageFlowStatus.Failure -> Icon(
modifier = modifier,
painter = painterResource(id = R.drawable.ic_message_error),
painter = painterResource(id = R.drawable.ic_warning_circle),
tint = MaterialTheme.wireColorScheme.error,
contentDescription = stringResource(R.string.content_description_message_error_status),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class GroupConversationDetailsViewModel @Inject constructor(
private val observeSelfDeletionTimerSettingsForConversation: ObserveSelfDeletionTimerSettingsForConversationUseCase,
override val savedStateHandle: SavedStateHandle,
private val isMLSEnabled: IsMLSEnabledUseCase,
private val refreshUsersWithoutMetadata: RefreshUsersWithoutMetadataUseCase,
refreshUsersWithoutMetadata: RefreshUsersWithoutMetadataUseCase,
) : GroupConversationParticipantsViewModel(
savedStateHandle, observeConversationMembers, refreshUsersWithoutMetadata
), GroupConversationDetailsBottomSheetEventsHandler {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

package com.wire.android.ui.home.conversations.details.editguestaccess

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
Expand All @@ -30,27 +29,25 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.wire.android.R
import com.wire.android.ui.common.button.WireButtonState
import com.wire.android.ui.common.button.WirePrimaryButton
import com.wire.android.ui.common.button.wirePrimaryButtonColors
import com.wire.android.ui.common.colorsScheme
import com.wire.android.ui.common.button.WireSecondaryButton
import com.wire.android.ui.common.button.wireSecondaryButtonColors
import com.wire.android.ui.theme.wireDimensions

@Composable
fun CreateLinkButton(
shouldDisableGenerateGuestLinkButton: Boolean,
fun CreateGuestLinkButton(
enabled: Boolean,
isLoading: Boolean,
onCreateLink: () -> Unit
) {
WirePrimaryButton(
WireSecondaryButton(
text = stringResource(id = R.string.guest_link_button_create_link),
fillMaxWidth = true,
onClick = onCreateLink,
loading = isLoading,
state = if (shouldDisableGenerateGuestLinkButton) WireButtonState.Disabled
state = if (!enabled) WireButtonState.Disabled
else WireButtonState.Default,
modifier = Modifier
.fillMaxWidth()
.background(MaterialTheme.colorScheme.background)
.padding(MaterialTheme.wireDimensions.spacing16x)

)
Expand All @@ -60,10 +57,9 @@ fun CreateLinkButton(
fun CopyLinkButton(
onCopy: () -> Unit
) {
WirePrimaryButton(
WireSecondaryButton(
modifier = Modifier
.fillMaxWidth()
.background(MaterialTheme.colorScheme.background)
.padding(
start = MaterialTheme.wireDimensions.spacing16x,
end = MaterialTheme.wireDimensions.spacing16x,
Expand All @@ -77,10 +73,9 @@ fun CopyLinkButton(
fun ShareLinkButton(
onShare: () -> Unit
) {
WirePrimaryButton(
WireSecondaryButton(
modifier = Modifier
.fillMaxWidth()
.background(MaterialTheme.colorScheme.background)
.padding(
start = MaterialTheme.wireDimensions.spacing16x,
end = MaterialTheme.wireDimensions.spacing16x,
Expand All @@ -96,21 +91,20 @@ fun RevokeLinkButton(
isLoading: Boolean = false,
onRevoke: () -> Unit
) {
WirePrimaryButton(
WireSecondaryButton(
modifier = Modifier
.fillMaxWidth()
.background(MaterialTheme.colorScheme.background)
.padding(
start = MaterialTheme.wireDimensions.spacing16x,
end = MaterialTheme.wireDimensions.spacing16x,
top = MaterialTheme.wireDimensions.spacing4x,
bottom = MaterialTheme.wireDimensions.spacing12x
),
colors = wirePrimaryButtonColors().copy(enabled = colorsScheme().error),
colors = wireSecondaryButtonColors(),
text = stringResource(id = R.string.guest_link_button_revoke_link),
fillMaxWidth = true,
loading = isLoading,
state = if (isLoading) WireButtonState.Disabled else WireButtonState.Default,
state = if (isLoading) WireButtonState.Disabled else WireButtonState.Error,
onClick = onRevoke
)
}
Expand All @@ -136,5 +130,5 @@ fun PreviewShareLinkButton() {
@Preview
@Composable
fun PreviewCreateLinkButton() {
CreateLinkButton(true, false) {}
CreateGuestLinkButton(true, false) {}
}

0 comments on commit 65fc8c7

Please sign in to comment.