extract duplicated string literals into named constants
This commit is contained in:
@@ -48,6 +48,9 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
|
|||||||
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||||
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
|
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
|
||||||
|
|
||||||
|
private const val LABEL_HANG_UP = "Hang up"
|
||||||
|
private const val LABEL_CALLING = "Calling…"
|
||||||
|
|
||||||
// ---- Shared building blocks for previews ----
|
// ---- Shared building blocks for previews ----
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -172,7 +175,7 @@ private fun PreviewCallControls(
|
|||||||
shape = CircleShape,
|
shape = CircleShape,
|
||||||
modifier = Modifier.size(64.dp),
|
modifier = Modifier.size(64.dp),
|
||||||
) {
|
) {
|
||||||
Icon(MaterialSymbols.CallEnd, "Hang up", tint = Color.White, modifier = Modifier.size(32.dp))
|
Icon(MaterialSymbols.CallEnd, LABEL_HANG_UP, tint = Color.White, modifier = Modifier.size(32.dp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -207,7 +210,7 @@ private fun PreviewCallInProgress(
|
|||||||
shape = CircleShape,
|
shape = CircleShape,
|
||||||
modifier = Modifier.size(64.dp),
|
modifier = Modifier.size(64.dp),
|
||||||
) {
|
) {
|
||||||
Icon(MaterialSymbols.CallEnd, "Hang up", tint = Color.White, modifier = Modifier.size(32.dp))
|
Icon(MaterialSymbols.CallEnd, LABEL_HANG_UP, tint = Color.White, modifier = Modifier.size(32.dp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,7 +220,7 @@ private fun PreviewCallInProgress(
|
|||||||
@Composable
|
@Composable
|
||||||
fun PreviewCallingScreen() {
|
fun PreviewCallingScreen() {
|
||||||
ThemeComparisonColumn {
|
ThemeComparisonColumn {
|
||||||
PreviewCallInProgress("Alice", "Calling\u2026")
|
PreviewCallInProgress("Alice", LABEL_CALLING)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,7 +245,7 @@ fun PreviewCallingGroupScreen() {
|
|||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
Text("Alice, Bob +1", fontWeight = FontWeight.Bold, fontSize = 20.sp)
|
Text("Alice, Bob +1", fontWeight = FontWeight.Bold, fontSize = 20.sp)
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
Text("Calling\u2026", color = MaterialTheme.colorScheme.onSurfaceVariant, fontSize = 16.sp)
|
Text(LABEL_CALLING, color = MaterialTheme.colorScheme.onSurfaceVariant, fontSize = 16.sp)
|
||||||
Spacer(modifier = Modifier.height(48.dp))
|
Spacer(modifier = Modifier.height(48.dp))
|
||||||
FloatingActionButton(
|
FloatingActionButton(
|
||||||
onClick = {},
|
onClick = {},
|
||||||
@@ -250,7 +253,7 @@ fun PreviewCallingGroupScreen() {
|
|||||||
shape = CircleShape,
|
shape = CircleShape,
|
||||||
modifier = Modifier.size(64.dp),
|
modifier = Modifier.size(64.dp),
|
||||||
) {
|
) {
|
||||||
Icon(MaterialSymbols.CallEnd, "Hang up", tint = Color.White, modifier = Modifier.size(32.dp))
|
Icon(MaterialSymbols.CallEnd, LABEL_HANG_UP, tint = Color.White, modifier = Modifier.size(32.dp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -580,7 +583,7 @@ fun PreviewPipCallUI() {
|
|||||||
) {
|
) {
|
||||||
Icon(MaterialSymbols.Person, contentDescription = null, modifier = Modifier.size(48.dp))
|
Icon(MaterialSymbols.Person, contentDescription = null, modifier = Modifier.size(48.dp))
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
Text("Calling\u2026", fontSize = 10.sp, color = MaterialTheme.colorScheme.onSurfaceVariant)
|
Text(LABEL_CALLING, fontSize = 10.sp, color = MaterialTheme.colorScheme.onSurfaceVariant)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-7
@@ -39,6 +39,8 @@ import kotlinx.coroutines.launch
|
|||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
private const val NOSTR_URI_PREFIX = "nostr:"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* INav for screens that live inside a free-standing Activity (no Compose
|
* INav for screens that live inside a free-standing Activity (no Compose
|
||||||
* NavHost in scope) and need to dispatch navigation requests back to
|
* NavHost in scope) and need to dispatch navigation requests back to
|
||||||
@@ -127,31 +129,31 @@ class BouncingIntentNav(
|
|||||||
private fun routeToBouncingUri(route: Route): String? =
|
private fun routeToBouncingUri(route: Route): String? =
|
||||||
when (route) {
|
when (route) {
|
||||||
is Route.Profile -> {
|
is Route.Profile -> {
|
||||||
"nostr:" + NPub.create(route.id)
|
NOSTR_URI_PREFIX + NPub.create(route.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
is Route.Note -> {
|
is Route.Note -> {
|
||||||
"nostr:" + NEvent.create(route.id, null, null, null)
|
NOSTR_URI_PREFIX + NEvent.create(route.id, null, null, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
is Route.EventRedirect -> {
|
is Route.EventRedirect -> {
|
||||||
"nostr:" + NEvent.create(route.id, null, null, null)
|
NOSTR_URI_PREFIX + NEvent.create(route.id, null, null, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
is Route.Hashtag -> {
|
is Route.Hashtag -> {
|
||||||
"nostr:hashtag?id=" + route.hashtag
|
NOSTR_URI_PREFIX + "hashtag?id=" + route.hashtag
|
||||||
}
|
}
|
||||||
|
|
||||||
is Route.LiveActivityChannel -> {
|
is Route.LiveActivityChannel -> {
|
||||||
"nostr:" + NAddress.create(route.kind, route.pubKeyHex, route.dTag, null)
|
NOSTR_URI_PREFIX + NAddress.create(route.kind, route.pubKeyHex, route.dTag, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
is Route.Community -> {
|
is Route.Community -> {
|
||||||
"nostr:" + NAddress.create(route.kind, route.pubKeyHex, route.dTag, null)
|
NOSTR_URI_PREFIX + NAddress.create(route.kind, route.pubKeyHex, route.dTag, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
is Route.PublicChatChannel -> {
|
is Route.PublicChatChannel -> {
|
||||||
"nostr:" + NEvent.create(route.id, null, ChannelCreateEvent.KIND, null)
|
NOSTR_URI_PREFIX + NEvent.create(route.id, null, ChannelCreateEvent.KIND, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
|
|||||||
+11
-6
@@ -44,11 +44,16 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
private const val SAMPLE_PUBKEY_FRAGMENT =
|
||||||
|
"\"pubkey\":\"460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c\","
|
||||||
|
|
||||||
|
private const val SAMPLE_KIND_20_FRAGMENT = "\"kind\":20,"
|
||||||
|
|
||||||
private const val SAMPLE_PICTURE_EVENT_JSON =
|
private const val SAMPLE_PICTURE_EVENT_JSON =
|
||||||
"{\"id\":\"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2\"," +
|
"{\"id\":\"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2\"," +
|
||||||
"\"pubkey\":\"460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c\"," +
|
SAMPLE_PUBKEY_FRAGMENT +
|
||||||
"\"created_at\":1708695717," +
|
"\"created_at\":1708695717," +
|
||||||
"\"kind\":20," +
|
SAMPLE_KIND_20_FRAGMENT +
|
||||||
"\"tags\":[[\"title\",\"Sunset at the Beach\"]," +
|
"\"tags\":[[\"title\",\"Sunset at the Beach\"]," +
|
||||||
"[\"imeta\",\"url https://image.nostr.build/sample-sunset.jpg\"," +
|
"[\"imeta\",\"url https://image.nostr.build/sample-sunset.jpg\"," +
|
||||||
"\"m image/jpeg\",\"dim 1200x800\",\"alt A beautiful sunset over the ocean\"," +
|
"\"m image/jpeg\",\"dim 1200x800\",\"alt A beautiful sunset over the ocean\"," +
|
||||||
@@ -58,9 +63,9 @@ private const val SAMPLE_PICTURE_EVENT_JSON =
|
|||||||
|
|
||||||
private const val SAMPLE_PICTURE_EVENT_NO_TITLE_JSON =
|
private const val SAMPLE_PICTURE_EVENT_NO_TITLE_JSON =
|
||||||
"{\"id\":\"b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3\"," +
|
"{\"id\":\"b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3\"," +
|
||||||
"\"pubkey\":\"460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c\"," +
|
SAMPLE_PUBKEY_FRAGMENT +
|
||||||
"\"created_at\":1708695000," +
|
"\"created_at\":1708695000," +
|
||||||
"\"kind\":20," +
|
SAMPLE_KIND_20_FRAGMENT +
|
||||||
"\"tags\":[[\"imeta\",\"url https://image.nostr.build/sample-mountain.jpg\"," +
|
"\"tags\":[[\"imeta\",\"url https://image.nostr.build/sample-mountain.jpg\"," +
|
||||||
"\"m image/jpeg\",\"dim 1080x1080\",\"alt Mountain landscape\"]]," +
|
"\"m image/jpeg\",\"dim 1080x1080\",\"alt Mountain landscape\"]]," +
|
||||||
"\"content\":\"Mountain vibes today. Fresh air and clear skies.\"," +
|
"\"content\":\"Mountain vibes today. Fresh air and clear skies.\"," +
|
||||||
@@ -68,9 +73,9 @@ private const val SAMPLE_PICTURE_EVENT_NO_TITLE_JSON =
|
|||||||
|
|
||||||
private const val SAMPLE_MULTI_IMAGE_EVENT_JSON =
|
private const val SAMPLE_MULTI_IMAGE_EVENT_JSON =
|
||||||
"{\"id\":\"c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4\"," +
|
"{\"id\":\"c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4\"," +
|
||||||
"\"pubkey\":\"460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c\"," +
|
SAMPLE_PUBKEY_FRAGMENT +
|
||||||
"\"created_at\":1708694000," +
|
"\"created_at\":1708694000," +
|
||||||
"\"kind\":20," +
|
SAMPLE_KIND_20_FRAGMENT +
|
||||||
"\"tags\":[[\"title\",\"Travel Photos\"]," +
|
"\"tags\":[[\"title\",\"Travel Photos\"]," +
|
||||||
"[\"imeta\",\"url https://image.nostr.build/sample-travel1.jpg\"," +
|
"[\"imeta\",\"url https://image.nostr.build/sample-travel1.jpg\"," +
|
||||||
"\"m image/jpeg\",\"dim 800x600\",\"alt City street\"]," +
|
"\"m image/jpeg\",\"dim 800x600\",\"alt City street\"]," +
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ import java.time.format.DateTimeFormatter
|
|||||||
* - paints the result with ANSI colour when stdout is a TTY (disabled
|
* - paints the result with ANSI colour when stdout is a TTY (disabled
|
||||||
* by `NO_COLOR`, forced on by `CLICOLOR_FORCE`).
|
* by `NO_COLOR`, forced on by `CLICOLOR_FORCE`).
|
||||||
*/
|
*/
|
||||||
|
private const val EMPTY_LABEL = "(empty)"
|
||||||
|
|
||||||
object Output {
|
object Output {
|
||||||
enum class Mode { TEXT, JSON }
|
enum class Mode { TEXT, JSON }
|
||||||
|
|
||||||
@@ -137,7 +139,7 @@ object Output {
|
|||||||
.append(coloredKey)
|
.append(coloredKey)
|
||||||
.append(":")
|
.append(":")
|
||||||
.append(padding)
|
.append(padding)
|
||||||
out.append(' ').append(color.dim("(empty)")).append('\n')
|
out.append(' ').append(color.dim(EMPTY_LABEL)).append('\n')
|
||||||
} else {
|
} else {
|
||||||
out.append(prefix).append(coloredKey).append(":\n")
|
out.append(prefix).append(coloredKey).append(":\n")
|
||||||
renderMapBody(out, v, "$prefix ", color)
|
renderMapBody(out, v, "$prefix ", color)
|
||||||
@@ -190,7 +192,7 @@ object Output {
|
|||||||
.append(prefix)
|
.append(prefix)
|
||||||
.append(dash)
|
.append(dash)
|
||||||
.append(' ')
|
.append(' ')
|
||||||
.append(color.dim("(empty)"))
|
.append(color.dim(EMPTY_LABEL))
|
||||||
.append('\n')
|
.append('\n')
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -224,7 +226,7 @@ object Output {
|
|||||||
.append(':')
|
.append(':')
|
||||||
.append(rPad)
|
.append(rPad)
|
||||||
.append(' ')
|
.append(' ')
|
||||||
.append(color.dim("(empty)"))
|
.append(color.dim(EMPTY_LABEL))
|
||||||
.append('\n')
|
.append('\n')
|
||||||
} else {
|
} else {
|
||||||
out.append("$prefix ").append(color.bold(rKey)).append(":\n")
|
out.append("$prefix ").append(color.bold(rKey)).append(":\n")
|
||||||
|
|||||||
@@ -211,6 +211,7 @@ internal object MacosKeychainBackend : SecretBackend {
|
|||||||
internal object SecretServiceBackend : SecretBackend {
|
internal object SecretServiceBackend : SecretBackend {
|
||||||
const val BACKEND_ID = "secret-service"
|
const val BACKEND_ID = "secret-service"
|
||||||
private const val SERVICE_ATTR = "amy-nostr"
|
private const val SERVICE_ATTR = "amy-nostr"
|
||||||
|
private const val SECRET_TOOL_BIN = "secret-tool"
|
||||||
|
|
||||||
override val name: String = "keychain:$BACKEND_ID"
|
override val name: String = "keychain:$BACKEND_ID"
|
||||||
|
|
||||||
@@ -224,7 +225,7 @@ internal object SecretServiceBackend : SecretBackend {
|
|||||||
) {
|
) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return which("secret-tool") != null
|
return which(SECRET_TOOL_BIN) != null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun store(
|
override fun store(
|
||||||
@@ -233,7 +234,7 @@ internal object SecretServiceBackend : SecretBackend {
|
|||||||
): IdentitySecret {
|
): IdentitySecret {
|
||||||
val res =
|
val res =
|
||||||
runProc(
|
runProc(
|
||||||
"secret-tool",
|
SECRET_TOOL_BIN,
|
||||||
"store",
|
"store",
|
||||||
"--label=amy Nostr identity ${pubKeyHex.take(8)}",
|
"--label=amy Nostr identity ${pubKeyHex.take(8)}",
|
||||||
"service",
|
"service",
|
||||||
@@ -250,7 +251,7 @@ internal object SecretServiceBackend : SecretBackend {
|
|||||||
|
|
||||||
override fun resolve(secret: IdentitySecret): String {
|
override fun resolve(secret: IdentitySecret): String {
|
||||||
require(secret is IdentitySecret.Keychain)
|
require(secret is IdentitySecret.Keychain)
|
||||||
val res = runProc("secret-tool", "lookup", "service", secret.service, "account", secret.account)
|
val res = runProc(SECRET_TOOL_BIN, "lookup", "service", secret.service, "account", secret.account)
|
||||||
if (res.exit != 0 || res.stdout.isBlank()) {
|
if (res.exit != 0 || res.stdout.isBlank()) {
|
||||||
throw RuntimeException("secret-tool lookup failed (exit=${res.exit}): ${res.stderr.trim()}")
|
throw RuntimeException("secret-tool lookup failed (exit=${res.exit}): ${res.stderr.trim()}")
|
||||||
}
|
}
|
||||||
@@ -259,7 +260,7 @@ internal object SecretServiceBackend : SecretBackend {
|
|||||||
|
|
||||||
override fun delete(secret: IdentitySecret) {
|
override fun delete(secret: IdentitySecret) {
|
||||||
require(secret is IdentitySecret.Keychain)
|
require(secret is IdentitySecret.Keychain)
|
||||||
runProc("secret-tool", "clear", "service", secret.service, "account", secret.account)
|
runProc(SECRET_TOOL_BIN, "clear", "service", secret.service, "account", secret.account)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun which(cmd: String): File? {
|
private fun which(cmd: String): File? {
|
||||||
|
|||||||
Reference in New Issue
Block a user