Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into displaying_connect…
Browse files Browse the repository at this point in the history
…ing_label_in_call

# Conflicts:
#	app/src/main/res/values/strings.xml
  • Loading branch information
ohassine committed Aug 23, 2023
2 parents 6e2d94f + e8638e5 commit 69694f5
Show file tree
Hide file tree
Showing 34 changed files with 1,682 additions and 162 deletions.
103 changes: 103 additions & 0 deletions app/src/androidTest/java/com/wire/android/LinkSpannableStringTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* 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

import android.text.style.URLSpan
import android.text.util.Linkify
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.wire.android.ui.common.LinkSpannableString
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class LinkSpannableStringTest {

lateinit var linkSpannableString: LinkSpannableString

@Before
fun setUp() {
linkSpannableString = LinkSpannableString("Hello, world!")
}

@Test
fun givenValidIndices_whenSetSpanIsCalled_thenSpanIsSet() {
// Given
val start = 0
val end = 5

// When
linkSpannableString.setSpan(URLSpan("http://example.com"), start, end, 0)

// Then
assert(linkSpannableString.getSpans(start, end, URLSpan::class.java).isNotEmpty())
}

@Test
fun givenInvalidStartIndex_whenSetSpanIsCalled_thenSpanIsNotSet() {
// Given
val start = -1
val end = 5

// When
linkSpannableString.setSpan(URLSpan("http://example.com"), start, end, 0)

// Then
assert(linkSpannableString.getSpans(start, end, URLSpan::class.java).isEmpty())
}

@Test
fun givenInvalidEndIndex_whenSetSpanIsCalled_thenSpanIsNotSet() {
// Given
val start = 0
val end = 20

// When
linkSpannableString.setSpan(URLSpan("http://example.com"), start, end, 0)

// Then
assert(linkSpannableString.getSpans(start, end, URLSpan::class.java).isEmpty())
}

@Test
fun givenASetSpan_whenRemoveSpanIsCalled_thenSpanIsRemoved() {
// Given
val urlSpan = URLSpan("http://example.com")
linkSpannableString.setSpan(urlSpan, 0, 5, 0)

// When
linkSpannableString.removeSpan(urlSpan)

// Then
assert(linkSpannableString.getSpans(0, 5, URLSpan::class.java).isEmpty())
}

@Test
fun givenATextWithLink_whenGetLinkInfosIsCalled_thenLinkInfoIsReturned() {
// Given
val text = "Visit http://example.com for more info."
val mask = Linkify.WEB_URLS

// When
val linkInfos = LinkSpannableString.getLinkInfos(text, mask)

// Then
assert(linkInfos.size == 1)
assert(linkInfos[0].url == "http://example.com")
}
}
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 @@ -41,6 +41,7 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextOverflow
import com.wire.android.appLogger

@Composable
fun ClickableText(
Expand Down Expand Up @@ -137,7 +138,11 @@ class LinkSpannableString(source: CharSequence) : SpannableString(source) {
}

override fun setSpan(what: Any?, start: Int, end: Int, flags: Int) {
super.setSpan(what, start, end, flags)
spanList.add(Data(what, start, end))
if (start >= 0 && end <= this.length && start <= end) {
super.setSpan(what, start, end, flags)
spanList.add(Data(what, start, end))
} else {
appLogger.e("[LinkSpannableString] Invalid span indices: start=$start, end=$end, length=$length")
}
}
}
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
Loading

0 comments on commit 69694f5

Please sign in to comment.