Prechádzať zdrojové kódy

Added key bottom sheet

Vadik Sirekanyan 2 rokov pred
rodič
commit
695b605c10

+ 5 - 1
app/src/main/java/org/sirekanyan/outline/MainContent.kt

@@ -34,6 +34,7 @@ import org.sirekanyan.outline.api.model.Key
 import org.sirekanyan.outline.db.ApiUrlDao
 import org.sirekanyan.outline.ui.AddKeyButton
 import org.sirekanyan.outline.ui.DrawerContent
+import org.sirekanyan.outline.ui.KeyBottomSheet
 import org.sirekanyan.outline.ui.KeyContent
 
 @Composable
@@ -56,7 +57,7 @@ fun MainContent(api: OutlineApi, dao: ApiUrlDao, state: MainState, keys: List<Ke
             LazyColumn(contentPadding = WindowInsets.systemBars.asPaddingValues()) {
                 keys.sortedByDescending(Key::traffic).forEach { key ->
                     item {
-                        KeyContent(key)
+                        KeyContent(key, onClick = { state.selectedKey = key })
                     }
                 }
             }
@@ -71,6 +72,9 @@ fun MainContent(api: OutlineApi, dao: ApiUrlDao, state: MainState, keys: List<Ke
                 }
             },
         )
+        state.selectedKey?.let {
+            KeyBottomSheet(key = it, onDismissRequest = { state.selectedKey = null })
+        }
     }
 }
 

+ 2 - 0
app/src/main/java/org/sirekanyan/outline/MainState.kt

@@ -11,6 +11,7 @@ import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.launch
+import org.sirekanyan.outline.api.model.Key
 
 @Composable
 fun rememberMainState(): MainState {
@@ -23,6 +24,7 @@ class MainState(val scope: CoroutineScope) {
     val drawer = DrawerState(DrawerValue.Closed)
     var page by mutableStateOf<Page>(HelloPage)
     val selected by derivedStateOf { (page as? SelectedPage)?.selected }
+    var selectedKey by mutableStateOf<Key?>(null)
 
     fun openDrawer() {
         scope.launch {

+ 5 - 2
app/src/main/java/org/sirekanyan/outline/api/model/AccessKey.kt

@@ -5,6 +5,9 @@ import kotlinx.serialization.Serializable
 @Serializable
 class AccessKey(
     val id: String,
-    val name: String,
     val accessUrl: String,
-)
+    private val name: String,
+) {
+    val nameOrDefault: String
+        get() = name.ifEmpty { "Key $id" }
+}

+ 64 - 0
app/src/main/java/org/sirekanyan/outline/ui/KeyBottomSheet.kt

@@ -0,0 +1,64 @@
+package org.sirekanyan.outline.ui
+
+import android.widget.Toast
+import android.widget.Toast.LENGTH_SHORT
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.navigationBarsPadding
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.ListItem
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.ModalBottomSheet
+import androidx.compose.material3.Text
+import androidx.compose.material3.rememberModalBottomSheetState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.RectangleShape
+import androidx.compose.ui.platform.LocalClipboardManager
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.unit.dp
+import kotlinx.coroutines.launch
+import org.sirekanyan.outline.api.model.Key
+import org.sirekanyan.outline.ui.icons.IconCopy
+
+@Composable
+@OptIn(ExperimentalMaterial3Api::class)
+fun KeyBottomSheet(key: Key, onDismissRequest: () -> Unit) {
+    val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
+    val localClipboard = LocalClipboardManager.current
+    val localContext = LocalContext.current
+    val coroutineScope = rememberCoroutineScope()
+    ModalBottomSheet(
+        onDismissRequest = onDismissRequest,
+        sheetState = sheetState,
+        shape = RectangleShape,
+        dragHandle = {},
+        windowInsets = WindowInsets(0.dp),
+    ) {
+        Column(Modifier.navigationBarsPadding().padding(top = 4.dp)) {
+            Text(
+                text = key.accessKey.nameOrDefault,
+                modifier = Modifier.padding(16.dp),
+                style = MaterialTheme.typography.labelLarge,
+            )
+            ListItem(
+                headlineContent = { Text("Copy") },
+                leadingContent = { Icon(IconCopy, null) },
+                modifier = Modifier.clickable {
+                    localClipboard.setText(AnnotatedString(key.accessKey.accessUrl))
+                    Toast.makeText(localContext, "Copied", LENGTH_SHORT).show()
+                    coroutineScope.launch {
+                        sheetState.hide()
+                    }.invokeOnCompletion {
+                        onDismissRequest()
+                    }
+                },
+            )
+        }
+    }
+}

+ 3 - 13
app/src/main/java/org/sirekanyan/outline/ui/KeyContent.kt

@@ -1,7 +1,5 @@
 package org.sirekanyan.outline.ui
 
-import android.widget.Toast
-import android.widget.Toast.LENGTH_SHORT
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Row
@@ -12,29 +10,21 @@ import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.platform.LocalClipboardManager
-import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.text.AnnotatedString
 import androidx.compose.ui.unit.dp
 import org.sirekanyan.outline.api.model.Key
 import org.sirekanyan.outline.text.formatTraffic
 
 @Composable
-fun KeyContent(key: Key) {
-    val localContext = LocalContext.current
-    val localClipboard = LocalClipboardManager.current
+fun KeyContent(key: Key, onClick: () -> Unit) {
     Row(
         Modifier
-            .clickable {
-                localClipboard.setText(AnnotatedString(key.accessKey.accessUrl))
-                Toast.makeText(localContext, "Copied", LENGTH_SHORT).show()
-            }
+            .clickable(onClick = onClick)
             .fillMaxWidth()
             .padding(16.dp),
         Arrangement.SpaceBetween,
         Alignment.CenterVertically,
     ) {
-        Text(key.accessKey.name.ifEmpty { "Key ${key.accessKey.id}" })
+        Text(key.accessKey.nameOrDefault)
         key.traffic?.let { traffic ->
             Text(
                 text = formatTraffic(traffic),

+ 36 - 0
app/src/main/java/org/sirekanyan/outline/ui/icons/IconCopy.kt

@@ -0,0 +1,36 @@
+package org.sirekanyan.outline.ui.icons
+
+import androidx.compose.material.icons.materialIcon
+import androidx.compose.material.icons.materialPath
+import androidx.compose.ui.graphics.vector.ImageVector
+
+val IconCopy: ImageVector =
+    materialIcon(name = "Filled.ContentCopy") {
+        materialPath {
+            moveTo(16.0f, 1.0f)
+            lineTo(4.0f, 1.0f)
+            curveToRelative(-1.1f, 0.0f, -2.0f, 0.9f, -2.0f, 2.0f)
+            verticalLineToRelative(14.0f)
+            horizontalLineToRelative(2.0f)
+            lineTo(4.0f, 3.0f)
+            horizontalLineToRelative(12.0f)
+            lineTo(16.0f, 1.0f)
+            close()
+            moveTo(19.0f, 5.0f)
+            lineTo(8.0f, 5.0f)
+            curveToRelative(-1.1f, 0.0f, -2.0f, 0.9f, -2.0f, 2.0f)
+            verticalLineToRelative(14.0f)
+            curveToRelative(0.0f, 1.1f, 0.9f, 2.0f, 2.0f, 2.0f)
+            horizontalLineToRelative(11.0f)
+            curveToRelative(1.1f, 0.0f, 2.0f, -0.9f, 2.0f, -2.0f)
+            lineTo(21.0f, 7.0f)
+            curveToRelative(0.0f, -1.1f, -0.9f, -2.0f, -2.0f, -2.0f)
+            close()
+            moveTo(19.0f, 21.0f)
+            lineTo(8.0f, 21.0f)
+            lineTo(8.0f, 7.0f)
+            horizontalLineToRelative(11.0f)
+            verticalLineToRelative(14.0f)
+            close()
+        }
+    }