mirror of
https://github.com/bitwarden/android.git
synced 2024-11-21 17:05:44 +03:00
Update the compose BOM to 2024.09.00 (#3874)
This commit is contained in:
parent
e468ec695b
commit
3f78ad6d6d
51 changed files with 355 additions and 373 deletions
|
@ -20,13 +20,13 @@ import androidx.compose.foundation.layout.width
|
|||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
|
@ -308,7 +308,7 @@ private fun TermsAndPrivacySwitch(
|
|||
}
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
|
||||
indication = ripple(color = MaterialTheme.colorScheme.primary),
|
||||
onClick = { onCheckedChange.invoke(!isChecked) },
|
||||
)
|
||||
.padding(start = 16.dp)
|
||||
|
|
|
@ -20,7 +20,6 @@ import androidx.compose.foundation.layout.width
|
|||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.text.ClickableText
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
|
@ -28,6 +27,7 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
|
@ -448,7 +448,7 @@ private fun ReceiveMarketingEmailsSwitch(
|
|||
}
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
|
||||
indication = ripple(color = MaterialTheme.colorScheme.primary),
|
||||
onClick = { onCheckedChange.invoke(!isChecked) },
|
||||
)
|
||||
.fillMaxWidth(),
|
||||
|
|
|
@ -298,7 +298,6 @@ private fun TwoFactorLoginScreenContent(
|
|||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@Preview(showBackground = true)
|
||||
private fun TwoFactorLoginScreenContentPreview() {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package com.x8bit.bitwarden.ui.auth.feature.welcome
|
||||
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
|
@ -23,7 +22,6 @@ import androidx.compose.foundation.pager.rememberPagerState
|
|||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
|
@ -57,7 +55,6 @@ private val LANDSCAPE_HORIZONTAL_MARGIN: Dp = 128.dp
|
|||
/**
|
||||
* Top level composable for the welcome screen.
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun WelcomeScreen(
|
||||
onNavigateToCreateAccount: () -> Unit,
|
||||
|
@ -103,7 +100,6 @@ fun WelcomeScreen(
|
|||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun WelcomeScreenContent(
|
||||
state: WelcomeState,
|
||||
|
|
|
@ -2,8 +2,8 @@ package com.x8bit.bitwarden.ui.platform.base.util
|
|||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
|
|
|
@ -7,6 +7,7 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.CombinedModifier
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.draw.drawWithCache
|
||||
|
@ -42,14 +43,17 @@ fun Modifier.scrolledContainerBackground(
|
|||
): Modifier {
|
||||
val expandedColor = MaterialTheme.colorScheme.surface
|
||||
val collapsedColor = MaterialTheme.colorScheme.surfaceContainer
|
||||
return this then drawBehind {
|
||||
drawRect(
|
||||
color = topAppBarScrollBehavior.toScrolledContainerColor(
|
||||
expandedColor = expandedColor,
|
||||
collapsedColor = collapsedColor,
|
||||
),
|
||||
)
|
||||
}
|
||||
return CombinedModifier(
|
||||
outer = this,
|
||||
inner = drawBehind {
|
||||
drawRect(
|
||||
color = topAppBarScrollBehavior.toScrolledContainerColor(
|
||||
expandedColor = expandedColor,
|
||||
collapsedColor = collapsedColor,
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,7 +21,6 @@ import androidx.compose.foundation.layout.size
|
|||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
|
@ -30,6 +29,7 @@ import androidx.compose.material3.Text
|
|||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
|
@ -276,7 +276,7 @@ private fun AccountSummaryItem(
|
|||
.testTag("AccountCell")
|
||||
.combinedClickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
|
||||
indication = ripple(color = MaterialTheme.colorScheme.primary),
|
||||
onClick = { onSwitchAccountClick(accountSummary) },
|
||||
onLongClick = { onSwitchAccountLongClick(accountSummary) },
|
||||
)
|
||||
|
@ -398,7 +398,7 @@ private fun AddAccountItem(
|
|||
modifier = Modifier
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
|
||||
indication = ripple(color = MaterialTheme.colorScheme.primary),
|
||||
onClick = onClick,
|
||||
)
|
||||
.padding(vertical = 8.dp)
|
||||
|
|
|
@ -4,9 +4,9 @@ import androidx.compose.foundation.clickable
|
|||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
|
@ -33,7 +33,7 @@ fun BitwardenBasicDialogRow(
|
|||
modifier = modifier
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
|
||||
indication = ripple(color = MaterialTheme.colorScheme.primary),
|
||||
onClick = onClick,
|
||||
)
|
||||
.padding(
|
||||
|
|
|
@ -6,10 +6,10 @@ import androidx.compose.foundation.layout.Box
|
|||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
|
@ -57,7 +57,7 @@ fun EnvironmentSelector(
|
|||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(28.dp))
|
||||
.clickable(
|
||||
indication = rememberRipple(
|
||||
indication = ripple(
|
||||
bounded = true,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
),
|
||||
|
|
|
@ -6,10 +6,10 @@ import androidx.compose.foundation.layout.Arrangement
|
|||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
|
@ -51,7 +51,7 @@ fun BitwardenGroupItem(
|
|||
modifier = Modifier
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
|
||||
indication = ripple(color = MaterialTheme.colorScheme.primary),
|
||||
onClick = onClick,
|
||||
)
|
||||
.bottomDivider(
|
||||
|
|
|
@ -10,11 +10,11 @@ import androidx.compose.foundation.layout.defaultMinSize
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
|
@ -83,7 +83,7 @@ fun BitwardenListItem(
|
|||
modifier = Modifier
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
|
||||
indication = ripple(color = MaterialTheme.colorScheme.primary),
|
||||
onClick = onClick,
|
||||
)
|
||||
.defaultMinSize(minHeight = 72.dp)
|
||||
|
|
|
@ -9,10 +9,10 @@ import androidx.compose.foundation.layout.Row
|
|||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
|
@ -50,7 +50,7 @@ fun BitwardenTextRow(
|
|||
.clickable(
|
||||
enabled = isEnabled,
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
|
||||
indication = ripple(color = MaterialTheme.colorScheme.primary),
|
||||
onClick = onClick,
|
||||
)
|
||||
.semantics(mergeDescendants = true) { },
|
||||
|
|
|
@ -13,14 +13,15 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.ScaffoldDefaults
|
||||
import androidx.compose.material3.contentColorFor
|
||||
import androidx.compose.material3.pulltorefresh.PullToRefreshContainer
|
||||
import androidx.compose.material3.pulltorefresh.PullToRefreshState
|
||||
import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults
|
||||
import androidx.compose.material3.pulltorefresh.pullToRefresh
|
||||
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.semantics.testTagsAsResourceId
|
||||
|
||||
|
@ -37,7 +38,7 @@ fun BitwardenScaffold(
|
|||
snackbarHost: @Composable () -> Unit = { },
|
||||
floatingActionButton: @Composable () -> Unit = { },
|
||||
floatingActionButtonPosition: FabPosition = FabPosition.End,
|
||||
pullToRefreshState: PullToRefreshState? = null,
|
||||
pullToRefreshState: BitwardenPullToRefreshState = rememberBitwardenPullToRefreshState(),
|
||||
containerColor: Color = MaterialTheme.colorScheme.surface,
|
||||
contentColor: Color = contentColorFor(containerColor),
|
||||
contentWindowInsets: WindowInsets = ScaffoldDefaults
|
||||
|
@ -48,7 +49,6 @@ fun BitwardenScaffold(
|
|||
Scaffold(
|
||||
modifier = Modifier
|
||||
.semantics { testTagsAsResourceId = true }
|
||||
.run { pullToRefreshState?.let { nestedScroll(it.nestedScrollConnection) } ?: this }
|
||||
.then(modifier),
|
||||
topBar = topBar,
|
||||
bottomBar = bottomBar,
|
||||
|
@ -63,18 +63,50 @@ fun BitwardenScaffold(
|
|||
contentColor = contentColor,
|
||||
contentWindowInsets = contentWindowInsets,
|
||||
content = { paddingValues ->
|
||||
Box {
|
||||
val internalPullToRefreshState = rememberPullToRefreshState()
|
||||
Box(
|
||||
modifier = Modifier.pullToRefresh(
|
||||
state = internalPullToRefreshState,
|
||||
isRefreshing = pullToRefreshState.isRefreshing,
|
||||
onRefresh = pullToRefreshState.onRefresh,
|
||||
enabled = pullToRefreshState.isEnabled,
|
||||
),
|
||||
) {
|
||||
content(paddingValues)
|
||||
|
||||
pullToRefreshState?.let {
|
||||
PullToRefreshContainer(
|
||||
state = it,
|
||||
modifier = Modifier
|
||||
.padding(paddingValues)
|
||||
.align(Alignment.TopCenter),
|
||||
)
|
||||
}
|
||||
PullToRefreshDefaults.Indicator(
|
||||
modifier = Modifier
|
||||
.padding(paddingValues)
|
||||
.align(Alignment.TopCenter),
|
||||
isRefreshing = pullToRefreshState.isRefreshing,
|
||||
state = internalPullToRefreshState,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* The state of the pull-to-refresh.
|
||||
*/
|
||||
data class BitwardenPullToRefreshState(
|
||||
val isEnabled: Boolean,
|
||||
val isRefreshing: Boolean,
|
||||
val onRefresh: () -> Unit,
|
||||
)
|
||||
|
||||
/**
|
||||
* Create and remember the default [BitwardenPullToRefreshState].
|
||||
*/
|
||||
@Composable
|
||||
fun rememberBitwardenPullToRefreshState(
|
||||
isEnabled: Boolean = false,
|
||||
isRefreshing: Boolean = false,
|
||||
onRefresh: () -> Unit = { },
|
||||
): BitwardenPullToRefreshState = remember(isEnabled, isRefreshing, onRefresh) {
|
||||
BitwardenPullToRefreshState(
|
||||
isEnabled = isEnabled,
|
||||
isRefreshing = isRefreshing,
|
||||
onRefresh = onRefresh,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.x8bit.bitwarden.ui.platform.components.segment
|
||||
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MultiChoiceSegmentedButtonRow
|
||||
import androidx.compose.material3.SegmentedButton
|
||||
import androidx.compose.material3.SegmentedButtonDefaults
|
||||
|
@ -16,7 +15,6 @@ import kotlinx.collections.immutable.ImmutableList
|
|||
* @param options List of options to display.
|
||||
* @param modifier Modifier.
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun BitwardenSegmentedButton(
|
||||
modifier: Modifier = Modifier,
|
||||
|
|
|
@ -5,9 +5,9 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
|
|||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
|
@ -41,7 +41,7 @@ fun BitwardenClickableText(
|
|||
modifier = modifier
|
||||
.clip(RoundedCornerShape(cornerSize))
|
||||
.clickable(
|
||||
indication = rememberRipple(
|
||||
indication = ripple(
|
||||
bounded = true,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
),
|
||||
|
|
|
@ -10,10 +10,10 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
|
@ -49,7 +49,7 @@ fun BitwardenSwitch(
|
|||
if (onCheckedChange != null) {
|
||||
this.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
|
||||
indication = ripple(color = MaterialTheme.colorScheme.primary),
|
||||
onClick = { onCheckedChange.invoke(!isChecked) },
|
||||
)
|
||||
} else {
|
||||
|
|
|
@ -5,11 +5,11 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
|
|||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
|
@ -49,7 +49,7 @@ fun BitwardenSwitchWithActions(
|
|||
modifier = Modifier
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
|
||||
indication = ripple(color = MaterialTheme.colorScheme.primary),
|
||||
onClick = { onCheckedChange?.invoke(!isChecked) },
|
||||
)
|
||||
.semantics(mergeDescendants = true) {
|
||||
|
|
|
@ -10,10 +10,10 @@ import androidx.compose.foundation.layout.height
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
|
@ -57,7 +57,7 @@ fun BitwardenWideSwitch(
|
|||
.wrapContentHeight()
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
|
||||
indication = ripple(color = MaterialTheme.colorScheme.primary),
|
||||
onClick = { onCheckedChange?.invoke(!isChecked) },
|
||||
enabled = !readOnly && enabled,
|
||||
)
|
||||
|
|
|
@ -12,13 +12,13 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
|
@ -108,7 +108,7 @@ private fun SettingsRow(
|
|||
modifier = Modifier
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
|
||||
indication = ripple(color = MaterialTheme.colorScheme.primary),
|
||||
onClick = onClick,
|
||||
)
|
||||
.bottomDivider(paddingStart = 16.dp)
|
||||
|
|
|
@ -14,7 +14,6 @@ import androidx.compose.foundation.layout.height
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
|
@ -22,6 +21,7 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
|
@ -249,7 +249,7 @@ private fun CopyRow(
|
|||
modifier = modifier
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
|
||||
indication = ripple(color = MaterialTheme.colorScheme.primary),
|
||||
onClick = onClick,
|
||||
)
|
||||
.semantics(mergeDescendants = true) {
|
||||
|
|
|
@ -17,19 +17,16 @@ import androidx.compose.foundation.lazy.LazyColumn
|
|||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
@ -52,6 +49,7 @@ import com.x8bit.bitwarden.ui.platform.components.content.BitwardenErrorContent
|
|||
import com.x8bit.bitwarden.ui.platform.components.content.BitwardenLoadingContent
|
||||
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenTwoButtonDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||
import com.x8bit.bitwarden.ui.platform.components.scaffold.rememberBitwardenPullToRefreshState
|
||||
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||
import com.x8bit.bitwarden.ui.platform.theme.LocalNonMaterialColors
|
||||
import com.x8bit.bitwarden.ui.platform.theme.LocalNonMaterialTypography
|
||||
|
@ -70,17 +68,15 @@ fun PendingRequestsScreen(
|
|||
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
||||
val context = LocalContext.current
|
||||
val resources = context.resources
|
||||
val pullToRefreshState by rememberUpdatedState(
|
||||
newValue = rememberPullToRefreshState().takeIf { state.isPullToRefreshEnabled },
|
||||
val pullToRefreshState = rememberBitwardenPullToRefreshState(
|
||||
isEnabled = state.isPullToRefreshEnabled,
|
||||
isRefreshing = state.isRefreshing,
|
||||
onRefresh = remember(viewModel) {
|
||||
{ viewModel.trySendAction(PendingRequestsAction.RefreshPull) }
|
||||
},
|
||||
)
|
||||
LaunchedEffect(key1 = pullToRefreshState?.isRefreshing) {
|
||||
if (pullToRefreshState?.isRefreshing == true) {
|
||||
viewModel.trySendAction(PendingRequestsAction.RefreshPull)
|
||||
}
|
||||
}
|
||||
EventsEffect(viewModel = viewModel) { event ->
|
||||
when (event) {
|
||||
PendingRequestsEvent.DismissPullToRefresh -> pullToRefreshState?.endRefresh()
|
||||
PendingRequestsEvent.NavigateBack -> onNavigateBack()
|
||||
is PendingRequestsEvent.NavigateToLoginApproval -> {
|
||||
onNavigateToLoginApproval(event.fingerprint)
|
||||
|
@ -244,7 +240,7 @@ private fun PendingRequestItem(
|
|||
modifier = modifier
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
|
||||
indication = ripple(color = MaterialTheme.colorScheme.primary),
|
||||
onClick = { onNavigateToLoginApproval(fingerprintPhrase) },
|
||||
),
|
||||
horizontalAlignment = Alignment.Start,
|
||||
|
|
|
@ -38,6 +38,7 @@ class PendingRequestsViewModel @Inject constructor(
|
|||
authRequests = emptyList(),
|
||||
viewState = PendingRequestsState.ViewState.Loading,
|
||||
isPullToRefreshSettingEnabled = settingsRepository.getPullToRefreshEnabledFlow().value,
|
||||
isRefreshing = false,
|
||||
),
|
||||
) {
|
||||
private var authJob: Job = Job().apply { complete() }
|
||||
|
@ -93,6 +94,7 @@ class PendingRequestsViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun handleRefreshPull() {
|
||||
mutableStateFlow.update { it.copy(isRefreshing = true) }
|
||||
updateAuthRequestList()
|
||||
}
|
||||
|
||||
|
@ -169,7 +171,7 @@ class PendingRequestsViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
sendEvent(PendingRequestsEvent.DismissPullToRefresh)
|
||||
mutableStateFlow.update { it.copy(isRefreshing = false) }
|
||||
}
|
||||
|
||||
private fun updateAuthRequestList() {
|
||||
|
@ -190,6 +192,7 @@ data class PendingRequestsState(
|
|||
val authRequests: List<AuthRequest>,
|
||||
val viewState: ViewState,
|
||||
private val isPullToRefreshSettingEnabled: Boolean,
|
||||
val isRefreshing: Boolean,
|
||||
) : Parcelable {
|
||||
/**
|
||||
* Indicates that the pull-to-refresh should be enabled in the UI.
|
||||
|
@ -259,11 +262,6 @@ data class PendingRequestsState(
|
|||
* Models events for the delete account screen.
|
||||
*/
|
||||
sealed class PendingRequestsEvent {
|
||||
/**
|
||||
* Dismisses the pull-to-refresh indicator.
|
||||
*/
|
||||
data object DismissPullToRefresh : PendingRequestsEvent()
|
||||
|
||||
/**
|
||||
* Navigates back.
|
||||
*/
|
||||
|
|
|
@ -18,7 +18,6 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
|
@ -28,6 +27,7 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
|
@ -280,7 +280,7 @@ private fun BlockAutoFillListItem(
|
|||
modifier = Modifier
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
|
||||
indication = ripple(color = MaterialTheme.colorScheme.primary),
|
||||
onClick = onClick,
|
||||
)
|
||||
.bottomDivider(paddingStart = 16.dp)
|
||||
|
|
|
@ -12,7 +12,6 @@ import androidx.compose.foundation.layout.navigationBarsPadding
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
|
@ -20,6 +19,7 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
|
@ -168,7 +168,7 @@ private fun FoldersContent(
|
|||
.testTag("FolderCell")
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
|
||||
indication = ripple(color = MaterialTheme.colorScheme.primary),
|
||||
onClick = { onItemClick(it.id) },
|
||||
)
|
||||
.bottomDivider(paddingStart = 16.dp)
|
||||
|
|
|
@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.navigationBars
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.statusBars
|
||||
import androidx.compose.material3.BottomAppBar
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.NavigationBarItem
|
||||
|
@ -142,7 +141,6 @@ fun VaultUnlockedNavBarScreen(
|
|||
* Scaffold that contains the bottom nav bar for the [VaultUnlockedNavBarScreen]
|
||||
*/
|
||||
@Composable
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Suppress("LongMethod")
|
||||
private fun VaultUnlockedNavBarScaffold(
|
||||
state: VaultUnlockedNavBarState,
|
||||
|
|
|
@ -12,10 +12,8 @@ import androidx.compose.material3.FloatingActionButton
|
|||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
|
@ -39,6 +37,7 @@ import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenBasicDialog
|
|||
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenLoadingDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.dialog.LoadingDialogState
|
||||
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||
import com.x8bit.bitwarden.ui.platform.components.scaffold.rememberBitwardenPullToRefreshState
|
||||
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||
import com.x8bit.bitwarden.ui.platform.composition.LocalIntentManager
|
||||
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||
|
@ -63,18 +62,16 @@ fun SendScreen(
|
|||
) {
|
||||
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
||||
val context = LocalContext.current
|
||||
val pullToRefreshState = rememberPullToRefreshState()
|
||||
.takeIf { state.isPullToRefreshEnabled }
|
||||
LaunchedEffect(key1 = pullToRefreshState?.isRefreshing) {
|
||||
if (pullToRefreshState?.isRefreshing == true) {
|
||||
viewModel.trySendAction(SendAction.RefreshPull)
|
||||
}
|
||||
}
|
||||
val pullToRefreshState = rememberBitwardenPullToRefreshState(
|
||||
isEnabled = state.isPullToRefreshEnabled,
|
||||
isRefreshing = state.isRefreshing,
|
||||
onRefresh = remember(viewModel) {
|
||||
{ viewModel.trySendAction(SendAction.RefreshPull) }
|
||||
},
|
||||
)
|
||||
|
||||
EventsEffect(viewModel = viewModel) { event ->
|
||||
when (event) {
|
||||
is SendEvent.DismissPullToRefresh -> pullToRefreshState?.endRefresh()
|
||||
|
||||
is SendEvent.NavigateToSearch -> onNavigateToSearchSend(SearchType.Sends.All)
|
||||
|
||||
is SendEvent.NavigateNewSend -> onNavigateToAddSend()
|
||||
|
|
|
@ -56,6 +56,7 @@ class SendViewModel @Inject constructor(
|
|||
policyDisablesSend = policyManager
|
||||
.getActivePolicies(type = PolicyTypeJson.DISABLE_SEND)
|
||||
.any(),
|
||||
isRefreshing = false,
|
||||
),
|
||||
) {
|
||||
|
||||
|
@ -174,9 +175,9 @@ class SendViewModel @Inject constructor(
|
|||
message = R.string.generic_error_message.asText(),
|
||||
),
|
||||
dialogState = null,
|
||||
isRefreshing = false,
|
||||
)
|
||||
}
|
||||
sendEvent(SendEvent.DismissPullToRefresh)
|
||||
}
|
||||
|
||||
is DataState.Loaded -> {
|
||||
|
@ -189,9 +190,9 @@ class SendViewModel @Inject constructor(
|
|||
.baseWebSendUrl,
|
||||
),
|
||||
dialogState = null,
|
||||
isRefreshing = false,
|
||||
)
|
||||
}
|
||||
sendEvent(SendEvent.DismissPullToRefresh)
|
||||
}
|
||||
|
||||
DataState.Loading -> {
|
||||
|
@ -212,9 +213,9 @@ class SendViewModel @Inject constructor(
|
|||
),
|
||||
),
|
||||
dialogState = null,
|
||||
isRefreshing = false,
|
||||
)
|
||||
}
|
||||
sendEvent(SendEvent.DismissPullToRefresh)
|
||||
}
|
||||
|
||||
is DataState.Pending -> {
|
||||
|
@ -317,6 +318,7 @@ class SendViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun handleRefreshPull() {
|
||||
mutableStateFlow.update { it.copy(isRefreshing = true) }
|
||||
// The Pull-To-Refresh composable is already in the refreshing state.
|
||||
// We will reset that state when sendDataStateFlow emits later on.
|
||||
vaultRepo.sync()
|
||||
|
@ -332,6 +334,7 @@ data class SendState(
|
|||
val dialogState: DialogState?,
|
||||
private val isPullToRefreshSettingEnabled: Boolean,
|
||||
val policyDisablesSend: Boolean,
|
||||
val isRefreshing: Boolean,
|
||||
) : Parcelable {
|
||||
|
||||
/**
|
||||
|
@ -573,11 +576,6 @@ sealed class SendAction {
|
|||
* Models events for the send screen.
|
||||
*/
|
||||
sealed class SendEvent {
|
||||
/**
|
||||
* Dismisses the pull-to-refresh indicator.
|
||||
*/
|
||||
data object DismissPullToRefresh : SendEvent()
|
||||
|
||||
/**
|
||||
* Navigate to the new send screen.
|
||||
*/
|
||||
|
|
|
@ -8,11 +8,8 @@ import androidx.compose.material3.FloatingActionButton
|
|||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.pulltorefresh.PullToRefreshState
|
||||
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
|
@ -45,7 +42,9 @@ import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenMasterPassword
|
|||
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenOverwritePasskeyConfirmationDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenPinDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.dialog.LoadingDialogState
|
||||
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenPullToRefreshState
|
||||
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||
import com.x8bit.bitwarden.ui.platform.components.scaffold.rememberBitwardenPullToRefreshState
|
||||
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||
import com.x8bit.bitwarden.ui.platform.composition.LocalBiometricsManager
|
||||
import com.x8bit.bitwarden.ui.platform.composition.LocalFido2CompletionManager
|
||||
|
@ -65,7 +64,6 @@ import kotlinx.collections.immutable.toImmutableList
|
|||
/**
|
||||
* Displays the vault item listing screen.
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||
fun VaultItemListingScreen(
|
||||
|
@ -89,18 +87,17 @@ fun VaultItemListingScreen(
|
|||
VaultItemListingUserVerificationHandlers.create(viewModel = viewModel)
|
||||
}
|
||||
|
||||
val pullToRefreshState = rememberPullToRefreshState().takeIf { state.isPullToRefreshEnabled }
|
||||
LaunchedEffect(key1 = pullToRefreshState?.isRefreshing) {
|
||||
if (pullToRefreshState?.isRefreshing == true) {
|
||||
viewModel.trySendAction(VaultItemListingsAction.RefreshPull)
|
||||
}
|
||||
}
|
||||
val pullToRefreshState = rememberBitwardenPullToRefreshState(
|
||||
isEnabled = state.isPullToRefreshEnabled,
|
||||
isRefreshing = state.isRefreshing,
|
||||
onRefresh = remember(viewModel) {
|
||||
{ viewModel.trySendAction(VaultItemListingsAction.RefreshPull) }
|
||||
},
|
||||
)
|
||||
EventsEffect(viewModel = viewModel) { event ->
|
||||
when (event) {
|
||||
is VaultItemListingEvent.NavigateBack -> onNavigateBack()
|
||||
|
||||
is VaultItemListingEvent.DismissPullToRefresh -> pullToRefreshState?.endRefresh()
|
||||
|
||||
is VaultItemListingEvent.NavigateToVaultItem -> {
|
||||
onNavigateToVaultItem(event.id)
|
||||
}
|
||||
|
@ -388,7 +385,7 @@ private fun VaultItemListingDialogs(
|
|||
@Composable
|
||||
private fun VaultItemListingScaffold(
|
||||
state: VaultItemListingState,
|
||||
pullToRefreshState: PullToRefreshState?,
|
||||
pullToRefreshState: BitwardenPullToRefreshState,
|
||||
vaultItemListingHandlers: VaultItemListingHandlers,
|
||||
) {
|
||||
var isAccountMenuVisible by rememberSaveable { mutableStateOf(false) }
|
||||
|
|
|
@ -133,6 +133,7 @@ class VaultItemListingViewModel @Inject constructor(
|
|||
fido2CredentialAssertionRequest = fido2AssertionData?.fido2AssertionRequest,
|
||||
fido2GetCredentialsRequest = fido2GetCredentialsData?.fido2GetCredentialsRequest,
|
||||
isPremium = userState.activeAccount.isPremium,
|
||||
isRefreshing = false,
|
||||
)
|
||||
},
|
||||
) {
|
||||
|
@ -298,6 +299,7 @@ class VaultItemListingViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun handleRefreshPull() {
|
||||
mutableStateFlow.update { it.copy(isRefreshing = true) }
|
||||
// The Pull-To-Refresh composable is already in the refreshing state.
|
||||
// We will reset that state when sendDataStateFlow emits later on.
|
||||
vaultRepository.sync()
|
||||
|
@ -1232,7 +1234,7 @@ class VaultItemListingViewModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
}
|
||||
sendEvent(VaultItemListingEvent.DismissPullToRefresh)
|
||||
mutableStateFlow.update { it.copy(isRefreshing = false) }
|
||||
}
|
||||
|
||||
private fun vaultLoadedReceive(vaultData: DataState.Loaded<VaultData>) {
|
||||
|
@ -1261,7 +1263,7 @@ class VaultItemListingViewModel @Inject constructor(
|
|||
),
|
||||
)
|
||||
}
|
||||
?: sendEvent(VaultItemListingEvent.DismissPullToRefresh)
|
||||
?: mutableStateFlow.update { it.copy(isRefreshing = false) }
|
||||
}
|
||||
|
||||
private fun vaultLoadingReceive() {
|
||||
|
@ -1286,7 +1288,7 @@ class VaultItemListingViewModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
}
|
||||
sendEvent(VaultItemListingEvent.DismissPullToRefresh)
|
||||
mutableStateFlow.update { it.copy(isRefreshing = false) }
|
||||
}
|
||||
|
||||
private fun vaultPendingReceive(vaultData: DataState.Pending<VaultData>) {
|
||||
|
@ -1640,6 +1642,7 @@ data class VaultItemListingState(
|
|||
val fido2GetCredentialsRequest: Fido2GetCredentialsRequest? = null,
|
||||
val hasMasterPassword: Boolean,
|
||||
val isPremium: Boolean,
|
||||
val isRefreshing: Boolean,
|
||||
) {
|
||||
/**
|
||||
* Whether or not this represents a listing screen for autofill.
|
||||
|
@ -2027,11 +2030,6 @@ data class VaultItemListingState(
|
|||
* Models events for the [VaultItemListingScreen].
|
||||
*/
|
||||
sealed class VaultItemListingEvent {
|
||||
/**
|
||||
* Dismisses the pull-to-refresh indicator.
|
||||
*/
|
||||
data object DismissPullToRefresh : VaultItemListingEvent()
|
||||
|
||||
/**
|
||||
* Navigates to the Create Account screen.
|
||||
*/
|
||||
|
|
|
@ -16,8 +16,6 @@ import androidx.compose.material3.FloatingActionButton
|
|||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.pulltorefresh.PullToRefreshState
|
||||
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
|
@ -52,7 +50,9 @@ import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenLoadingDialog
|
|||
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenMasterPasswordDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenTwoButtonDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.dialog.LoadingDialogState
|
||||
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenPullToRefreshState
|
||||
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||
import com.x8bit.bitwarden.ui.platform.components.scaffold.rememberBitwardenPullToRefreshState
|
||||
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||
import com.x8bit.bitwarden.ui.platform.composition.LocalExitManager
|
||||
import com.x8bit.bitwarden.ui.platform.composition.LocalIntentManager
|
||||
|
@ -70,7 +70,6 @@ import kotlinx.collections.immutable.toImmutableList
|
|||
/**
|
||||
* The vault screen for the application.
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
fun VaultScreen(
|
||||
|
@ -88,16 +87,15 @@ fun VaultScreen(
|
|||
) {
|
||||
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
||||
val context = LocalContext.current
|
||||
val pullToRefreshState = rememberPullToRefreshState().takeIf { state.isPullToRefreshEnabled }
|
||||
LaunchedEffect(key1 = pullToRefreshState?.isRefreshing) {
|
||||
if (pullToRefreshState?.isRefreshing == true) {
|
||||
viewModel.trySendAction(VaultAction.RefreshPull)
|
||||
}
|
||||
}
|
||||
val pullToRefreshState = rememberBitwardenPullToRefreshState(
|
||||
isEnabled = state.isPullToRefreshEnabled,
|
||||
isRefreshing = state.isRefreshing,
|
||||
onRefresh = remember(viewModel) {
|
||||
{ viewModel.trySendAction(VaultAction.RefreshPull) }
|
||||
},
|
||||
)
|
||||
EventsEffect(viewModel = viewModel) { event ->
|
||||
when (event) {
|
||||
VaultEvent.DismissPullToRefresh -> pullToRefreshState?.endRefresh()
|
||||
|
||||
VaultEvent.NavigateToAddItemScreen -> onNavigateToVaultAddItemScreen()
|
||||
|
||||
VaultEvent.NavigateToVaultSearchScreen -> onNavigateToSearchVault(SearchType.Vault.All)
|
||||
|
@ -167,7 +165,7 @@ private fun VaultScreenPushNotifications(
|
|||
@Composable
|
||||
private fun VaultScreenScaffold(
|
||||
state: VaultState,
|
||||
pullToRefreshState: PullToRefreshState?,
|
||||
pullToRefreshState: BitwardenPullToRefreshState,
|
||||
vaultHandlers: VaultHandlers,
|
||||
onDimBottomNavBarRequest: (shouldDim: Boolean) -> Unit,
|
||||
) {
|
||||
|
|
|
@ -91,6 +91,7 @@ class VaultViewModel @Inject constructor(
|
|||
baseIconUrl = userState.activeAccount.environment.environmentUrlData.baseIconUrl,
|
||||
hasMasterPassword = userState.activeAccount.hasMasterPassword,
|
||||
hideNotificationsDialog = isBuildVersionBelow(Build.VERSION_CODES.TIRAMISU) || isFdroid,
|
||||
isRefreshing = false,
|
||||
)
|
||||
},
|
||||
) {
|
||||
|
@ -298,6 +299,7 @@ class VaultViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun handleRefreshPull() {
|
||||
mutableStateFlow.update { it.copy(isRefreshing = true) }
|
||||
// The Pull-To-Refresh composable is already in the refreshing state.
|
||||
// We will reset that state when sendDataStateFlow emits later on.
|
||||
vaultRepository.sync()
|
||||
|
@ -510,8 +512,8 @@ class VaultViewModel @Inject constructor(
|
|||
hasMasterPassword = state.hasMasterPassword,
|
||||
errorTitle = R.string.an_error_has_occurred.asText(),
|
||||
errorMessage = R.string.generic_error_message.asText(),
|
||||
isRefreshing = false,
|
||||
)
|
||||
sendEvent(VaultEvent.DismissPullToRefresh)
|
||||
}
|
||||
|
||||
private fun vaultLoadedReceive(vaultData: DataState.Loaded<VaultData>) {
|
||||
|
@ -532,9 +534,9 @@ class VaultViewModel @Inject constructor(
|
|||
vaultFilterType = vaultFilterTypeOrDefault,
|
||||
),
|
||||
dialog = null,
|
||||
isRefreshing = false,
|
||||
)
|
||||
}
|
||||
sendEvent(VaultEvent.DismissPullToRefresh)
|
||||
}
|
||||
|
||||
private fun vaultLoadingReceive() {
|
||||
|
@ -551,8 +553,8 @@ class VaultViewModel @Inject constructor(
|
|||
isIconLoadingDisabled = state.isIconLoadingDisabled,
|
||||
hasMasterPassword = state.hasMasterPassword,
|
||||
errorMessage = R.string.internet_connection_required_message.asText(),
|
||||
isRefreshing = false,
|
||||
)
|
||||
sendEvent(VaultEvent.DismissPullToRefresh)
|
||||
}
|
||||
|
||||
private fun vaultPendingReceive(vaultData: DataState.Pending<VaultData>) {
|
||||
|
@ -633,6 +635,7 @@ data class VaultState(
|
|||
val baseIconUrl: String,
|
||||
val isIconLoadingDisabled: Boolean,
|
||||
val hideNotificationsDialog: Boolean,
|
||||
val isRefreshing: Boolean,
|
||||
) : Parcelable {
|
||||
|
||||
/**
|
||||
|
@ -921,11 +924,6 @@ data class VaultState(
|
|||
* Models effects for the [VaultScreen].
|
||||
*/
|
||||
sealed class VaultEvent {
|
||||
/**
|
||||
* Dismisses the pull-to-refresh indicator.
|
||||
*/
|
||||
data object DismissPullToRefresh : VaultEvent()
|
||||
|
||||
/**
|
||||
* Navigate to the Vault Search screen.
|
||||
*/
|
||||
|
@ -1186,6 +1184,7 @@ private fun MutableStateFlow<VaultState>.updateToErrorStateOrDialog(
|
|||
hasMasterPassword: Boolean,
|
||||
errorTitle: Text,
|
||||
errorMessage: Text,
|
||||
isRefreshing: Boolean,
|
||||
) {
|
||||
this.update {
|
||||
if (vaultData != null) {
|
||||
|
@ -1201,6 +1200,7 @@ private fun MutableStateFlow<VaultState>.updateToErrorStateOrDialog(
|
|||
title = errorTitle,
|
||||
message = errorMessage,
|
||||
),
|
||||
isRefreshing = isRefreshing,
|
||||
)
|
||||
} else {
|
||||
it.copy(
|
||||
|
@ -1208,6 +1208,7 @@ private fun MutableStateFlow<VaultState>.updateToErrorStateOrDialog(
|
|||
message = errorMessage,
|
||||
),
|
||||
dialog = null,
|
||||
isRefreshing = isRefreshing,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,11 +8,11 @@ import androidx.compose.foundation.layout.Row
|
|||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
|
@ -60,7 +60,7 @@ fun VaultVerificationCodeItem(
|
|||
modifier = Modifier
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
|
||||
indication = ripple(color = MaterialTheme.colorScheme.primary),
|
||||
onClick = onItemClick,
|
||||
)
|
||||
.defaultMinSize(minHeight = 72.dp)
|
||||
|
|
|
@ -7,10 +7,8 @@ import androidx.compose.foundation.lazy.LazyColumn
|
|||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
|
@ -31,6 +29,7 @@ import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenLoadingDialog
|
|||
import com.x8bit.bitwarden.ui.platform.components.dialog.LoadingDialogState
|
||||
import com.x8bit.bitwarden.ui.platform.components.header.BitwardenListHeaderTextWithSupportLabel
|
||||
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||
import com.x8bit.bitwarden.ui.platform.components.scaffold.rememberBitwardenPullToRefreshState
|
||||
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||
import com.x8bit.bitwarden.ui.vault.feature.verificationcode.handlers.VerificationCodeHandlers
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
@ -54,16 +53,16 @@ fun VerificationCodeScreen(
|
|||
VerificationCodeHandlers.create(viewModel)
|
||||
}
|
||||
|
||||
val pullToRefreshState = rememberPullToRefreshState().takeIf { state.isPullToRefreshEnabled }
|
||||
LaunchedEffect(key1 = pullToRefreshState?.isRefreshing) {
|
||||
if (pullToRefreshState?.isRefreshing == true) {
|
||||
viewModel.trySendAction(VerificationCodeAction.RefreshPull)
|
||||
}
|
||||
}
|
||||
val pullToRefreshState = rememberBitwardenPullToRefreshState(
|
||||
isEnabled = state.isPullToRefreshEnabled,
|
||||
isRefreshing = state.isRefreshing,
|
||||
onRefresh = remember(viewModel) {
|
||||
{ viewModel.trySendAction(VerificationCodeAction.RefreshPull) }
|
||||
},
|
||||
)
|
||||
|
||||
EventsEffect(viewModel = viewModel) { event ->
|
||||
when (event) {
|
||||
is VerificationCodeEvent.DismissPullToRefresh -> pullToRefreshState?.endRefresh()
|
||||
is VerificationCodeEvent.NavigateBack -> onNavigateBack()
|
||||
is VerificationCodeEvent.NavigateToVaultItem -> onNavigateToVaultItemScreen(event.id)
|
||||
is VerificationCodeEvent.NavigateToVaultSearchScreen -> {
|
||||
|
@ -74,7 +73,6 @@ fun VerificationCodeScreen(
|
|||
|
||||
VerificationCodeDialogs(dialogState = state.dialogState)
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||
BitwardenScaffold(
|
||||
modifier = Modifier
|
||||
|
|
|
@ -49,6 +49,7 @@ class VerificationCodeViewModel @Inject constructor(
|
|||
vaultFilterType = vaultRepository.vaultFilterType,
|
||||
viewState = VerificationCodeState.ViewState.Loading,
|
||||
dialogState = null,
|
||||
isRefreshing = false,
|
||||
)
|
||||
},
|
||||
) {
|
||||
|
@ -123,6 +124,7 @@ class VerificationCodeViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun handleRefreshPull() {
|
||||
mutableStateFlow.update { it.copy(isRefreshing = true) }
|
||||
// The Pull-To-Refresh composable is already in the refreshing state.
|
||||
// We will reset that state when sendDataStateFlow emits later on.
|
||||
vaultRepository.sync()
|
||||
|
@ -228,7 +230,7 @@ class VerificationCodeViewModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
}
|
||||
sendEvent(VerificationCodeEvent.DismissPullToRefresh)
|
||||
mutableStateFlow.update { it.copy(isRefreshing = false) }
|
||||
}
|
||||
|
||||
private fun vaultPendingReceive(
|
||||
|
@ -248,7 +250,7 @@ class VerificationCodeViewModel @Inject constructor(
|
|||
verificationCodeData = verificationCodeData.data,
|
||||
clearDialogState = true,
|
||||
)
|
||||
sendEvent(VerificationCodeEvent.DismissPullToRefresh)
|
||||
mutableStateFlow.update { it.copy(isRefreshing = false) }
|
||||
}
|
||||
|
||||
private fun vaultLoadingReceive() {
|
||||
|
@ -271,7 +273,7 @@ class VerificationCodeViewModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
}
|
||||
sendEvent(VerificationCodeEvent.DismissPullToRefresh)
|
||||
mutableStateFlow.update { it.copy(isRefreshing = false) }
|
||||
}
|
||||
|
||||
private fun updateStateWithVerificationCodeData(
|
||||
|
@ -339,6 +341,7 @@ data class VerificationCodeState(
|
|||
val baseIconUrl: String,
|
||||
val dialogState: DialogState?,
|
||||
val isPullToRefreshSettingEnabled: Boolean,
|
||||
val isRefreshing: Boolean,
|
||||
) : Parcelable {
|
||||
|
||||
/**
|
||||
|
@ -421,12 +424,6 @@ data class VerificationCodeDisplayItem(
|
|||
* Models events for the [VerificationCodeScreen].
|
||||
*/
|
||||
sealed class VerificationCodeEvent {
|
||||
|
||||
/**
|
||||
* Dismisses the pull-to-refresh indicator.
|
||||
*/
|
||||
data object DismissPullToRefresh : VerificationCodeEvent()
|
||||
|
||||
/**
|
||||
* Navigate back.
|
||||
*/
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.x8bit.bitwarden.ui.auth.feature.loginwithdevice
|
|||
|
||||
import android.net.Uri
|
||||
import androidx.compose.ui.test.assert
|
||||
import androidx.compose.ui.test.assertCountEquals
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.hasAnyAncestor
|
||||
import androidx.compose.ui.test.isDialog
|
||||
|
@ -124,12 +125,14 @@ class LoginWithDeviceScreenTest : BaseComposeTest() {
|
|||
mutableStateFlow.update {
|
||||
it.copy(viewState = LoginWithDeviceState.ViewState.Loading)
|
||||
}
|
||||
composeTestRule.onNode(isProgressBar).assertIsDisplayed()
|
||||
// There are 2 because of the pull-to-refresh
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(2)
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = DEFAULT_STATE.viewState)
|
||||
}
|
||||
composeTestRule.onNode(isProgressBar).assertDoesNotExist()
|
||||
// Only pull-to-refresh remains
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.x8bit.bitwarden.ui.platform.feature.search
|
||||
|
||||
import androidx.compose.ui.test.assert
|
||||
import androidx.compose.ui.test.assertCountEquals
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertIsNotDisplayed
|
||||
import androidx.compose.ui.test.filterToOne
|
||||
|
@ -125,13 +126,15 @@ class SearchScreenTest : BaseComposeTest() {
|
|||
@Test
|
||||
fun `progressbar should be displayed according to state`() {
|
||||
mutableStateFlow.update { DEFAULT_STATE }
|
||||
composeTestRule.onNode(isProgressBar).assertIsDisplayed()
|
||||
// There are 2 because of the pull-to-refresh
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(2)
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = SearchState.ViewState.Empty(message = null))
|
||||
}
|
||||
|
||||
composeTestRule.onNode(isProgressBar).assertDoesNotExist()
|
||||
// Only pull-to-refresh remains
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -119,6 +119,7 @@ class PendingRequestsScreenTest : BaseComposeTest() {
|
|||
authRequests = emptyList(),
|
||||
viewState = PendingRequestsState.ViewState.Loading,
|
||||
isPullToRefreshSettingEnabled = false,
|
||||
isRefreshing = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -376,6 +376,7 @@ class PendingRequestsViewModelTest : BaseViewModelTest() {
|
|||
authRequests = emptyList(),
|
||||
viewState = PendingRequestsState.ViewState.Empty,
|
||||
isPullToRefreshSettingEnabled = false,
|
||||
isRefreshing = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.x8bit.bitwarden.ui.tools.feature.send
|
||||
|
||||
import androidx.compose.ui.test.assert
|
||||
import androidx.compose.ui.test.assertCountEquals
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertTextEquals
|
||||
import androidx.compose.ui.test.filterToOne
|
||||
|
@ -263,22 +264,26 @@ class SendScreenTest : BaseComposeTest() {
|
|||
mutableStateFlow.update {
|
||||
it.copy(viewState = SendState.ViewState.Loading)
|
||||
}
|
||||
composeTestRule.onNode(isProgressBar).assertIsDisplayed()
|
||||
// There are 2 because of the pull-to-refresh
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(2)
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = SendState.ViewState.Empty)
|
||||
}
|
||||
composeTestRule.onNode(isProgressBar).assertDoesNotExist()
|
||||
// Only pull-to-refresh remains
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(1)
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = SendState.ViewState.Error("Fail".asText()))
|
||||
}
|
||||
composeTestRule.onNode(isProgressBar).assertDoesNotExist()
|
||||
// Only pull-to-refresh remains
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(1)
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = DEFAULT_CONTENT_VIEW_STATE)
|
||||
}
|
||||
composeTestRule.onNode(isProgressBar).assertDoesNotExist()
|
||||
// Only pull-to-refresh remains
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -709,6 +714,7 @@ private val DEFAULT_STATE: SendState = SendState(
|
|||
dialogState = null,
|
||||
isPullToRefreshSettingEnabled = false,
|
||||
policyDisablesSend = false,
|
||||
isRefreshing = false,
|
||||
)
|
||||
|
||||
private val DEFAULT_SEND_ITEM: SendState.ViewState.Content.SendItem =
|
||||
|
|
|
@ -313,52 +313,52 @@ class SendViewModelTest : BaseViewModelTest() {
|
|||
assertEquals(initialState.copy(dialogState = null), viewModel.stateFlow.value)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `VaultRepository SendData Error should update view state to Error and emit DismissPullToRefresh`() =
|
||||
runTest {
|
||||
val dialogState = SendState.DialogState.Loading(R.string.syncing.asText())
|
||||
val viewModel = createViewModel(state = DEFAULT_STATE.copy(dialogState = dialogState))
|
||||
fun `VaultRepository SendData Error should update view state to Error`() = runTest {
|
||||
val dialogState = SendState.DialogState.Loading(R.string.syncing.asText())
|
||||
val viewModel = createViewModel(state = DEFAULT_STATE.copy(dialogState = dialogState))
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
mutableSendDataFlow.value = DataState.Error(Throwable("Fail"))
|
||||
assertEquals(SendEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
viewModel.eventFlow.test {
|
||||
mutableSendDataFlow.value = DataState.Error(Throwable("Fail"))
|
||||
}
|
||||
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(
|
||||
viewState = SendState.ViewState.Error(
|
||||
message = R.string.generic_error_message.asText(),
|
||||
),
|
||||
dialogState = null,
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(
|
||||
viewState = SendState.ViewState.Error(
|
||||
message = R.string.generic_error_message.asText(),
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
dialogState = null,
|
||||
isRefreshing = false,
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `VaultRepository SendData Loaded should update view state and emit DismissPullToRefresh`() =
|
||||
runTest {
|
||||
val dialogState = SendState.DialogState.Loading(R.string.syncing.asText())
|
||||
val viewModel = createViewModel(state = DEFAULT_STATE.copy(dialogState = dialogState))
|
||||
val viewState = mockk<SendState.ViewState.Content>()
|
||||
val sendData = mockk<SendData> {
|
||||
every {
|
||||
toViewState(Environment.Us.environmentUrlData.baseWebSendUrl)
|
||||
} returns viewState
|
||||
}
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
mutableSendDataFlow.value = DataState.Loaded(sendData)
|
||||
assertEquals(SendEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(viewState = viewState, dialogState = null),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
fun `VaultRepository SendData Loaded should update view state`() = runTest {
|
||||
val dialogState = SendState.DialogState.Loading(R.string.syncing.asText())
|
||||
val viewModel = createViewModel(state = DEFAULT_STATE.copy(dialogState = dialogState))
|
||||
val viewState = mockk<SendState.ViewState.Content>()
|
||||
val sendData = mockk<SendData> {
|
||||
every {
|
||||
toViewState(Environment.Us.environmentUrlData.baseWebSendUrl)
|
||||
} returns viewState
|
||||
}
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
mutableSendDataFlow.value = DataState.Loaded(sendData)
|
||||
}
|
||||
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(
|
||||
viewState = viewState,
|
||||
dialogState = null,
|
||||
isRefreshing = false,
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `VaultRepository SendData Loading should update view state to Loading`() {
|
||||
val dialogState = SendState.DialogState.Loading(R.string.syncing.asText())
|
||||
|
@ -372,34 +372,32 @@ class SendViewModelTest : BaseViewModelTest() {
|
|||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `VaultRepository SendData NoNetwork should update view state to Error and emit DismissPullToRefresh`() =
|
||||
runTest {
|
||||
val dialogState = SendState.DialogState.Loading(R.string.syncing.asText())
|
||||
val viewModel = createViewModel(state = DEFAULT_STATE.copy(dialogState = dialogState))
|
||||
fun `VaultRepository SendData NoNetwork should update view state to Error`() = runTest {
|
||||
val dialogState = SendState.DialogState.Loading(R.string.syncing.asText())
|
||||
val viewModel = createViewModel(state = DEFAULT_STATE.copy(dialogState = dialogState))
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
mutableSendDataFlow.value = DataState.NoNetwork()
|
||||
assertEquals(SendEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(
|
||||
viewState = SendState.ViewState.Error(
|
||||
message = R.string.internet_connection_required_title
|
||||
.asText()
|
||||
.concat(
|
||||
" ".asText(),
|
||||
R.string.internet_connection_required_message.asText(),
|
||||
),
|
||||
),
|
||||
dialogState = null,
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
viewModel.eventFlow.test {
|
||||
mutableSendDataFlow.value = DataState.NoNetwork()
|
||||
}
|
||||
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(
|
||||
viewState = SendState.ViewState.Error(
|
||||
message = R.string.internet_connection_required_title
|
||||
.asText()
|
||||
.concat(
|
||||
" ".asText(),
|
||||
R.string.internet_connection_required_message.asText(),
|
||||
),
|
||||
),
|
||||
dialogState = null,
|
||||
isRefreshing = false,
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `VaultRepository SendData Pending should update view state`() {
|
||||
val dialogState = SendState.DialogState.Loading(R.string.syncing.asText())
|
||||
|
@ -470,4 +468,5 @@ private val DEFAULT_STATE: SendState = SendState(
|
|||
dialogState = null,
|
||||
isPullToRefreshSettingEnabled = false,
|
||||
policyDisablesSend = false,
|
||||
isRefreshing = false,
|
||||
)
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package com.x8bit.bitwarden.ui.tools.feature.send.addsend
|
||||
|
||||
import androidx.compose.ui.semantics.SemanticsActions
|
||||
import androidx.compose.ui.test.assert
|
||||
import androidx.compose.ui.test.assertCountEquals
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertIsEnabled
|
||||
import androidx.compose.ui.test.assertIsNotDisplayed
|
||||
|
@ -19,6 +21,7 @@ import androidx.compose.ui.test.onNodeWithContentDescription
|
|||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performScrollTo
|
||||
import androidx.compose.ui.test.performSemanticsAction
|
||||
import androidx.compose.ui.test.performTextInput
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||
|
@ -409,7 +412,9 @@ class AddSendScreenTest : BaseComposeTest() {
|
|||
fun `File segmented button click should send FileTypeClick`() {
|
||||
composeTestRule
|
||||
.onNodeWithText("File")
|
||||
.performClick()
|
||||
// A bug prevents performClick from working here so we
|
||||
// have to perform the semantic action instead.
|
||||
.performSemanticsAction(SemanticsActions.OnClick)
|
||||
verify { viewModel.trySendAction(AddSendAction.FileTypeClick) }
|
||||
}
|
||||
|
||||
|
@ -417,7 +422,9 @@ class AddSendScreenTest : BaseComposeTest() {
|
|||
fun `Text segmented button click should send TextTypeClick`() {
|
||||
composeTestRule
|
||||
.onAllNodesWithText("Text")[0]
|
||||
.performClick()
|
||||
// A bug prevents performClick from working here so we
|
||||
// have to perform the semantic action instead.
|
||||
.performSemanticsAction(SemanticsActions.OnClick)
|
||||
verify { viewModel.trySendAction(AddSendAction.TextTypeClick) }
|
||||
}
|
||||
|
||||
|
@ -912,17 +919,20 @@ class AddSendScreenTest : BaseComposeTest() {
|
|||
mutableStateFlow.update {
|
||||
it.copy(viewState = AddSendState.ViewState.Loading)
|
||||
}
|
||||
composeTestRule.onNode(isProgressBar).assertIsDisplayed()
|
||||
// There are 2 because of the pull-to-refresh
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(2)
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = AddSendState.ViewState.Error("Fail".asText()))
|
||||
}
|
||||
composeTestRule.onNode(isProgressBar).assertDoesNotExist()
|
||||
// Only pull-to-refresh remains
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(1)
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = DEFAULT_VIEW_STATE)
|
||||
}
|
||||
composeTestRule.onNode(isProgressBar).assertDoesNotExist()
|
||||
// Only pull-to-refresh remains
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.x8bit.bitwarden.ui.vault.feature.addedit
|
|||
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.test.assert
|
||||
import androidx.compose.ui.test.assertCountEquals
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertIsEnabled
|
||||
import androidx.compose.ui.test.assertIsNotDisplayed
|
||||
|
@ -580,12 +581,14 @@ class VaultAddEditScreenTest : BaseComposeTest() {
|
|||
mutableStateFlow.update {
|
||||
it.copy(viewState = VaultAddEditState.ViewState.Loading)
|
||||
}
|
||||
composeTestRule.onNode(isProgressBar).assertIsDisplayed()
|
||||
// There are 2 because of the pull-to-refresh
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(2)
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = VaultAddEditState.ViewState.Error("Fail".asText()))
|
||||
}
|
||||
composeTestRule.onNode(isProgressBar).assertDoesNotExist()
|
||||
// Only pull-to-refresh remains
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(1)
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
|
@ -596,7 +599,8 @@ class VaultAddEditScreenTest : BaseComposeTest() {
|
|||
),
|
||||
)
|
||||
}
|
||||
composeTestRule.onNode(isProgressBar).assertDoesNotExist()
|
||||
// Only pull-to-refresh remains
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.x8bit.bitwarden.ui.vault.feature.attachments
|
||||
|
||||
import androidx.compose.ui.test.assert
|
||||
import androidx.compose.ui.test.assertCountEquals
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.filterToOne
|
||||
import androidx.compose.ui.test.hasAnyAncestor
|
||||
|
@ -89,17 +90,20 @@ class AttachmentsScreenTest : BaseComposeTest() {
|
|||
@Test
|
||||
fun `progressbar should be displayed according to state`() {
|
||||
mutableStateFlow.update { it.copy(viewState = AttachmentsState.ViewState.Loading) }
|
||||
composeTestRule.onNode(isProgressBar).assertIsDisplayed()
|
||||
// There are 2 because of the pull-to-refresh
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(2)
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = AttachmentsState.ViewState.Error("Fail".asText()))
|
||||
}
|
||||
composeTestRule.onNode(isProgressBar).assertDoesNotExist()
|
||||
// Only pull-to-refresh remains
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(1)
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = DEFAULT_CONTENT_WITHOUT_ATTACHMENTS)
|
||||
}
|
||||
composeTestRule.onNode(isProgressBar).assertDoesNotExist()
|
||||
// Only pull-to-refresh remains
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -22,7 +22,6 @@ import androidx.compose.ui.test.onNodeWithContentDescription
|
|||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.onSiblings
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performScrollTo
|
||||
import androidx.compose.ui.test.performTextInput
|
||||
import androidx.core.net.toUri
|
||||
import com.x8bit.bitwarden.R
|
||||
|
@ -1364,9 +1363,8 @@ class VaultItemScreenTest : BaseComposeTest() {
|
|||
)
|
||||
}
|
||||
|
||||
composeTestRule
|
||||
.onNode(isProgressBar)
|
||||
.assertDoesNotExist()
|
||||
// Only pull-to-refresh remains
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(1)
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Passkey")
|
||||
|
@ -1411,9 +1409,8 @@ class VaultItemScreenTest : BaseComposeTest() {
|
|||
)
|
||||
}
|
||||
|
||||
composeTestRule
|
||||
.onNode(isProgressBar)
|
||||
.assertDoesNotExist()
|
||||
// Only pull-to-refresh remains
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(1)
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription("Copy TOTP")
|
||||
|
@ -1434,10 +1431,8 @@ class VaultItemScreenTest : BaseComposeTest() {
|
|||
)
|
||||
}
|
||||
|
||||
composeTestRule
|
||||
.onNode(isProgressBar)
|
||||
.performScrollTo()
|
||||
.assertIsDisplayed()
|
||||
// There are 2 because of the pull-to-refresh
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(2)
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription("Copy TOTP")
|
||||
|
@ -1452,10 +1447,8 @@ class VaultItemScreenTest : BaseComposeTest() {
|
|||
)
|
||||
}
|
||||
|
||||
composeTestRule
|
||||
.onNode(isProgressBar)
|
||||
.performScrollTo()
|
||||
.assertIsDisplayed()
|
||||
// There are 2 because of the pull-to-refresh
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(2)
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription("Copy TOTP")
|
||||
|
@ -1471,9 +1464,8 @@ class VaultItemScreenTest : BaseComposeTest() {
|
|||
)
|
||||
}
|
||||
|
||||
composeTestRule
|
||||
.onNode(isProgressBar)
|
||||
.assertIsNotDisplayed()
|
||||
// Only pull-to-refresh remains
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(1)
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription("Copy TOTP")
|
||||
|
@ -1680,19 +1672,22 @@ class VaultItemScreenTest : BaseComposeTest() {
|
|||
mutableStateFlow.update {
|
||||
it.copy(viewState = VaultItemState.ViewState.Loading)
|
||||
}
|
||||
composeTestRule.onNode(isProgressBar).assertIsDisplayed()
|
||||
// There are 2 because of the pull-to-refresh
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(2)
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = VaultItemState.ViewState.Error("Fail".asText()))
|
||||
}
|
||||
composeTestRule.onNode(isProgressBar).assertDoesNotExist()
|
||||
// Only pull-to-refresh remains
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(1)
|
||||
|
||||
mutableStateFlow.update { currentState ->
|
||||
updateLoginType(currentState) {
|
||||
copy(totpCodeItemData = null)
|
||||
}
|
||||
}
|
||||
composeTestRule.onNode(isProgressBar).assertDoesNotExist()
|
||||
// Only pull-to-refresh remains
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.x8bit.bitwarden.ui.vault.feature.itemlisting
|
||||
|
||||
import androidx.compose.ui.test.assert
|
||||
import androidx.compose.ui.test.assertCountEquals
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertIsNotDisplayed
|
||||
import androidx.compose.ui.test.assertTextEquals
|
||||
|
@ -490,9 +491,8 @@ class VaultItemListingScreenTest : BaseComposeTest() {
|
|||
fun `progressbar should be displayed according to state`() {
|
||||
mutableStateFlow.update { DEFAULT_STATE }
|
||||
|
||||
composeTestRule
|
||||
.onNode(isProgressBar)
|
||||
.assertIsDisplayed()
|
||||
// There are 2 because of the pull-to-refresh
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(2)
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
|
@ -504,9 +504,8 @@ class VaultItemListingScreenTest : BaseComposeTest() {
|
|||
)
|
||||
}
|
||||
|
||||
composeTestRule
|
||||
.onNode(isProgressBar)
|
||||
.assertDoesNotExist()
|
||||
// Only pull-to-refresh remains
|
||||
composeTestRule.onAllNodes(isProgressBar).assertCountEquals(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -2059,6 +2058,7 @@ private val DEFAULT_STATE = VaultItemListingState(
|
|||
policyDisablesSend = false,
|
||||
hasMasterPassword = true,
|
||||
isPremium = false,
|
||||
isRefreshing = false,
|
||||
)
|
||||
|
||||
private val STATE_FOR_AUTOFILL = DEFAULT_STATE.copy(
|
||||
|
|
|
@ -498,10 +498,6 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
|||
VaultItemListingState.DialogState.Loading(R.string.saving.asText()),
|
||||
viewModel.stateFlow.value.dialogState,
|
||||
)
|
||||
assertEquals(
|
||||
VaultItemListingEvent.DismissPullToRefresh,
|
||||
awaitItem(),
|
||||
)
|
||||
assertEquals(
|
||||
VaultItemListingEvent.Fido2UserVerification(
|
||||
isRequired = true,
|
||||
|
@ -1195,40 +1191,36 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `vaultDataStateFlow Loaded with items should update ViewState to Content`() =
|
||||
runTest {
|
||||
setupMockUri()
|
||||
fun `vaultDataStateFlow Loaded with items should update ViewState to Content`() = runTest {
|
||||
setupMockUri()
|
||||
|
||||
val dataState = DataState.Loaded(
|
||||
data = VaultData(
|
||||
cipherViewList = listOf(createMockCipherView(number = 1, isDeleted = false)),
|
||||
folderViewList = listOf(createMockFolderView(number = 1)),
|
||||
collectionViewList = listOf(createMockCollectionView(number = 1)),
|
||||
sendViewList = listOf(createMockSendView(number = 1)),
|
||||
),
|
||||
)
|
||||
val dataState = DataState.Loaded(
|
||||
data = VaultData(
|
||||
cipherViewList = listOf(createMockCipherView(number = 1, isDeleted = false)),
|
||||
folderViewList = listOf(createMockFolderView(number = 1)),
|
||||
collectionViewList = listOf(createMockCollectionView(number = 1)),
|
||||
sendViewList = listOf(createMockSendView(number = 1)),
|
||||
),
|
||||
)
|
||||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
mutableVaultDataStateFlow.tryEmit(value = dataState)
|
||||
assertEquals(VaultItemListingEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
mutableVaultDataStateFlow.tryEmit(value = dataState)
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.Content(
|
||||
displayCollectionList = emptyList(),
|
||||
displayItemList = listOf(
|
||||
createMockDisplayItemForCipher(number = 1)
|
||||
.copy(secondSubtitleTestTag = "PasskeySite"),
|
||||
),
|
||||
displayFolderList = emptyList(),
|
||||
assertEquals(
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.Content(
|
||||
displayCollectionList = emptyList(),
|
||||
displayItemList = listOf(
|
||||
createMockDisplayItemForCipher(number = 1)
|
||||
.copy(secondSubtitleTestTag = "PasskeySite"),
|
||||
),
|
||||
displayFolderList = emptyList(),
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
|
@ -1475,10 +1467,9 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
|||
),
|
||||
)
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
viewModel.eventFlow.test {
|
||||
mutableVaultDataStateFlow.tryEmit(value = dataState)
|
||||
assertEquals(VaultItemListingEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
|
||||
mutableVaultDataStateFlow.tryEmit(value = dataState)
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.NoItems(
|
||||
|
@ -1504,10 +1495,8 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
|||
)
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
mutableVaultDataStateFlow.tryEmit(value = dataState)
|
||||
assertEquals(VaultItemListingEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
mutableVaultDataStateFlow.tryEmit(value = dataState)
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.NoItems(
|
||||
|
@ -1626,10 +1615,8 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
|||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
mutableVaultDataStateFlow.tryEmit(value = dataState)
|
||||
assertEquals(VaultItemListingEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
mutableVaultDataStateFlow.tryEmit(value = dataState)
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.Error(
|
||||
|
@ -1656,10 +1643,8 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
|||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
mutableVaultDataStateFlow.tryEmit(value = dataState)
|
||||
assertEquals(VaultItemListingEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
mutableVaultDataStateFlow.tryEmit(value = dataState)
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.Content(
|
||||
|
@ -1691,10 +1676,8 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
|||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
mutableVaultDataStateFlow.tryEmit(value = dataState)
|
||||
assertEquals(VaultItemListingEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
mutableVaultDataStateFlow.tryEmit(value = dataState)
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.NoItems(
|
||||
|
@ -1721,10 +1704,8 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
|||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
mutableVaultDataStateFlow.tryEmit(value = dataState)
|
||||
assertEquals(VaultItemListingEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
mutableVaultDataStateFlow.tryEmit(value = dataState)
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.NoItems(
|
||||
|
@ -1743,10 +1724,8 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
|||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
mutableVaultDataStateFlow.tryEmit(value = dataState)
|
||||
assertEquals(VaultItemListingEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
mutableVaultDataStateFlow.tryEmit(value = dataState)
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.Error(
|
||||
|
@ -1777,10 +1756,8 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
|||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
mutableVaultDataStateFlow.tryEmit(value = dataState)
|
||||
assertEquals(VaultItemListingEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
mutableVaultDataStateFlow.tryEmit(value = dataState)
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.Content(
|
||||
|
@ -1811,10 +1788,8 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
|||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
mutableVaultDataStateFlow.tryEmit(value = dataState)
|
||||
assertEquals(VaultItemListingEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
mutableVaultDataStateFlow.tryEmit(value = dataState)
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.NoItems(
|
||||
|
@ -1840,10 +1815,8 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
|||
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
mutableVaultDataStateFlow.tryEmit(value = dataState)
|
||||
assertEquals(VaultItemListingEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
mutableVaultDataStateFlow.tryEmit(value = dataState)
|
||||
|
||||
assertEquals(
|
||||
createVaultItemListingState(
|
||||
viewState = VaultItemListingState.ViewState.NoItems(
|
||||
|
@ -3763,6 +3736,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
|||
hasMasterPassword = true,
|
||||
fido2CredentialRequest = null,
|
||||
isPremium = true,
|
||||
isRefreshing = false,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1190,6 +1190,7 @@ private val DEFAULT_STATE: VaultState = VaultState(
|
|||
isIconLoadingDisabled = false,
|
||||
hasMasterPassword = true,
|
||||
hideNotificationsDialog = true,
|
||||
isRefreshing = false,
|
||||
)
|
||||
|
||||
private val DEFAULT_CONTENT_VIEW_STATE: VaultState.ViewState.Content = VaultState.ViewState.Content(
|
||||
|
|
|
@ -612,7 +612,6 @@ class VaultViewModelTest : BaseViewModelTest() {
|
|||
VaultEvent.ShowToast(R.string.syncing_complete.asText()),
|
||||
awaitItem(),
|
||||
)
|
||||
assertEquals(VaultEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -660,7 +659,6 @@ class VaultViewModelTest : BaseViewModelTest() {
|
|||
VaultEvent.ShowToast(R.string.syncing_complete.asText()),
|
||||
awaitItem(),
|
||||
)
|
||||
assertEquals(VaultEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1591,4 +1589,5 @@ private fun createMockVaultState(
|
|||
isIconLoadingDisabled = false,
|
||||
hasMasterPassword = true,
|
||||
hideNotificationsDialog = true,
|
||||
isRefreshing = false,
|
||||
)
|
||||
|
|
|
@ -407,4 +407,5 @@ private val DEFAULT_STATE = VerificationCodeState(
|
|||
baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl,
|
||||
isPullToRefreshSettingEnabled = false,
|
||||
dialogState = null,
|
||||
isRefreshing = false,
|
||||
)
|
||||
|
|
|
@ -171,7 +171,6 @@ class VerificationCodeViewModelTest : BaseViewModelTest() {
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `AuthCodeFlow Pending with data should update state to Content`() {
|
||||
setupMockUri()
|
||||
|
@ -197,7 +196,6 @@ class VerificationCodeViewModelTest : BaseViewModelTest() {
|
|||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `AuthCodeFlow Pending with no data should call NavigateBack to go to the vault screen`() =
|
||||
runTest {
|
||||
|
@ -216,7 +214,6 @@ class VerificationCodeViewModelTest : BaseViewModelTest() {
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `AuthCodeFlow Error with data should update state to Content`() = runTest {
|
||||
setupMockUri()
|
||||
|
@ -233,10 +230,6 @@ class VerificationCodeViewModelTest : BaseViewModelTest() {
|
|||
),
|
||||
)
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
assertEquals(VerificationCodeEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
|
||||
assertEquals(
|
||||
createVerificationCodeState(
|
||||
viewState = VerificationCodeState.ViewState.Content(
|
||||
|
@ -247,7 +240,6 @@ class VerificationCodeViewModelTest : BaseViewModelTest() {
|
|||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `AuthCodeFlow Error with no data should call NavigateBack to go to the vault screen`() =
|
||||
runTest {
|
||||
|
@ -264,11 +256,9 @@ class VerificationCodeViewModelTest : BaseViewModelTest() {
|
|||
|
||||
viewModel.eventFlow.test {
|
||||
assertEquals(VerificationCodeEvent.NavigateBack, awaitItem())
|
||||
assertEquals(VerificationCodeEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `AuthCodeFlow Error with null data should show error screen`() = runTest {
|
||||
setupMockUri()
|
||||
|
@ -282,10 +272,6 @@ class VerificationCodeViewModelTest : BaseViewModelTest() {
|
|||
),
|
||||
)
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
assertEquals(VerificationCodeEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
|
||||
assertEquals(
|
||||
createVerificationCodeState(
|
||||
viewState = VerificationCodeState.ViewState.Error(
|
||||
|
@ -308,7 +294,6 @@ class VerificationCodeViewModelTest : BaseViewModelTest() {
|
|||
|
||||
viewModel.eventFlow.test {
|
||||
assertEquals(VerificationCodeEvent.NavigateBack, awaitItem())
|
||||
assertEquals(VerificationCodeEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -350,10 +335,6 @@ class VerificationCodeViewModelTest : BaseViewModelTest() {
|
|||
),
|
||||
)
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
assertEquals(VerificationCodeEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
|
||||
assertEquals(
|
||||
createVerificationCodeState(
|
||||
viewState = VerificationCodeState.ViewState.Content(
|
||||
|
@ -375,7 +356,6 @@ class VerificationCodeViewModelTest : BaseViewModelTest() {
|
|||
|
||||
viewModel.eventFlow.test {
|
||||
assertEquals(VerificationCodeEvent.NavigateBack, awaitItem())
|
||||
assertEquals(VerificationCodeEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -394,10 +374,6 @@ class VerificationCodeViewModelTest : BaseViewModelTest() {
|
|||
),
|
||||
)
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
assertEquals(VerificationCodeEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
|
||||
assertEquals(
|
||||
createVerificationCodeState(
|
||||
viewState = VerificationCodeState.ViewState.Content(
|
||||
|
@ -426,7 +402,6 @@ class VerificationCodeViewModelTest : BaseViewModelTest() {
|
|||
|
||||
viewModel.eventFlow.test {
|
||||
assertEquals(VerificationCodeEvent.NavigateBack, awaitItem())
|
||||
assertEquals(VerificationCodeEvent.DismissPullToRefresh, awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -527,6 +502,7 @@ class VerificationCodeViewModelTest : BaseViewModelTest() {
|
|||
baseIconUrl = environmentRepository.environment.environmentUrlData.baseIconUrl,
|
||||
dialogState = null,
|
||||
isPullToRefreshSettingEnabled = settingsRepository.getPullToRefreshEnabledFlow().value,
|
||||
isRefreshing = false,
|
||||
)
|
||||
|
||||
private fun createDisplayItemList() = listOf(
|
||||
|
|
|
@ -12,7 +12,7 @@ androidxActivity = "1.9.1"
|
|||
androidXBiometrics = "1.2.0-alpha05"
|
||||
androidxBrowser = "1.8.0"
|
||||
androidxCamera = "1.3.4"
|
||||
androidxComposeBom = "2024.08.00"
|
||||
androidxComposeBom = "2024.09.00"
|
||||
androidxCore = "1.13.1"
|
||||
androidxCredentials = "1.2.2"
|
||||
androidxHiltNavigationCompose = "1.2.0"
|
||||
|
|
Loading…
Reference in a new issue