From 0cdcfab32a2bed9493e0a3870d981eb01fc04c0c Mon Sep 17 00:00:00 2001
From: Dave Severns <dseverns@livefront.com>
Date: Thu, 2 Jan 2025 11:54:46 -0500
Subject: [PATCH] WIP

---
 .../content/BitwardenContentBlock.kt          | 96 ++++++++++++++++++-
 1 file changed, 92 insertions(+), 4 deletions(-)

diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/components/content/BitwardenContentBlock.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/components/content/BitwardenContentBlock.kt
index 391ed9ea8..38e3447b8 100644
--- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/components/content/BitwardenContentBlock.kt
+++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/components/content/BitwardenContentBlock.kt
@@ -2,14 +2,18 @@ package com.x8bit.bitwarden.ui.platform.components.content
 
 import androidx.annotation.DrawableRes
 import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material3.Icon
+import androidx.compose.material3.Switch
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
@@ -19,8 +23,11 @@ import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.RectangleShape
+import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.layout.onGloballyPositioned
 import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.text.AnnotatedString
 import androidx.compose.ui.text.TextStyle
 import androidx.compose.ui.tooling.preview.Preview
@@ -28,6 +35,7 @@ import androidx.compose.ui.unit.dp
 import com.x8bit.bitwarden.R
 import com.x8bit.bitwarden.ui.platform.base.util.bottomDivider
 import com.x8bit.bitwarden.ui.platform.components.model.ContentBlockData
+import com.x8bit.bitwarden.ui.platform.components.toggle.color.bitwardenSwitchColors
 import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
 import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
 
@@ -43,6 +51,9 @@ fun BitwardenContentBlock(
     subtitleTextStyle: TextStyle = BitwardenTheme.typography.bodyMedium,
     backgroundColor: Color = BitwardenTheme.colorScheme.background.secondary,
     showDivider: Boolean = true,
+    shape: ContentBlockShape = ContentBlockShape.Default,
+    onContentClick: (() -> Unit)? = null,
+    trailingContent: (@Composable () -> Unit)? = null,
 ) {
     BitwardenContentBlock(
         headerText = data.headerText,
@@ -53,6 +64,9 @@ fun BitwardenContentBlock(
         iconVectorResource = data.iconVectorResource,
         backgroundColor = backgroundColor,
         showDivider = showDivider,
+        shape = shape,
+        onContentClick = onContentClick,
+        trailingContent = trailingContent,
     )
 }
 
@@ -70,6 +84,9 @@ private fun BitwardenContentBlock(
     showDivider: Boolean = true,
     @DrawableRes iconVectorResource: Int? = null,
     backgroundColor: Color = BitwardenTheme.colorScheme.background.secondary,
+    shape: ContentBlockShape = ContentBlockShape.Default,
+    onContentClick: (() -> Unit)? = null,
+    trailingContent: (@Composable () -> Unit)? = null,
 ) {
     var dividerStartPadding by remember { mutableStateOf(0.dp) }
     val localDensity = LocalDensity.current
@@ -77,9 +94,15 @@ private fun BitwardenContentBlock(
     Row(
         modifier = Modifier
             .fillMaxWidth()
-            .background(backgroundColor)
+            .background(
+                color = backgroundColor,
+                shape = shape(),
+            )
+            .clickable(enabled = onContentClick != null) {
+                onContentClick?.invoke()
+            }
             .bottomDivider(
-                enabled = showDivider,
+                enabled = showDivider && (shape !is ContentBlockShape.Bottom),
                 paddingStart = dividerStartPadding,
             )
             .then(modifier),
@@ -107,7 +130,7 @@ private fun BitwardenContentBlock(
                 ?: Spacer(Modifier.width(16.dp))
         }
 
-        Column(modifier = Modifier.weight(weight = 1f, fill = false)) {
+        Column(modifier = Modifier.weight(weight = 1f, fill = true)) {
             Spacer(Modifier.height(12.dp))
             Text(
                 text = headerText,
@@ -123,16 +146,68 @@ private fun BitwardenContentBlock(
             }
             Spacer(Modifier.height(12.dp))
         }
+        trailingContent?.let {
+            Spacer(Modifier.width(16.dp))
+            it()
+        }
         Spacer(Modifier.width(16.dp))
     }
 }
 
+/**
+ * Sealed interface representing the shape of a [BitwardenContentBlock] background.
+ */
+sealed interface ContentBlockShape {
+    /**
+     * Returns the [Shape] defined by this [ContentBlockShape].
+     */
+    operator fun invoke(): Shape
+
+    /**
+     * The default [ContentBlockShape] implementation. A rectangle shape.
+     */
+    data object Default : ContentBlockShape {
+        override fun invoke(): Shape = RectangleShape
+    }
+
+    /**
+     * The shape of a [BitwardenContentBlock] with rounded corners at the top.
+     */
+    data object Top : ContentBlockShape {
+        override fun invoke(): Shape = RoundedCornerShape(
+            topStart = 8.dp,
+            topEnd = 8.dp,
+        )
+    }
+
+    /**
+     * The shape of a [BitwardenContentBlock] with rounded corners at the bottom.
+     */
+    data object Bottom : ContentBlockShape {
+        override fun invoke(): Shape = RoundedCornerShape(
+            bottomStart = 8.dp,
+            bottomEnd = 8.dp,
+        )
+    }
+
+    /**
+     * The shape of a [BitwardenContentBlock] with rounded corners on all sides.
+     */
+    data object Rounded : ContentBlockShape {
+        override fun invoke(): Shape = RoundedCornerShape(
+            size = 8.dp,
+        )
+    }
+}
+
 @Preview
 @Composable
 private fun BitwardenContentBlock_preview() {
     BitwardenTheme {
         Column(
-            modifier = Modifier.background(color = BitwardenTheme.colorScheme.background.primary),
+            modifier = Modifier
+                .background(color = BitwardenTheme.colorScheme.background.primary)
+                .padding(16.dp),
         ) {
             BitwardenContentBlock(
                 data = ContentBlockData(
@@ -140,6 +215,7 @@ private fun BitwardenContentBlock_preview() {
                     subtitleText = "Subtitle",
                     iconVectorResource = null,
                 ),
+                shape = ContentBlockShape.Top,
             )
             BitwardenContentBlock(
                 data = ContentBlockData(
@@ -155,6 +231,17 @@ private fun BitwardenContentBlock_preview() {
                     iconVectorResource = null,
                 ),
                 showDivider = false,
+                trailingContent = {
+                    Switch(
+                        modifier = Modifier
+                            .height(height = 56.dp)
+                            .testTag(tag = "SwitchToggle"),
+                        enabled = false,
+                        checked = false,
+                        onCheckedChange = null,
+                        colors = bitwardenSwitchColors(),
+                    )
+                },
             )
             BitwardenContentBlock(
                 data = ContentBlockData(
@@ -162,6 +249,7 @@ private fun BitwardenContentBlock_preview() {
                     subtitleText = "Subtitle",
                     iconVectorResource = null,
                 ),
+                shape = ContentBlockShape.Bottom,
             )
         }
     }