mirror of
https://github.com/bitwarden/android.git
synced 2025-12-10 09:56:45 -06:00
Simplify the BitwardenExpandableFloatingActionButton (#5989)
This commit is contained in:
parent
3a4f1d719f
commit
572d3357ee
@ -50,7 +50,6 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.core.net.toUri
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.ItemListingExpandableFabAction
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.VaultDropdownMenuAction
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.model.SharedCodesDisplayState
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.model.VerificationCodeDisplayItem
|
||||
@ -73,7 +72,8 @@ import com.bitwarden.ui.platform.components.dialog.BitwardenBasicDialog
|
||||
import com.bitwarden.ui.platform.components.dialog.BitwardenLoadingDialog
|
||||
import com.bitwarden.ui.platform.components.dialog.BitwardenTwoButtonDialog
|
||||
import com.bitwarden.ui.platform.components.fab.BitwardenExpandableFloatingActionButton
|
||||
import com.bitwarden.ui.platform.components.fab.ExpandableFabIcon
|
||||
import com.bitwarden.ui.platform.components.fab.model.ExpandableFabIcon
|
||||
import com.bitwarden.ui.platform.components.fab.model.ExpandableFabOption
|
||||
import com.bitwarden.ui.platform.components.header.BitwardenListHeaderText
|
||||
import com.bitwarden.ui.platform.components.icon.model.IconData
|
||||
import com.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||
@ -188,25 +188,25 @@ fun ItemListingScreen(
|
||||
BitwardenExpandableFloatingActionButton(
|
||||
modifier = Modifier.testTag("AddItemButton"),
|
||||
items = persistentListOf(
|
||||
ItemListingExpandableFabAction.ScanQrCode(
|
||||
ExpandableFabOption(
|
||||
label = BitwardenString.scan_a_qr_code.asText(),
|
||||
icon = IconData.Local(
|
||||
iconRes = BitwardenDrawable.ic_camera_small,
|
||||
contentDescription = BitwardenString.scan_a_qr_code.asText(),
|
||||
testTag = "ScanQRCodeButton",
|
||||
),
|
||||
onScanQrCodeClick = remember(viewModel) {
|
||||
onFabOptionClick = remember(viewModel) {
|
||||
{ launcher.launch(Manifest.permission.CAMERA) }
|
||||
},
|
||||
),
|
||||
ItemListingExpandableFabAction.EnterSetupKey(
|
||||
ExpandableFabOption(
|
||||
label = BitwardenString.enter_key_manually.asText(),
|
||||
icon = IconData.Local(
|
||||
iconRes = BitwardenDrawable.ic_lock_encrypted_small,
|
||||
contentDescription = BitwardenString.enter_key_manually.asText(),
|
||||
testTag = "EnterSetupKeyButton",
|
||||
),
|
||||
onEnterSetupKeyClick = remember(viewModel) {
|
||||
onFabOptionClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(ItemListingAction.EnterSetupKeyClick) }
|
||||
},
|
||||
),
|
||||
|
||||
@ -1,42 +0,0 @@
|
||||
package com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model
|
||||
|
||||
import androidx.compose.material3.ExtendedFloatingActionButton
|
||||
import com.bitwarden.ui.platform.components.fab.ExpandableFabOption
|
||||
import com.bitwarden.ui.platform.components.icon.model.IconData
|
||||
import com.bitwarden.ui.util.Text
|
||||
|
||||
/**
|
||||
* Models [ExpandableFabOption]s that can be triggered by the [ExtendedFloatingActionButton].
|
||||
*/
|
||||
sealed class ItemListingExpandableFabAction(
|
||||
label: Text,
|
||||
icon: IconData.Local,
|
||||
onFabOptionClick: () -> Unit,
|
||||
) : ExpandableFabOption(label, icon, onFabOptionClick) {
|
||||
|
||||
/**
|
||||
* Indicates the Scan QR code button was clicked.
|
||||
*/
|
||||
class ScanQrCode(
|
||||
label: Text,
|
||||
icon: IconData.Local,
|
||||
onScanQrCodeClick: () -> Unit,
|
||||
) : ItemListingExpandableFabAction(
|
||||
label = label,
|
||||
icon = icon,
|
||||
onFabOptionClick = onScanQrCodeClick,
|
||||
)
|
||||
|
||||
/**
|
||||
* Indicates the Enter Key button was clicked.
|
||||
*/
|
||||
class EnterSetupKey(
|
||||
label: Text,
|
||||
icon: IconData.Local,
|
||||
onEnterSetupKeyClick: () -> Unit,
|
||||
) : ItemListingExpandableFabAction(
|
||||
label = label,
|
||||
icon = icon,
|
||||
onFabOptionClick = onEnterSetupKeyClick,
|
||||
)
|
||||
}
|
||||
@ -17,16 +17,17 @@ import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.SmallFloatingActionButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.rotate
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.bitwarden.ui.platform.base.util.nullableTestTag
|
||||
import com.bitwarden.ui.platform.components.icon.model.IconData
|
||||
import com.bitwarden.ui.platform.components.fab.model.ExpandableFabIcon
|
||||
import com.bitwarden.ui.platform.components.fab.model.ExpandableFabOption
|
||||
import com.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||
import com.bitwarden.ui.platform.theme.BitwardenTheme
|
||||
import com.bitwarden.ui.util.Text
|
||||
@ -39,18 +40,46 @@ import kotlinx.collections.immutable.ImmutableList
|
||||
* @param items [ExpandableFabOption] buttons displayed when the FAB is expanded.
|
||||
* @param label [Text] displayed when the FAB is expanded.
|
||||
* @param modifier The modifier for this composable.
|
||||
* @param expandableFabState [ExpandableFabIcon] displayed in the FAB.
|
||||
* @param onStateChange Lambda invoked when the FAB expanded state changes.
|
||||
* @param initialIsExpanded The initial state of the [ExpandableFabIcon] displayed in the FAB.
|
||||
*/
|
||||
@Composable
|
||||
fun BitwardenExpandableFloatingActionButton(
|
||||
expandableFabIcon: ExpandableFabIcon,
|
||||
items: ImmutableList<ExpandableFabOption>,
|
||||
modifier: Modifier = Modifier,
|
||||
label: Text? = null,
|
||||
initialIsExpanded: Boolean = false,
|
||||
) {
|
||||
var isExpanded by rememberSaveable { mutableStateOf(value = initialIsExpanded) }
|
||||
BitwardenExpandableFloatingActionButton(
|
||||
expandableFabIcon = expandableFabIcon,
|
||||
items = items,
|
||||
label = label,
|
||||
isExpanded = isExpanded,
|
||||
onIsExpandedChange = { isExpanded = it },
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A FAB that expands, when clicked, to display a collection of options that can be clicked.
|
||||
*
|
||||
* @param expandableFabIcon The icon to display and how to display it.
|
||||
* @param items [ExpandableFabOption] buttons displayed when the FAB is expanded.
|
||||
* @param label [Text] displayed when the FAB is expanded.
|
||||
* @param modifier The modifier for this composable.
|
||||
* @param isExpanded whether the FAB is in the expanded state.
|
||||
* @param onIsExpandedChange Lambda invoked when the FAB expanded state changes.
|
||||
*/
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
fun <T : ExpandableFabOption> BitwardenExpandableFloatingActionButton(
|
||||
fun BitwardenExpandableFloatingActionButton(
|
||||
expandableFabIcon: ExpandableFabIcon,
|
||||
items: ImmutableList<T>,
|
||||
items: ImmutableList<ExpandableFabOption>,
|
||||
modifier: Modifier = Modifier,
|
||||
label: Text? = null,
|
||||
expandableFabState: MutableState<ExpandableFabState> = rememberExpandableFabState(),
|
||||
onStateChange: (expandableFabState: ExpandableFabState) -> Unit = { },
|
||||
isExpanded: Boolean,
|
||||
onIsExpandedChange: (isExpanded: Boolean) -> Unit,
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.End,
|
||||
@ -58,14 +87,14 @@ fun <T : ExpandableFabOption> BitwardenExpandableFloatingActionButton(
|
||||
modifier = modifier,
|
||||
) {
|
||||
AnimatedVisibility(
|
||||
visible = expandableFabState.value.isExpanded(),
|
||||
visible = isExpanded,
|
||||
label = "display_fab_options_animation",
|
||||
modifier = Modifier.weight(weight = 1f),
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.clickable(interactionSource = null, indication = null) {
|
||||
expandableFabState.value = ExpandableFabState.Collapsed
|
||||
onIsExpandedChange(false)
|
||||
}
|
||||
.fillMaxSize(),
|
||||
horizontalAlignment = Alignment.End,
|
||||
@ -78,8 +107,7 @@ fun <T : ExpandableFabOption> BitwardenExpandableFloatingActionButton(
|
||||
items(items) { expandableFabOption ->
|
||||
ExpandableFabOption(
|
||||
onFabOptionClick = {
|
||||
expandableFabState.value = expandableFabState.value.toggleValue()
|
||||
onStateChange(expandableFabState.value)
|
||||
onIsExpandedChange(!isExpanded)
|
||||
expandableFabOption.onFabOptionClick()
|
||||
},
|
||||
expandableFabOption = expandableFabOption,
|
||||
@ -89,23 +117,12 @@ fun <T : ExpandableFabOption> BitwardenExpandableFloatingActionButton(
|
||||
}
|
||||
|
||||
val rotation by animateFloatAsState(
|
||||
targetValue = if (expandableFabState.value.isExpanded()) {
|
||||
expandableFabIcon.iconRotation ?: 0f
|
||||
} else {
|
||||
0f
|
||||
},
|
||||
targetValue = if (isExpanded) expandableFabIcon.iconRotation else 0f,
|
||||
label = "add_item_rotation",
|
||||
)
|
||||
ExtendedFloatingActionButton(
|
||||
onClick = {
|
||||
expandableFabState.value = expandableFabState.value.toggleValue()
|
||||
onStateChange(expandableFabState.value)
|
||||
},
|
||||
expanded = if (label != null) {
|
||||
!expandableFabState.value.isExpanded()
|
||||
} else {
|
||||
false
|
||||
},
|
||||
onClick = { onIsExpandedChange(!isExpanded) },
|
||||
expanded = if (label != null) !isExpanded else false,
|
||||
containerColor = BitwardenTheme.colorScheme.filledButton.background,
|
||||
contentColor = BitwardenTheme.colorScheme.filledButton.foreground,
|
||||
shape = BitwardenTheme.shapes.fab,
|
||||
@ -131,9 +148,9 @@ fun <T : ExpandableFabOption> BitwardenExpandableFloatingActionButton(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun <T : ExpandableFabOption> ExpandableFabOption(
|
||||
expandableFabOption: T,
|
||||
onFabOptionClick: (option: T) -> Unit,
|
||||
private fun ExpandableFabOption(
|
||||
expandableFabOption: ExpandableFabOption,
|
||||
onFabOptionClick: (option: ExpandableFabOption) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
SmallFloatingActionButton(
|
||||
@ -163,53 +180,3 @@ private fun <T : ExpandableFabOption> ExpandableFabOption(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun rememberExpandableFabState(): MutableState<ExpandableFabState> =
|
||||
remember { mutableStateOf(ExpandableFabState.Collapsed) }
|
||||
|
||||
/**
|
||||
* Represents options displayed when the FAB is expanded.
|
||||
*/
|
||||
abstract class ExpandableFabOption(
|
||||
val label: Text,
|
||||
val icon: IconData.Local,
|
||||
val onFabOptionClick: () -> Unit,
|
||||
)
|
||||
|
||||
/**
|
||||
* Models data for an expandable FAB icon.
|
||||
*/
|
||||
data class ExpandableFabIcon(
|
||||
val icon: IconData.Local,
|
||||
val iconRotation: Float?,
|
||||
)
|
||||
|
||||
/**
|
||||
* Models the state of the expandable FAB.
|
||||
*/
|
||||
sealed class ExpandableFabState {
|
||||
/**
|
||||
* Indicates if the FAB is expanded.
|
||||
*/
|
||||
fun isExpanded(): Boolean = this == Expanded
|
||||
|
||||
/**
|
||||
* Invert the state of the FAB.
|
||||
*/
|
||||
fun toggleValue(): ExpandableFabState = if (isExpanded()) {
|
||||
Collapsed
|
||||
} else {
|
||||
Expanded
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates the FAB is collapsed.
|
||||
*/
|
||||
data object Collapsed : ExpandableFabState()
|
||||
|
||||
/**
|
||||
* Indicates the FAB is expanded.
|
||||
*/
|
||||
data object Expanded : ExpandableFabState()
|
||||
}
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
package com.bitwarden.ui.platform.components.fab.model
|
||||
|
||||
import com.bitwarden.ui.platform.components.icon.model.IconData
|
||||
|
||||
/**
|
||||
* Models data for an expandable FAB icon.
|
||||
*/
|
||||
data class ExpandableFabIcon(
|
||||
val icon: IconData.Local,
|
||||
val iconRotation: Float,
|
||||
)
|
||||
@ -0,0 +1,13 @@
|
||||
package com.bitwarden.ui.platform.components.fab.model
|
||||
|
||||
import com.bitwarden.ui.platform.components.icon.model.IconData
|
||||
import com.bitwarden.ui.util.Text
|
||||
|
||||
/**
|
||||
* Represents options displayed when the FAB is expanded.
|
||||
*/
|
||||
data class ExpandableFabOption(
|
||||
val label: Text,
|
||||
val icon: IconData.Local,
|
||||
val onFabOptionClick: () -> Unit,
|
||||
)
|
||||
Loading…
x
Reference in New Issue
Block a user