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