From 5ad1bb869ba707317365856cd368ed1020afbb6c Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Wed, 7 May 2025 17:19:05 -0300 Subject: [PATCH] Add a option to accept or reject a permission temporarily --- .../8.json | 50 +- .../9.json | 449 ++++++++++++++++++ .../greenart7c3/nostrsigner/SignerProvider.kt | 60 ++- .../nostrsigner/database/AppDatabase.kt | 24 +- .../nostrsigner/database/ApplicationDao.kt | 2 +- .../database/ApplicationPermissionsEntity.kt | 3 + .../nostrsigner/service/AmberUtils.kt | 47 +- .../nostrsigner/ui/EditPermission.kt | 10 +- .../greenart7c3/nostrsigner/ui/MainScreen.kt | 33 +- .../nostrsigner/ui/SettingsScreen.kt | 32 +- .../ui/actions/AccountBackupDialog.kt | 2 +- .../ui/components/EncryptDecryptData.kt | 20 +- .../nostrsigner/ui/components/EventData.kt | 20 +- .../ui/components/LoginWithPubKey.kt | 21 +- .../ui/components/MultiEventHomeScreen.kt | 5 + .../ui/components/RememberMyChoice.kt | 65 +-- .../ui/components/SeedWordsPage.kt | 2 +- .../nostrsigner/ui/components/SignMessage.kt | 20 +- .../ui/components/SingleEventHomeScreen.kt | 81 +++- app/src/main/res/values/strings.xml | 2 + 20 files changed, 819 insertions(+), 129 deletions(-) create mode 100644 app/schemas/com.greenart7c3.nostrsigner.database.AppDatabase/9.json diff --git a/app/schemas/com.greenart7c3.nostrsigner.database.AppDatabase/8.json b/app/schemas/com.greenart7c3.nostrsigner.database.AppDatabase/8.json index 4043886c..709fa75f 100644 --- a/app/schemas/com.greenart7c3.nostrsigner.database.AppDatabase/8.json +++ b/app/schemas/com.greenart7c3.nostrsigner.database.AppDatabase/8.json @@ -2,7 +2,7 @@ "formatVersion": 1, "database": { "version": 8, - "identityHash": "cfdf9a16e23cb231083a71a03c572c39", + "identityHash": "08bd4cb1d1d0fd652f0234b33fcd367b", "entities": [ { "tableName": "application", @@ -106,18 +106,16 @@ "orders": [], "createSql": "CREATE INDEX IF NOT EXISTS `index_name` ON `${TABLE_NAME}` (`name`)" } - ], - "foreignKeys": [] + ] }, { "tableName": "applicationPermission", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER, `pkKey` TEXT NOT NULL, `type` TEXT NOT NULL, `kind` INTEGER, `acceptable` INTEGER NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`pkKey`) REFERENCES `application`(`key`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER, `pkKey` TEXT NOT NULL, `type` TEXT NOT NULL, `kind` INTEGER, `acceptable` INTEGER NOT NULL, `rememberType` INTEGER NOT NULL, `acceptUntil` INTEGER NOT NULL, `rejectUntil` INTEGER NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`pkKey`) REFERENCES `application`(`key`) ON UPDATE NO ACTION ON DELETE CASCADE )", "fields": [ { "fieldPath": "id", "columnName": "id", - "affinity": "INTEGER", - "notNull": false + "affinity": "INTEGER" }, { "fieldPath": "pkKey", @@ -134,14 +132,31 @@ { "fieldPath": "kind", "columnName": "kind", - "affinity": "INTEGER", - "notNull": false + "affinity": "INTEGER" }, { "fieldPath": "acceptable", "columnName": "acceptable", "affinity": "INTEGER", "notNull": true + }, + { + "fieldPath": "rememberType", + "columnName": "rememberType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "acceptUntil", + "columnName": "acceptUntil", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "rejectUntil", + "columnName": "rejectUntil", + "affinity": "INTEGER", + "notNull": true } ], "primaryKey": { @@ -234,8 +249,7 @@ "orders": [], "createSql": "CREATE INDEX IF NOT EXISTS `index_notification_time` ON `${TABLE_NAME}` (`time`)" } - ], - "foreignKeys": [] + ] }, { "tableName": "history", @@ -262,8 +276,7 @@ { "fieldPath": "kind", "columnName": "kind", - "affinity": "INTEGER", - "notNull": false + "affinity": "INTEGER" }, { "fieldPath": "time", @@ -358,9 +371,7 @@ "columnNames": [ "id" ] - }, - "indices": [], - "foreignKeys": [] + } }, { "tableName": "history2", @@ -387,8 +398,7 @@ { "fieldPath": "kind", "columnName": "kind", - "affinity": "INTEGER", - "notNull": false + "affinity": "INTEGER" }, { "fieldPath": "time", @@ -428,14 +438,12 @@ "orders": [], "createSql": "CREATE INDEX IF NOT EXISTS `history_by_id2` ON `${TABLE_NAME}` (`id`)" } - ], - "foreignKeys": [] + ] } ], - "views": [], "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, 'cfdf9a16e23cb231083a71a03c572c39')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '08bd4cb1d1d0fd652f0234b33fcd367b')" ] } } \ No newline at end of file diff --git a/app/schemas/com.greenart7c3.nostrsigner.database.AppDatabase/9.json b/app/schemas/com.greenart7c3.nostrsigner.database.AppDatabase/9.json new file mode 100644 index 00000000..56d4b999 --- /dev/null +++ b/app/schemas/com.greenart7c3.nostrsigner.database.AppDatabase/9.json @@ -0,0 +1,449 @@ +{ + "formatVersion": 1, + "database": { + "version": 9, + "identityHash": "08bd4cb1d1d0fd652f0234b33fcd367b", + "entities": [ + { + "tableName": "application", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `name` TEXT NOT NULL, `relays` TEXT NOT NULL, `url` TEXT NOT NULL, `icon` TEXT NOT NULL, `description` TEXT NOT NULL, `pubKey` TEXT NOT NULL, `isConnected` INTEGER NOT NULL, `secret` TEXT NOT NULL, `useSecret` INTEGER NOT NULL, `signPolicy` INTEGER NOT NULL, `closeApplication` INTEGER NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "key", + "columnName": "key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "relays", + "columnName": "relays", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "icon", + "columnName": "icon", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pubKey", + "columnName": "pubKey", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isConnected", + "columnName": "isConnected", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "secret", + "columnName": "secret", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "useSecret", + "columnName": "useSecret", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "signPolicy", + "columnName": "signPolicy", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "closeApplication", + "columnName": "closeApplication", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "key" + ] + }, + "indices": [ + { + "name": "index_key", + "unique": true, + "columnNames": [ + "key" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_key` ON `${TABLE_NAME}` (`key`)" + }, + { + "name": "index_name", + "unique": false, + "columnNames": [ + "name" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_name` ON `${TABLE_NAME}` (`name`)" + } + ] + }, + { + "tableName": "applicationPermission", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER, `pkKey` TEXT NOT NULL, `type` TEXT NOT NULL, `kind` INTEGER, `acceptable` INTEGER NOT NULL, `rememberType` INTEGER NOT NULL, `acceptUntil` INTEGER NOT NULL, `rejectUntil` INTEGER NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`pkKey`) REFERENCES `application`(`key`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER" + }, + { + "fieldPath": "pkKey", + "columnName": "pkKey", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "kind", + "columnName": "kind", + "affinity": "INTEGER" + }, + { + "fieldPath": "acceptable", + "columnName": "acceptable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "rememberType", + "columnName": "rememberType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "acceptUntil", + "columnName": "acceptUntil", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "rejectUntil", + "columnName": "rejectUntil", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "permissions_by_pk_key", + "unique": false, + "columnNames": [ + "pkKey" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `permissions_by_pk_key` ON `${TABLE_NAME}` (`pkKey`)" + }, + { + "name": "permissions_unique", + "unique": true, + "columnNames": [ + "pkKey", + "type", + "kind" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `permissions_unique` ON `${TABLE_NAME}` (`pkKey`, `type`, `kind`)" + } + ], + "foreignKeys": [ + { + "table": "application", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "pkKey" + ], + "referencedColumns": [ + "key" + ] + } + ] + }, + { + "tableName": "notification", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `eventId` TEXT NOT NULL, `time` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "eventId", + "columnName": "eventId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "time", + "columnName": "time", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_notification_eventId", + "unique": false, + "columnNames": [ + "eventId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_notification_eventId` ON `${TABLE_NAME}` (`eventId`)" + }, + { + "name": "index_notification_time", + "unique": false, + "columnNames": [ + "time" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_notification_time` ON `${TABLE_NAME}` (`time`)" + } + ] + }, + { + "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, FOREIGN KEY(`pkKey`) REFERENCES `application`(`key`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "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 + } + ], + "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`)" + } + ], + "foreignKeys": [ + { + "table": "application", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "pkKey" + ], + "referencedColumns": [ + "key" + ] + } + ] + }, + { + "tableName": "amber_log", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `type` TEXT NOT NULL, `message` TEXT NOT NULL, `time` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "message", + "columnName": "message", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "time", + "columnName": "time", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "history2", + "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)", + "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 + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "history_by_pk_key2", + "unique": false, + "columnNames": [ + "pkKey" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `history_by_pk_key2` ON `${TABLE_NAME}` (`pkKey`)" + }, + { + "name": "history_by_id2", + "unique": false, + "columnNames": [ + "id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `history_by_id2` ON `${TABLE_NAME}` (`id`)" + } + ] + } + ], + "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, '08bd4cb1d1d0fd652f0234b33fcd367b')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/SignerProvider.kt b/app/src/main/java/com/greenart7c3/nostrsigner/SignerProvider.kt index 851e5a38..8b81ab7a 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/SignerProvider.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/SignerProvider.kt @@ -93,7 +93,20 @@ class SignerProvider : ContentProvider() { sortOrder ?: packageName, "SIGN_MESSAGE", ) - val isRemembered = if (signPolicy == 2) true else permission?.acceptable ?: return null + val rejectUntil = permission?.rejectUntil ?: 0 + val acceptUntil = permission?.acceptUntil ?: 0 + val isRemembered = if (signPolicy == 2) { + true + } else { + if (rejectUntil == 0L && acceptUntil == 0L) return null + if (rejectUntil > TimeUtils.now() && rejectUntil > 0) { + false + } else if (acceptUntil > TimeUtils.now() && acceptUntil > 0) { + true + } else { + return null + } + } if (!isRemembered) { scope.launch { database.applicationDao().addHistory( @@ -193,7 +206,20 @@ class SignerProvider : ContentProvider() { } } val signPolicy = database.applicationDao().getSignPolicy(sortOrder ?: packageName) - val isRemembered = if (signPolicy == 2) true else permission?.acceptable ?: return null + val rejectUntil = permission?.rejectUntil ?: 0 + val acceptUntil = permission?.acceptUntil ?: 0 + val isRemembered = if (signPolicy == 2) { + true + } else { + if (rejectUntil == 0L && acceptUntil == 0L) return null + if (rejectUntil > TimeUtils.now() && rejectUntil > 0) { + false + } else if (acceptUntil > TimeUtils.now() && acceptUntil > 0) { + true + } else { + return null + } + } if (!isRemembered) { scope.launch { database.applicationDao().addHistory( @@ -308,7 +334,20 @@ class SignerProvider : ContentProvider() { } } val signPolicy = database.applicationDao().getSignPolicy(sortOrder ?: packageName) - val isRemembered = if (signPolicy == 2) true else permission?.acceptable ?: return null + val rejectUntil = permission?.rejectUntil ?: 0 + val acceptUntil = permission?.acceptUntil ?: 0 + val isRemembered = if (signPolicy == 2) { + true + } else { + if (rejectUntil == 0L && acceptUntil == 0L) return null + if (rejectUntil > TimeUtils.now() && rejectUntil > 0) { + false + } else if (acceptUntil > TimeUtils.now() && acceptUntil > 0) { + true + } else { + return null + } + } if (!isRemembered) { scope.launch { database.applicationDao().addHistory( @@ -395,7 +434,20 @@ class SignerProvider : ContentProvider() { ) val signPolicy = database.applicationDao().getSignPolicy(sortOrder ?: packageName) - val isRemembered = if (signPolicy == 2) true else permission?.acceptable ?: return null + val rejectUntil = permission?.rejectUntil ?: 0 + val acceptUntil = permission?.acceptUntil ?: 0 + val isRemembered = if (signPolicy == 2) { + true + } else { + if (rejectUntil == 0L && acceptUntil == 0L) return null + if (rejectUntil > TimeUtils.now() && rejectUntil > 0) { + false + } else if (acceptUntil > TimeUtils.now() && acceptUntil > 0) { + true + } else { + return null + } + } if (!isRemembered) { scope.launch { database.applicationDao().addHistory( diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/database/AppDatabase.kt b/app/src/main/java/com/greenart7c3/nostrsigner/database/AppDatabase.kt index 4f337bc7..e10afe31 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/database/AppDatabase.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/database/AppDatabase.kt @@ -67,6 +67,26 @@ val MIGRATION_7_8 = } } +val MIGRATION_8_9 = + object : Migration(8, 9) { + override fun migrate(db: SupportSQLiteDatabase) { + db.execSQL("ALTER TABLE `applicationPermission` ADD COLUMN `rememberType` INTEGER NOT NULL DEFAULT 0") + db.execSQL("ALTER TABLE `applicationPermission` ADD COLUMN `acceptUntil` INTEGER NOT NULL DEFAULT 0") + db.execSQL("ALTER TABLE `applicationPermission` ADD COLUMN `rejectUntil` INTEGER NOT NULL DEFAULT 0") + val cursor = db.query("SELECT * FROM applicationPermission") + while (cursor.moveToNext()) { + val id = cursor.getInt(cursor.getColumnIndexOrThrow("id")) + val acceptable = cursor.getInt(cursor.getColumnIndexOrThrow("acceptable")) + val until = Long.MAX_VALUE / 1000 + if (acceptable == 1) { + db.execSQL("UPDATE applicationPermission SET acceptUntil = $until, rejectUntil = 0, rememberType = 4 WHERE id = $id") + } else { + db.execSQL("UPDATE applicationPermission SET rejectUntil = $until, acceptUntil = 0, rememberType = 4 WHERE id = $id") + } + } + } + } + @Database( entities = [ ApplicationEntity::class, @@ -76,7 +96,7 @@ val MIGRATION_7_8 = LogEntity::class, HistoryEntity2::class, ], - version = 8, + version = 9, ) @TypeConverters(Converters::class) abstract class AppDatabase : RoomDatabase() { @@ -106,8 +126,10 @@ abstract class AppDatabase : RoomDatabase() { .addMigrations(MIGRATION_5_6) .addMigrations(MIGRATION_6_7) .addMigrations(MIGRATION_7_8) + .addMigrations(MIGRATION_8_9) .build() instance.openHelper.writableDatabase.execSQL("VACUUM") + instance } } diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/database/ApplicationDao.kt b/app/src/main/java/com/greenart7c3/nostrsigner/database/ApplicationDao.kt index 6fb53ef1..c71c47b3 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/database/ApplicationDao.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/database/ApplicationDao.kt @@ -64,7 +64,7 @@ interface ApplicationDao { @Transaction suspend fun getBySecret(secret: String): ApplicationWithPermissions? - @Query("SELECT * FROM applicationPermission WHERE pkKey = :key") + @Query("SELECT * FROM applicationPermission WHERE pkKey = :key and rememberType = 4") suspend fun getAllByKey(key: String): List @Query("SELECT * FROM application") diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/database/ApplicationPermissionsEntity.kt b/app/src/main/java/com/greenart7c3/nostrsigner/database/ApplicationPermissionsEntity.kt index c5e303e8..73fd7292 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/database/ApplicationPermissionsEntity.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/database/ApplicationPermissionsEntity.kt @@ -34,4 +34,7 @@ data class ApplicationPermissionsEntity( val type: String, val kind: Int?, var acceptable: Boolean, + val rememberType: Int, + var acceptUntil: Long, + var rejectUntil: Long, ) diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/service/AmberUtils.kt b/app/src/main/java/com/greenart7c3/nostrsigner/service/AmberUtils.kt index 108fc447..6ecde056 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/service/AmberUtils.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/service/AmberUtils.kt @@ -9,8 +9,8 @@ import com.greenart7c3.nostrsigner.models.Account import com.greenart7c3.nostrsigner.models.BunkerRequest import com.greenart7c3.nostrsigner.models.IntentData import com.greenart7c3.nostrsigner.models.SignerType -import com.greenart7c3.nostrsigner.models.kindToNip import com.greenart7c3.nostrsigner.ui.IntentResultType +import com.greenart7c3.nostrsigner.ui.RememberType import com.vitorpamplona.ammolite.relays.RelaySetupInfo import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey @@ -23,6 +23,7 @@ import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponse import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent import com.vitorpamplona.quartz.nip57Zaps.PrivateZapEncryption import com.vitorpamplona.quartz.utils.Hex +import com.vitorpamplona.quartz.utils.TimeUtils object AmberUtils { fun encryptOrDecryptData( @@ -161,27 +162,39 @@ object AmberUtils { intentData: IntentData, kind: Int?, value: Boolean, + rememberType: RememberType, account: Account, ) { - val noPermission = application.permissions.none { - val nip = it.kind?.kindToNip()?.toIntOrNull() - (it.type == intentData.type.toString() && it.kind == kind) || (nip != null && it.type == "NIP" && it.kind == nip) + val until = when (rememberType) { + RememberType.ALWAYS -> Long.MAX_VALUE / 1000 + RememberType.ONE_MINUTE -> TimeUtils.oneMinuteFromNow() + RememberType.FIVE_MINUTES -> TimeUtils.now() + TimeUtils.FIVE_MINUTES + RememberType.TEN_MINUTES -> TimeUtils.now() + TimeUtils.FIFTEEN_MINUTES + RememberType.NEVER -> 0L } - if (noPermission) { - application.permissions.add( - ApplicationPermissionsEntity( - null, - key, - intentData.type.toString(), - kind, - value, - ), - ) - Amber.instance.getDatabase(account.npub) - .applicationDao() - .insertApplicationWithPermissions(application) + if (kind != null) { + application.permissions.removeIf { it.kind == kind && it.type == intentData.type.toString() } + } else { + application.permissions.removeIf { it.type == intentData.type.toString() && it.type != "SIGN_EVENT" } } + + application.permissions.add( + ApplicationPermissionsEntity( + null, + key, + intentData.type.toString(), + kind, + value, + rememberType.screenCode, + if (value) until else 0L, + if (!value) until else 0L, + ), + ) + + Amber.instance.getDatabase(account.npub) + .applicationDao() + .insertApplicationWithPermissions(application) } } diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/EditPermission.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/EditPermission.kt index 82837d94..cb2c4615 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/EditPermission.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/EditPermission.kt @@ -212,7 +212,10 @@ fun EditPermission( val localPermissions = permissions.map { if (it.id == permission.id) { - it.copy(acceptable = !permission.acceptable) + it.copy( + acceptable = !permission.acceptable, + rememberType = RememberType.ALWAYS.screenCode, + ) } else { it.copy() } @@ -235,7 +238,10 @@ fun EditPermission( val localPermissions = permissions.map { if (it.id == permission.id) { - it.copy(acceptable = !permission.acceptable) + it.copy( + acceptable = !permission.acceptable, + rememberType = RememberType.ALWAYS.screenCode, + ) } else { it.copy() } diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/MainScreen.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/MainScreen.kt index d5eb1630..b3d8ba85 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/MainScreen.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/MainScreen.kt @@ -142,6 +142,7 @@ fun sendResult( signPolicy: Int? = null, onRemoveIntentData: (List, IntentResultType) -> Unit, shouldCloseApplication: Boolean? = null, + rememberType: RememberType, ) { onLoading(true) Amber.instance.applicationIOScope.launch { @@ -196,7 +197,7 @@ fun sendResult( intentData.bunkerRequest?.secret ?: "", intentData.bunkerRequest?.secret != null, account.signPolicy, - shouldCloseApplication ?: (intentData.bunkerRequest?.closeApplication != false), + shouldCloseApplication ?: (intentData.bunkerRequest?.closeApplication == false), ), permissions = mutableListOf(), ) @@ -217,6 +218,9 @@ fun sendResult( it.type.toUpperCase(Locale.current), it.kind, true, + RememberType.ALWAYS.screenCode, + Long.MAX_VALUE / 1000, + 0, ), ) } @@ -234,6 +238,9 @@ fun sendResult( it.type.toUpperCase(Locale.current), it.kind, true, + RememberType.ALWAYS.screenCode, + Long.MAX_VALUE / 1000, + 0, ), ) } @@ -244,7 +251,21 @@ fun sendResult( } } - if (rememberChoice) { + if (rememberType != RememberType.NEVER) { + val until = when (rememberType) { + RememberType.ALWAYS -> Long.MAX_VALUE / 1000 + RememberType.ONE_MINUTE -> TimeUtils.oneMinuteFromNow() + RememberType.FIVE_MINUTES -> TimeUtils.now() + TimeUtils.FIVE_MINUTES + RememberType.TEN_MINUTES -> TimeUtils.now() + TimeUtils.FIFTEEN_MINUTES + RememberType.NEVER -> 0L + } + + if (kind != null) { + application.permissions.removeIf { it.kind == kind && it.type == intentData.type.toString() } + } else { + application.permissions.removeIf { it.type == intentData.type.toString() && it.type != "SIGN_EVENT" } + } + application.permissions.add( ApplicationPermissionsEntity( null, @@ -252,6 +273,9 @@ fun sendResult( intentData.type.toString(), kind, true, + rememberType.screenCode, + until, + 0, ), ) } @@ -272,6 +296,9 @@ fun sendResult( SignerType.GET_PUBLIC_KEY.toString(), null, true, + RememberType.ALWAYS.screenCode, + Long.MAX_VALUE / 1000, + 0, ), ) } @@ -309,7 +336,7 @@ fun sendResult( onDone = { Amber.instance.applicationIOScope.launch { if (!it) { - if (rememberChoice) { + if (rememberType != RememberType.NEVER) { if (intentData.type == SignerType.SIGN_EVENT) { kind?.let { database.applicationDao().deletePermissions(key, intentData.type.toString(), kind) diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/SettingsScreen.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/SettingsScreen.kt index e79e70eb..ab81c311 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/SettingsScreen.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/SettingsScreen.kt @@ -423,9 +423,11 @@ fun SettingsScreen( @Composable fun SettingsRow( name: Int, - description: Int, + description: Int?, selectedItems: ImmutableList, selectedIndex: Int, + maxLines: Int = 1, + overflow: TextOverflow = TextOverflow.Ellipsis, onSelect: (Int) -> Unit, ) { Row( @@ -438,16 +440,18 @@ fun SettingsRow( ) { Text( text = stringResource(name), - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - Text( - text = stringResource(description), - style = MaterialTheme.typography.bodySmall, - color = Color.Gray, - maxLines = 2, - overflow = TextOverflow.Ellipsis, + maxLines = maxLines, + overflow = overflow, ) + description?.let { + Text( + text = stringResource(description), + style = MaterialTheme.typography.bodySmall, + color = Color.Gray, + maxLines = 2, + overflow = TextOverflow.Ellipsis, + ) + } } TextSpinner( @@ -462,6 +466,14 @@ fun SettingsRow( } } +enum class RememberType(val screenCode: Int, val resourceId: Int) { + NEVER(0, R.string.never), + ONE_MINUTE(1, R.string.one_minute), + FIVE_MINUTES(2, R.string.five_minutes), + TEN_MINUTES(3, R.string.ten_minutes), + ALWAYS(4, R.string.always), +} + enum class BiometricsTimeType(val screenCode: Int, val resourceId: Int) { EVERY_TIME(0, R.string.every_time), ONE_MINUTE(1, R.string.one_minute), diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/actions/AccountBackupDialog.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/actions/AccountBackupDialog.kt index 7a287172..14e2279d 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/actions/AccountBackupDialog.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/actions/AccountBackupDialog.kt @@ -122,7 +122,7 @@ fun AccountBackupScreen( SeedWordsPage( seedWords = account.seedWords, showNextButton = false, - ) {} + ) } } } diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/EncryptDecryptData.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/EncryptDecryptData.kt index 835de624..28105561 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/EncryptDecryptData.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/EncryptDecryptData.kt @@ -18,6 +18,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier @@ -36,6 +37,7 @@ import androidx.compose.ui.unit.sp import com.greenart7c3.nostrsigner.R import com.greenart7c3.nostrsigner.models.Account import com.greenart7c3.nostrsigner.models.SignerType +import com.greenart7c3.nostrsigner.ui.RememberType import com.greenart7c3.nostrsigner.ui.verticalScrollbar import kotlinx.coroutines.launch @@ -51,8 +53,8 @@ fun EncryptDecryptData( applicationName: String?, appName: String, type: SignerType, - onAccept: () -> Unit, - onReject: () -> Unit, + onAccept: (RememberType) -> Unit, + onReject: (RememberType) -> Unit, ) { var showMore by androidx.compose.runtime.remember { mutableStateOf(false) @@ -61,6 +63,9 @@ fun EncryptDecryptData( val coroutineScope = rememberCoroutineScope() val context = LocalContext.current val scrollState = rememberScrollState() + var rememberType by remember { + mutableStateOf(RememberType.NEVER) + } Column( Modifier @@ -165,12 +170,17 @@ fun EncryptDecryptData( onAccept, onReject, ) { - remember.value = !remember.value + remember.value = it != RememberType.NEVER + rememberType = it } AcceptRejectButtons( - onAccept, - onReject, + onAccept = { + onAccept(rememberType) + }, + onReject = { + onReject(rememberType) + }, ) } } diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/EventData.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/EventData.kt index 57ff976f..710726b5 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/EventData.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/EventData.kt @@ -18,6 +18,7 @@ import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.key import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -35,6 +36,7 @@ import com.greenart7c3.nostrsigner.models.Account import com.greenart7c3.nostrsigner.models.Permission import com.greenart7c3.nostrsigner.models.SignerType import com.greenart7c3.nostrsigner.service.model.AmberEvent +import com.greenart7c3.nostrsigner.ui.RememberType import com.greenart7c3.nostrsigner.ui.verticalScrollbar import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent @@ -51,14 +53,17 @@ fun EventData( event: Event, rawJson: String, type: SignerType, - onAccept: () -> Unit, - onReject: () -> Unit, + onAccept: (RememberType) -> Unit, + onReject: (RememberType) -> Unit, ) { var showMore by androidx.compose.runtime.remember { mutableStateOf(false) } val context = LocalContext.current val scrollState = rememberScrollState() + var rememberType by remember { + mutableStateOf(RememberType.NEVER) + } Column( Modifier @@ -157,12 +162,17 @@ fun EventData( onAccept, onReject, ) { - remember.value = !remember.value + remember.value = it != RememberType.NEVER + rememberType = it } AcceptRejectButtons( - onAccept, - onReject, + onAccept = { + onAccept(rememberType) + }, + onReject = { + onReject(rememberType) + }, ) } } diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/LoginWithPubKey.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/LoginWithPubKey.kt index 7dc32efd..028ccb3b 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/LoginWithPubKey.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/LoginWithPubKey.kt @@ -59,6 +59,7 @@ import com.greenart7c3.nostrsigner.R import com.greenart7c3.nostrsigner.models.Account import com.greenart7c3.nostrsigner.models.Permission import com.greenart7c3.nostrsigner.service.toShortenHex +import com.greenart7c3.nostrsigner.ui.RememberType import com.greenart7c3.nostrsigner.ui.fromHex import com.greenart7c3.nostrsigner.ui.navigation.Route import com.greenart7c3.nostrsigner.ui.verticalScrollbar @@ -132,8 +133,8 @@ fun LoginWithPubKey( appName: String, applicationName: String?, permissions: List?, - onAccept: (List?, Int, Boolean?) -> Unit, - onReject: () -> Unit, + onAccept: (List?, Int, Boolean?, RememberType) -> Unit, + onReject: (RememberType) -> Unit, ) { val localPermissions = remember { val snapshot = mutableStateListOf() @@ -144,6 +145,7 @@ fun LoginWithPubKey( } val scrollState = rememberScrollState() + var rememberType by remember { mutableStateOf(RememberType.NEVER) } if (isBunkerRequest) { Column( @@ -195,7 +197,8 @@ fun LoginWithPubKey( onReject = onReject, remember = remember.value, onChanged = { - remember.value = !remember.value + remember.value = it != RememberType.NEVER + rememberType = it }, packageName = packageName, ) @@ -203,14 +206,16 @@ fun LoginWithPubKey( AmberButton( modifier = Modifier.padding(vertical = 20.dp), onClick = { - onAccept(localPermissions, 1, null) + onAccept(localPermissions, 1, null, rememberType) }, text = stringResource(R.string.grant_permissions), ) AmberButton( modifier = Modifier.padding(vertical = 20.dp), - onClick = onReject, + onClick = { + onReject(rememberType) + }, colors = ButtonDefaults.buttonColors( containerColor = Color(0xFFFF6B00), ), @@ -405,14 +410,16 @@ fun LoginWithPubKey( AmberButton( modifier = Modifier.padding(vertical = 20.dp), onClick = { - onAccept(localPermissions, selectedOption, closeApp) + onAccept(localPermissions, selectedOption, closeApp, rememberType) }, text = stringResource(R.string.grant_permissions), ) AmberButton( modifier = Modifier.padding(vertical = 20.dp), - onClick = onReject, + onClick = { + onReject(rememberType) + }, colors = ButtonDefaults.buttonColors( containerColor = Color(0xFFFF6B00), ), diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/MultiEventHomeScreen.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/MultiEventHomeScreen.kt index 41fe60d5..3fe5fe76 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/MultiEventHomeScreen.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/MultiEventHomeScreen.kt @@ -65,6 +65,7 @@ import com.greenart7c3.nostrsigner.service.MultiEventScreenIntents import com.greenart7c3.nostrsigner.service.getAppCompatActivity import com.greenart7c3.nostrsigner.service.toShortenHex import com.greenart7c3.nostrsigner.ui.IntentResultType +import com.greenart7c3.nostrsigner.ui.RememberType import com.greenart7c3.nostrsigner.ui.Result import com.greenart7c3.nostrsigner.ui.navigation.Route import com.greenart7c3.nostrsigner.ui.theme.orange @@ -230,6 +231,7 @@ fun MultiEventHomeScreen( intentData, localEvent.kind, intentData.rememberMyChoice.value, + RememberType.ALWAYS, thisAccount, ) } @@ -313,6 +315,7 @@ fun MultiEventHomeScreen( intentData, null, intentData.rememberMyChoice.value, + RememberType.ALWAYS, thisAccount, ) } @@ -438,6 +441,7 @@ fun MultiEventHomeScreen( intentData, null, intentData.rememberMyChoice.value, + RememberType.ALWAYS, thisAccount, ) } @@ -570,6 +574,7 @@ fun MultiEventHomeScreen( intentData, null, false, + RememberType.ALWAYS, thisAccount, ) } diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/RememberMyChoice.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/RememberMyChoice.kt index a483394f..a83777dc 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/RememberMyChoice.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/RememberMyChoice.kt @@ -1,18 +1,17 @@ package com.greenart7c3.nostrsigner.ui.components -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Switch -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp +import androidx.compose.ui.text.style.TextOverflow import com.greenart7c3.nostrsigner.R +import com.greenart7c3.nostrsigner.ui.RememberType +import com.greenart7c3.nostrsigner.ui.SettingsRow +import kotlinx.collections.immutable.persistentListOf @Composable fun RememberMyChoice( @@ -20,39 +19,41 @@ fun RememberMyChoice( remember: Boolean, packageName: String?, alwaysShow: Boolean = false, - onAccept: () -> Unit, - onReject: () -> Unit, - onChanged: () -> Unit, + onAccept: (RememberType) -> Unit, + onReject: (RememberType) -> Unit, + onChanged: (RememberType) -> Unit, ) { + val items = + persistentListOf( + TitleExplainer(stringResource(RememberType.NEVER.resourceId)), + TitleExplainer(stringResource(RememberType.ONE_MINUTE.resourceId)), + TitleExplainer(stringResource(RememberType.FIVE_MINUTES.resourceId)), + TitleExplainer(stringResource(RememberType.TEN_MINUTES.resourceId)), + TitleExplainer(stringResource(RememberType.ALWAYS.resourceId)), + ) + var index by remember { + mutableIntStateOf(0) + } if (shouldRunAcceptOrReject != null) { LaunchedEffect(Unit) { if (shouldRunAcceptOrReject) { - onAccept() + onAccept(RememberType.entries[index]) } else { - onReject() + onReject(RememberType.entries[index]) } } } if (packageName != null || alwaysShow) { - Row( - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .padding(vertical = 8.dp) - .clickable { - onChanged() - }, + SettingsRow( + R.string.automatically_sign_this_for, + null, + items, + index, + maxLines = Int.MAX_VALUE, + overflow = TextOverflow.Clip, ) { - Text( - modifier = Modifier.weight(1f), - text = stringResource(R.string.remember_my_choice_and_don_t_ask_again), - ) - Switch( - checked = remember, - onCheckedChange = { - onChanged() - }, - ) + index = it + onChanged(RememberType.entries[it]) } } } diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/SeedWordsPage.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/SeedWordsPage.kt index dad3920c..28d1e902 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/SeedWordsPage.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/SeedWordsPage.kt @@ -33,7 +33,7 @@ import kotlinx.coroutines.launch fun SeedWordsPage( seedWords: Set, showNextButton: Boolean = true, - onNextPage: () -> Unit, + onNextPage: () -> Unit = {}, ) { val clipboardManager = LocalClipboard.current val scope = rememberCoroutineScope() diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/SignMessage.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/SignMessage.kt index 13c106ac..65047036 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/SignMessage.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/SignMessage.kt @@ -18,6 +18,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier @@ -36,6 +37,7 @@ import androidx.compose.ui.unit.sp import com.greenart7c3.nostrsigner.R import com.greenart7c3.nostrsigner.models.Account import com.greenart7c3.nostrsigner.models.SignerType +import com.greenart7c3.nostrsigner.ui.RememberType import com.greenart7c3.nostrsigner.ui.verticalScrollbar import kotlinx.coroutines.launch @@ -50,8 +52,8 @@ fun SignMessage( applicationName: String?, appName: String, type: SignerType, - onAccept: () -> Unit, - onReject: () -> Unit, + onAccept: (RememberType) -> Unit, + onReject: (RememberType) -> Unit, ) { var showMore by androidx.compose.runtime.remember { mutableStateOf(false) @@ -60,6 +62,9 @@ fun SignMessage( val coroutineScope = rememberCoroutineScope() val context = LocalContext.current val scrollState = rememberScrollState() + var rememberType by remember { + mutableStateOf(RememberType.NEVER) + } Column( Modifier @@ -158,12 +163,17 @@ fun SignMessage( onAccept, onReject, ) { - remember.value = !remember.value + remember.value = it != RememberType.NEVER + rememberType = it } AcceptRejectButtons( - onAccept, - onReject, + onAccept = { + onAccept(rememberType) + }, + onReject = { + onReject(rememberType) + }, ) } } diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/SingleEventHomeScreen.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/SingleEventHomeScreen.kt index 1e9aea18..63059629 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/SingleEventHomeScreen.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/SingleEventHomeScreen.kt @@ -1,5 +1,6 @@ package com.greenart7c3.nostrsigner.ui.components +import android.util.Log import android.widget.Toast import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -36,6 +37,7 @@ import com.greenart7c3.nostrsigner.service.AmberUtils import com.greenart7c3.nostrsigner.service.getAppCompatActivity import com.greenart7c3.nostrsigner.service.toShortenHex import com.greenart7c3.nostrsigner.ui.IntentResultType +import com.greenart7c3.nostrsigner.ui.RememberType import com.greenart7c3.nostrsigner.ui.sendResult import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip19Bech32.bech32.bechToBytes @@ -96,7 +98,7 @@ fun SingleEventHomeScreen( } LoginWithPubKey( - applicationEntity?.application?.closeApplication ?: (intentData.bunkerRequest?.closeApplication == true), + applicationEntity?.application?.closeApplication ?: (intentData.bunkerRequest?.closeApplication != false), paddingValues, remember, intentData.bunkerRequest != null && intentData.type == SignerType.GET_PUBLIC_KEY, @@ -105,7 +107,7 @@ fun SingleEventHomeScreen( appName, applicationName, intentData.permissions, - { permissions, signPolicy, closeApplication -> + { permissions, signPolicy, closeApplication, rememberType -> val sig = if (intentData.type == SignerType.CONNECT) { intentData.bunkerRequest!!.nostrConnectSecret.ifBlank { "ack" } @@ -134,6 +136,7 @@ fun SingleEventHomeScreen( signPolicy = signPolicy, onRemoveIntentData = onRemoveIntentData, shouldCloseApplication = closeApplication, + rememberType = rememberType, ) return@LoginWithPubKey @@ -161,9 +164,9 @@ fun SingleEventHomeScreen( ) } } else { - onRemoveIntentData(listOf(intentData), IntentResultType.REMOVE) context.getAppCompatActivity()?.intent = null context.getAppCompatActivity()?.finish() + onRemoveIntentData(listOf(intentData), IntentResultType.REMOVE) onLoading(false) } }, @@ -186,11 +189,24 @@ fun SingleEventHomeScreen( } else { packageName } + val acceptUntil = permission?.acceptUntil ?: 0 + val rejectUntil = permission?.rejectUntil ?: 0 + + val acceptOrReject = if (rejectUntil == 0L && acceptUntil == 0L) { + null + } else if (rejectUntil > TimeUtils.now() && rejectUntil > 0) { + false + } else if (acceptUntil > TimeUtils.now() && acceptUntil > 0) { + true + } else { + null + } + SignMessage( account, paddingValues, intentData.data, - permission?.acceptable, + acceptOrReject, remember, localPackageName, applicationName, @@ -213,6 +229,7 @@ fun SingleEventHomeScreen( null, onLoading, onRemoveIntentData = onRemoveIntentData, + rememberType = it, ) } }, @@ -246,13 +263,14 @@ fun SingleEventHomeScreen( permissions = mutableListOf(), ) - if (remember.value) { + if (it != RememberType.NEVER) { AmberUtils.acceptOrRejectPermission( application, key, intentData, null, false, + it, account, ) } @@ -288,11 +306,11 @@ fun SingleEventHomeScreen( onRemoveIntentData = onRemoveIntentData, ) } else { - onRemoveIntentData(listOf(intentData), IntentResultType.REMOVE) context.getAppCompatActivity()?.intent = null if (application.application.closeApplication) { context.getAppCompatActivity()?.finish() } + onRemoveIntentData(listOf(intentData), IntentResultType.REMOVE) onLoading(false) } } @@ -328,12 +346,26 @@ fun SingleEventHomeScreen( } else { packageName } + + val acceptUntil = permission?.acceptUntil ?: 0 + val rejectUntil = permission?.rejectUntil ?: 0 + + val acceptOrReject = if (rejectUntil == 0L && acceptUntil == 0L) { + null + } else if (rejectUntil > TimeUtils.now() && rejectUntil > 0) { + false + } else if (acceptUntil > TimeUtils.now() && acceptUntil > 0) { + true + } else { + null + } + EncryptDecryptData( account, paddingValues, intentData.data, intentData.encryptedData ?: "", - permission?.acceptable, + acceptOrReject, remember, localPackageName, applicationName, @@ -360,6 +392,7 @@ fun SingleEventHomeScreen( null, onRemoveIntentData = onRemoveIntentData, onLoading = onLoading, + rememberType = it, ) }, { @@ -389,13 +422,14 @@ fun SingleEventHomeScreen( ), permissions = mutableListOf(), ) - if (remember.value) { + if (it != RememberType.NEVER) { AmberUtils.acceptOrRejectPermission( application, key, intentData, null, false, + it, account, ) } @@ -431,11 +465,11 @@ fun SingleEventHomeScreen( onLoading, ) } else { - onRemoveIntentData(listOf(intentData), IntentResultType.REMOVE) context.getAppCompatActivity()?.intent = null if (application.application.closeApplication) { context.getAppCompatActivity()?.finish() } + onRemoveIntentData(listOf(intentData), IntentResultType.REMOVE) onLoading(false) } } @@ -480,10 +514,24 @@ fun SingleEventHomeScreen( } else { packageName } + + val acceptUntil = permission?.acceptUntil ?: 0 + val rejectUntil = permission?.rejectUntil ?: 0 + + val acceptOrReject = if (rejectUntil == 0L && acceptUntil == 0L) { + null + } else if (rejectUntil > TimeUtils.now() && rejectUntil > 0) { + false + } else if (acceptUntil > TimeUtils.now() && acceptUntil > 0) { + true + } else { + null + } + EventData( account, paddingValues, - permission?.acceptable, + acceptOrReject, remember, localPackageName, appName, @@ -530,6 +578,7 @@ fun SingleEventHomeScreen( signPolicy = null, appName = null, permissions = null, + rememberType = it, ) }, { @@ -568,13 +617,14 @@ fun SingleEventHomeScreen( ) } - if (remember.value) { + if (it != RememberType.NEVER) { AmberUtils.acceptOrRejectPermission( application, key, intentData, event.kind, false, + it, account, ) } @@ -604,11 +654,14 @@ fun SingleEventHomeScreen( onRemoveIntentData = onRemoveIntentData, ) } else { - onRemoveIntentData(listOf(intentData), IntentResultType.REMOVE) - context.getAppCompatActivity()?.intent = null + val activity = context.getAppCompatActivity() + Log.d("activity", "is activity null ${activity == null}") + activity?.intent = null + Log.d("activity", "Shold close app ${application.application.closeApplication}") if (application.application.closeApplication) { - context.getAppCompatActivity()?.finish() + activity?.finish() } + onRemoveIntentData(listOf(intentData), IntentResultType.REMOVE) onLoading(false) } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a8802705..33121b2e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -522,4 +522,6 @@ Starter packs Media starter packs Media follows + Automatically sign this for + Always