Skip to content

Commit

Permalink
add copy buttons to response body and header table
Browse files Browse the repository at this point in the history
  • Loading branch information
sunny-chung committed Feb 12, 2024
1 parent f759db9 commit a603124
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.sunnychung.application.multiplatform.hellohttp.ux

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.sunnychung.application.multiplatform.hellohttp.ux.local.LocalColor

@Composable
fun FloatingCopyButton(size: Dp = 20.dp, innerPadding: Dp = 4.dp, modifier: Modifier = Modifier, onClick: () -> Unit) {
val colours = LocalColor.current
AppImageButton(
resource = "copy-to-clipboard.svg",
size = size + innerPadding * 2,
innerPadding = PaddingValues(innerPadding),
color = colours.copyButton,
onClick = onClick,
modifier = modifier
.background(colours.backgroundFloatingButton, RoundedCornerShape(4.dp))
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import androidx.compose.ui.unit.dp
import com.sunnychung.application.multiplatform.hellohttp.ux.local.LocalColor

@Composable
fun KeyValueTableView(modifier: Modifier = Modifier, keyValues: List<Pair<String, String>>) {
fun KeyValueTableView(modifier: Modifier = Modifier, keyValues: List<Pair<String, String>>, isCopyable: Boolean = false) {
val colors = LocalColor.current

Column(modifier) {
Expand All @@ -30,8 +30,42 @@ fun KeyValueTableView(modifier: Modifier = Modifier, keyValues: List<Pair<String
LazyColumn {
items(items = keyValues) {
Row(modifier = Modifier.height(IntrinsicSize.Max)) {
AppTextField(value = it.first, readOnly = true, onValueChange = {}, backgroundColor = Color.Transparent, contentPadding = PaddingValues(0.dp), modifier = Modifier.weight(0.4f).fillMaxHeight().border(width = 1.dp, color = colors.placeholder, RectangleShape).padding(all = 8.dp))
AppTextField(value = it.second, readOnly = true, onValueChange = {}, backgroundColor = Color.Transparent, contentPadding = PaddingValues(0.dp), modifier = Modifier.weight(0.6f).fillMaxHeight().border(width = 1.dp, color = colors.placeholder, RectangleShape).padding(all = 8.dp))
CopyableContentContainer(
textToCopy = it.first,
isEnabled = isCopyable,
size = 16.dp,
innerPadding = 2.dp,
outerPadding = PaddingValues(top = 6.dp, end = 2.dp),
modifier = Modifier.weight(0.4f).fillMaxHeight()
.border(width = 1.dp, color = colors.placeholder, RectangleShape)
) {
AppTextField(
value = it.first,
readOnly = true,
onValueChange = {},
backgroundColor = Color.Transparent,
contentPadding = PaddingValues(0.dp),
modifier = Modifier.padding(all = 8.dp),
)
}
CopyableContentContainer(
textToCopy = it.second,
isEnabled = isCopyable,
size = 16.dp,
innerPadding = 2.dp,
outerPadding = PaddingValues(top = 6.dp, end = 2.dp),
modifier = Modifier.weight(0.6f).fillMaxHeight()
.border(width = 1.dp, color = colors.placeholder, RectangleShape)
) {
AppTextField(
value = it.second,
readOnly = true,
onValueChange = {},
backgroundColor = Color.Transparent,
contentPadding = PaddingValues(0.dp),
modifier = Modifier.padding(all = 8.dp),
)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
Expand All @@ -30,11 +31,17 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.PointerEventType
import androidx.compose.ui.input.pointer.onPointerEvent
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
Expand Down Expand Up @@ -169,7 +176,7 @@ fun ResponseViewerView(response: UserResponse, connectionStatus: ConnectionStatu
ResponseTab.Stream -> ResponseStreamView(response)

ResponseTab.Header -> if (response.headers != null) {
KeyValueTableView(keyValues = response.headers!!, modifier = Modifier.fillMaxSize().padding(8.dp))
KeyValueTableView(keyValues = response.headers!!, isCopyable = true, modifier = Modifier.fillMaxSize().padding(8.dp))
} else {
ResponseEmptyView(type = "header", isCommunicating = connectionStatus.isConnectionActive(), modifier = Modifier.fillMaxSize().padding(8.dp))
}
Expand Down Expand Up @@ -507,25 +514,28 @@ fun BodyViewerView(
PrettifyResult(contentToUse.decodeToString() ?: "")
}

CodeEditorView(
isReadOnly = true,
text = prettifyResult.prettyString,
collapsableLines = prettifyResult.collapsableLineRange,
collapsableChars = prettifyResult.collapsableCharRange,
transformations = if (selectedView.prettifier!!.formatName.contains("JSON")) {
listOf(JsonSyntaxHighlightTransformation(colours = colours))
} else {
emptyList()
},
modifier = modifier,
)
CopyableContentContainer(textToCopy = prettifyResult.prettyString, modifier = modifier) {
CodeEditorView(
isReadOnly = true,
text = prettifyResult.prettyString,
collapsableLines = prettifyResult.collapsableLineRange,
collapsableChars = prettifyResult.collapsableCharRange,
transformations = if (selectedView.prettifier!!.formatName.contains("JSON")) {
listOf(JsonSyntaxHighlightTransformation(colours = colours))
} else {
emptyList()
},
)
}
} else {
CodeEditorView(
isReadOnly = true,
text = errorMessage ?: content.decodeToString(),
textColor = colours.warning,
modifier = modifier,
)
val text = errorMessage ?: content.decodeToString()
CopyableContentContainer(textToCopy = text, modifier = modifier) {
CodeEditorView(
isReadOnly = true,
text = text,
textColor = colours.warning,
)
}
}
if (isEnableJsonPath) {
AppTextFieldWithPlaceholder(
Expand Down Expand Up @@ -591,6 +601,51 @@ fun ResponseBodyView(response: UserResponse) {
}
}

@Composable
@OptIn(ExperimentalComposeUiApi::class)
fun CopyableContentContainer(
modifier: Modifier = Modifier,
textToCopy: String,
isEnabled: Boolean = true,
size: Dp = 20.dp,
innerPadding: Dp = 4.dp,
outerPadding: PaddingValues = PaddingValues(top = 4.dp, end = 12.dp),
contentView: @Composable () -> Unit
) {
if (!isEnabled) {
Box(modifier = modifier) {
contentView()
}
return
}

val clipboardManager = LocalClipboardManager.current
var isShowCopyButton by remember { mutableStateOf(false) }

Box(
modifier = modifier
.onPointerEvent(PointerEventType.Enter) {
isShowCopyButton = true
}
.onPointerEvent(PointerEventType.Exit) {
isShowCopyButton = false
}
) {
contentView()
if (isShowCopyButton) {
FloatingCopyButton(
size = size,
innerPadding = innerPadding,
modifier = Modifier
.align(Alignment.TopEnd)
.padding(outerPadding)
) {
clipboardManager.setText(AnnotatedString(textToCopy))
}
}
}
}

private val DATE_TIME_FORMAT = KDateTimeFormat("HH:mm:ss.lll")
private val TIMESTAMP_COLUMN_WIDTH_DP = 120.dp
private val TYPE_COLUMN_WIDTH_DP = 20.dp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ data class AppColor(
val backgroundInputFieldHighlight: Color,
val backgroundInputFieldHighlightEmphasize: Color,
val backgroundCollapsed: Color,
val backgroundFloatingButton: Color = background.copy(alpha = 0.7f),

val primary: Color,
val bright: Color,
Expand Down Expand Up @@ -58,6 +59,8 @@ data class AppColor(
val scrollBarUnhover: Color,
val scrollBarHover: Color,

val copyButton: Color = image.copy(alpha = 0.8f),

val syntaxColor: SyntaxColor,
)

Expand Down
2 changes: 2 additions & 0 deletions src/jvmMain/resources/image/copy-to-clipboard.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit a603124

Please sign in to comment.