Merge pull request #309 from greenart7c3/claude/add-requests-activities-screen-gUyg0

Store event content in history and display in activities
This commit is contained in:
greenart7c3
2026-03-06 13:20:17 -03:00
committed by GitHub
12 changed files with 221 additions and 8 deletions
@@ -0,0 +1,111 @@
{
"formatVersion": 1,
"database": {
"version": 3,
"identityHash": "05375ac6ff0b7b2ab82afd950bea114c",
"entities": [
{
"tableName": "history",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `pkKey` TEXT NOT NULL, `type` TEXT NOT NULL, `kind` INTEGER, `time` INTEGER NOT NULL, `accepted` INTEGER NOT NULL, `translatedPermission` TEXT NOT NULL, `content` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pkKey",
"columnName": "pkKey",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "kind",
"columnName": "kind",
"affinity": "INTEGER"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "accepted",
"columnName": "accepted",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "translatedPermission",
"columnName": "translatedPermission",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "content",
"columnName": "content",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "history_by_pk_key",
"unique": false,
"columnNames": [
"pkKey"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_pk_key` ON `${TABLE_NAME}` (`pkKey`)"
},
{
"name": "history_by_id",
"unique": false,
"columnNames": [
"id"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_id` ON `${TABLE_NAME}` (`id`)"
},
{
"name": "history_by_time",
"unique": false,
"columnNames": [
"time"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_time` ON `${TABLE_NAME}` (`time`)"
},
{
"name": "history_by_key_and_time",
"unique": false,
"columnNames": [
"pkKey",
"time"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_key_and_time` ON `${TABLE_NAME}` (`pkKey`, `time`)"
}
]
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '05375ac6ff0b7b2ab82afd950bea114c')"
]
}
}
@@ -111,6 +111,7 @@ class SignerProvider : ContentProvider() {
null,
TimeUtils.now(),
false,
content = message,
),
account.npub,
)
@@ -133,6 +134,7 @@ class SignerProvider : ContentProvider() {
null,
TimeUtils.now(),
true,
content = message,
),
account.npub,
)
@@ -209,6 +211,7 @@ class SignerProvider : ContentProvider() {
event.kind,
TimeUtils.now(),
false,
content = event.toJson(),
),
account.npub,
)
@@ -233,6 +236,7 @@ class SignerProvider : ContentProvider() {
event.kind,
TimeUtils.now(),
true,
content = signedEvent.toJson(),
),
account.npub,
)
@@ -309,6 +313,7 @@ class SignerProvider : ContentProvider() {
null,
TimeUtils.now(),
false,
content = content,
),
account.npub,
)
@@ -366,6 +371,7 @@ class SignerProvider : ContentProvider() {
null,
TimeUtils.now(),
true,
content = if (type == SignerType.NIP04_DECRYPT || type == SignerType.NIP44_DECRYPT || type == SignerType.DECRYPT_ZAP_EVENT) result else content,
),
account.npub,
)
@@ -15,11 +15,17 @@ val migration_1_2 = object : Migration(1, 2) {
}
}
val migration_2_3 = object : Migration(2, 3) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE history ADD COLUMN content TEXT NOT NULL DEFAULT ''")
}
}
@Database(
entities = [
HistoryEntity::class,
],
version = 2,
version = 3,
)
@TypeConverters(Converters::class)
abstract class HistoryDatabase : RoomDatabase() {
@@ -41,7 +47,7 @@ abstract class HistoryDatabase : RoomDatabase() {
)
.setQueryExecutor(executor)
.setTransactionExecutor(transactionExecutor)
.addMigrations(migration_1_2)
.addMigrations(migration_1_2, migration_2_3)
.build()
instance
@@ -34,4 +34,5 @@ data class HistoryEntity(
val time: Long,
val accepted: Boolean,
val translatedPermission: String = "",
val content: String = "",
)
@@ -364,6 +364,14 @@ object BunkerRequestUtils {
kind,
TimeUtils.now(),
true,
content = when (type) {
SignerType.SIGN_EVENT,
SignerType.NIP04_DECRYPT,
SignerType.NIP44_DECRYPT,
SignerType.DECRYPT_ZAP_EVENT,
-> response
else -> getDataFromBunker(bunkerRequest.request)
},
),
account.npub,
)
@@ -486,6 +494,7 @@ object BunkerRequestUtils {
null,
TimeUtils.now(),
false,
content = getDataFromBunker(bunkerRequest.request),
),
account.npub,
)
@@ -243,6 +243,7 @@ class EventNotificationConsumer(private val applicationContext: Context) {
amberEvent?.kind,
TimeUtils.now(),
true,
content = amberEvent?.content ?: "",
),
acc.npub,
)
@@ -766,6 +766,14 @@ object IntentUtils {
kind,
TimeUtils.now(),
true,
content = when (intentData.type) {
SignerType.SIGN_EVENT -> event
SignerType.NIP04_DECRYPT,
SignerType.NIP44_DECRYPT,
SignerType.DECRYPT_ZAP_EVENT,
-> value
else -> intentData.data
},
),
account.npub,
)
@@ -905,6 +913,7 @@ object IntentUtils {
kind,
TimeUtils.now(),
false,
content = intentData.data,
),
account.npub,
)
@@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.text.input.TextFieldState
@@ -28,6 +29,7 @@ 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.platform.LocalClipboard
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
@@ -43,14 +45,17 @@ import androidx.paging.PagingConfig
import androidx.paging.compose.collectAsLazyPagingItems
import com.greenart7c3.nostrsigner.Amber
import com.greenart7c3.nostrsigner.R
import com.greenart7c3.nostrsigner.database.AppDatabase
import com.greenart7c3.nostrsigner.database.HistoryEntity
import com.greenart7c3.nostrsigner.models.Account
import com.greenart7c3.nostrsigner.models.TimeUtils
import com.greenart7c3.nostrsigner.models.supportedKindNumbers
import com.greenart7c3.nostrsigner.service.ApplicationNameCache
import com.greenart7c3.nostrsigner.service.model.AmberEvent
import com.greenart7c3.nostrsigner.service.toShortenHex
import com.greenart7c3.nostrsigner.ui.components.EventSection
import com.greenart7c3.nostrsigner.ui.components.SimpleSearchBar
import com.greenart7c3.nostrsigner.ui.components.TagsSection
import com.greenart7c3.nostrsigner.ui.components.copyToClipboard
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -147,6 +152,15 @@ fun ActivitiesScreen(
@Composable
fun ActivityRow(activity: HistoryEntity, account: Account) {
val clipboard = LocalClipboard.current
val parsedEvent = remember(activity.content) {
if (activity.content.isBlank()) {
null
} else {
runCatching { AmberEvent.fromJson(activity.content).toEvent() }.getOrNull()
}
}
Column {
Row(
modifier = Modifier
@@ -161,7 +175,6 @@ fun ActivityRow(activity: HistoryEntity, account: Account) {
ApplicationName(
key = activity.pkKey,
accepted = activity.accepted,
database = Amber.instance.getDatabase(account.npub),
account = account,
)
@@ -172,6 +185,45 @@ fun ActivityRow(activity: HistoryEntity, account: Account) {
color = if (activity.accepted) Color.Unspecified else Color.Gray,
)
if (parsedEvent != null) {
if (parsedEvent.content.isNotBlank()) {
Spacer(Modifier.height(4.dp))
EventSection(
padding = 0.dp,
label = stringResource(R.string.content),
displayValue = parsedEvent.content,
onCopy = { copyToClipboard(clipboard, parsedEvent.content) },
)
}
if (parsedEvent.tags.isNotEmpty()) {
Spacer(Modifier.height(4.dp))
TagsSection(
horizontalPadding = 0,
verticalPadding = 0,
label = stringResource(R.string.tags),
tags = parsedEvent.tags,
onCopy = {
copyToClipboard(
clipboard,
parsedEvent.tags.joinToString(separator = ", ") {
"[${it.joinToString(separator = ", ") { tag -> "\"$tag\"" }}]"
},
)
},
)
}
} else if (activity.content.isNotBlank()) {
Spacer(Modifier.height(4.dp))
Text(
modifier = Modifier.padding(top = 2.dp),
text = activity.content,
maxLines = 3,
overflow = TextOverflow.Ellipsis,
fontSize = 14.sp,
color = if (activity.accepted) Color.Unspecified else Color.Gray,
)
}
Text(
modifier = Modifier.padding(top = 4.dp, bottom = 16.dp),
text = TimeUtils.formatLongToCustomDateTimeWithSeconds(activity.time * 1000),
@@ -197,7 +249,6 @@ fun ActivityRow(activity: HistoryEntity, account: Account) {
fun ApplicationName(
key: String,
accepted: Boolean,
database: AppDatabase,
account: Account,
) {
var name by remember { mutableStateOf("") }
@@ -205,7 +256,7 @@ fun ApplicationName(
LaunchedEffect(Unit) {
launch(Dispatchers.IO) {
if (ApplicationNameCache.names["${account.npub.toShortenHex()}-$key"] == null) {
val app = database.dao().getByKey(key)
val app = Amber.instance.getDatabase(account.npub).dao().getByKey(key)
app?.let {
name = it.application.name
ApplicationNameCache.names["${account.npub.toShortenHex()}-$key"] = it.application.name
@@ -397,6 +397,7 @@ fun BunkerMultiEventHomeScreen(
kind = localEvent.kind,
time = TimeUtils.now(),
accepted = request.checked.value,
content = localEvent.toJson(),
),
thisAccount.npub,
)
@@ -450,6 +451,7 @@ fun BunkerMultiEventHomeScreen(
null,
TimeUtils.now(),
request.checked.value,
content = request.request.params.first(),
),
thisAccount.npub,
)
@@ -494,6 +496,7 @@ fun BunkerMultiEventHomeScreen(
null,
TimeUtils.now(),
request.checked.value,
content = "",
),
thisAccount.npub,
)
@@ -549,6 +552,11 @@ fun BunkerMultiEventHomeScreen(
null,
TimeUtils.now(),
request.checked.value,
content = if (type == SignerType.NIP04_DECRYPT || type == SignerType.NIP44_DECRYPT || type == SignerType.DECRYPT_ZAP_EVENT) {
request.encryptedData?.result ?: ""
} else {
request.request.params.getOrElse(1) { "" }
},
),
thisAccount.npub,
)
@@ -18,6 +18,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.greenart7c3.nostrsigner.R
@@ -27,11 +28,12 @@ fun EventSection(
label: String,
displayValue: String,
onCopy: () -> Unit,
padding: Dp = 16.dp,
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
.padding(padding),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.Top,
) {
@@ -409,6 +409,7 @@ fun IntentMultiEventHomeScreen(
localEvent.kind,
TimeUtils.now(),
intentData.checked.value,
content = localEvent.toJson(),
),
thisAccount.npub,
)
@@ -462,6 +463,7 @@ fun IntentMultiEventHomeScreen(
null,
TimeUtils.now(),
intentData.checked.value,
content = intentData.data,
),
thisAccount.npub,
)
@@ -501,6 +503,11 @@ fun IntentMultiEventHomeScreen(
null,
TimeUtils.now(),
intentData.checked.value,
content = if (intentData.type == SignerType.NIP04_DECRYPT || intentData.type == SignerType.NIP44_DECRYPT || intentData.type == SignerType.DECRYPT_ZAP_EVENT) {
intentData.encryptedData?.result ?: ""
} else {
intentData.data
},
),
thisAccount.npub,
)
@@ -27,6 +27,8 @@ fun TagsSection(
label: String,
tags: Array<Array<String>>,
onCopy: () -> Unit,
horizontalPadding: Int = 16,
verticalPadding: Int = 12,
) {
val tagsToShow = tags.take(10)
val moreCount = tags.size - 10
@@ -34,7 +36,7 @@ fun TagsSection(
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 12.dp),
.padding(horizontal = horizontalPadding.dp, vertical = verticalPadding.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.Top,
) {