From f36e64a8e81f8ebea44fa296a1d158873045d40e Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Wed, 10 Apr 2024 10:31:40 -0300 Subject: [PATCH] only ask for notifications after login --- .../1.json | 178 ++++++++++++++++++ .../greenart7c3/nostrsigner/MainActivity.kt | 93 --------- .../greenart7c3/nostrsigner/ui/MainScreen.kt | 99 ++++++++++ 3 files changed, 277 insertions(+), 93 deletions(-) create mode 100644 app/schemas/com.greenart7c3.nostrsigner.database.AppDatabase/1.json diff --git a/app/schemas/com.greenart7c3.nostrsigner.database.AppDatabase/1.json b/app/schemas/com.greenart7c3.nostrsigner.database.AppDatabase/1.json new file mode 100644 index 00000000..d9cc6717 --- /dev/null +++ b/app/schemas/com.greenart7c3.nostrsigner.database.AppDatabase/1.json @@ -0,0 +1,178 @@ +{ + "formatVersion": 1, + "database": { + "version": 1, + "identityHash": "5651f3201d3521ce45fda80b053e6722", + "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, 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 + } + ], + "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`)" + } + ], + "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 )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "pkKey", + "columnName": "pkKey", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "kind", + "columnName": "kind", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "acceptable", + "columnName": "acceptable", + "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" + ] + } + ] + } + ], + "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, '5651f3201d3521ce45fda80b053e6722')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/MainActivity.kt b/app/src/main/java/com/greenart7c3/nostrsigner/MainActivity.kt index cde49822..daa9df67 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/MainActivity.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/MainActivity.kt @@ -1,32 +1,20 @@ package com.greenart7c3.nostrsigner import android.content.Intent -import android.content.pm.PackageManager -import android.os.Build import android.os.Bundle import android.util.Log import androidx.activity.compose.setContent -import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Button import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.core.content.ContextCompat import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.view.WindowCompat import androidx.lifecycle.viewmodel.compose.viewModel import com.greenart7c3.nostrsigner.database.AppDatabase import com.greenart7c3.nostrsigner.models.IntentData import com.greenart7c3.nostrsigner.service.IntentUtils -import com.greenart7c3.nostrsigner.service.PushNotificationUtils import com.greenart7c3.nostrsigner.ui.AccountScreen import com.greenart7c3.nostrsigner.ui.AccountStateViewModel import com.greenart7c3.nostrsigner.ui.theme.NostrSignerTheme @@ -38,46 +26,6 @@ import kotlinx.coroutines.withContext fun Intent.isLaunchFromHistory(): Boolean = this.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY == Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY class MainActivity : AppCompatActivity() { - private val requestPermissionLauncher = registerForActivityResult( - ActivityResultContracts.RequestPermission() - ) { isGranted: Boolean -> - if (isGranted) { - initNotifications() - } else { - if (LocalPreferences.shouldShowRationale() == null) { - LocalPreferences.updateShoulShowRationale(true) - } - } - } - - private fun initNotifications() { - runBlocking { - PushNotificationUtils.init(LocalPreferences.allSavedAccounts()) - } - } - - private fun askNotificationPermission(onShouldShowRequestPermissionRationale: () -> Unit) { - // This is only necessary for API level >= 33 (TIRAMISU) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - if (ContextCompat.checkSelfPermission(this, "android.permission.POST_NOTIFICATIONS") != PackageManager.PERMISSION_GRANTED - ) { - val shouldShowRationale = LocalPreferences.shouldShowRationale() - if (shouldShowRationale == null) { - requestPermissionLauncher.launch("android.permission.POST_NOTIFICATIONS") - return - } - - if (!shouldShowRationale) { - return - } - - onShouldShowRequestPermissionRationale() - } - } else { - requestPermissionLauncher.launch("android.permission.POST_NOTIFICATIONS") - } - } - private val intents = MutableStateFlow>(listOf()) override fun onCreate(savedInstanceState: Bundle?) { @@ -85,14 +33,7 @@ class MainActivity : AppCompatActivity() { WindowCompat.setDecorFitsSystemWindows(window, false) installSplashScreen() - initNotifications() - setContent { - var showDialog by remember { mutableStateOf(false) } - askNotificationPermission { - showDialog = true - } - if (intent.isLaunchFromHistory()) { Log.d("isLaunchFromHistory", "Cleared intent history") intent = Intent() @@ -113,40 +54,6 @@ class MainActivity : AppCompatActivity() { } NostrSignerTheme { - if (showDialog) { - AlertDialog( - onDismissRequest = { - showDialog = false - }, - title = { - Text(text = "Permission Needed") - }, - text = { - Text(text = "Notifications are needed to use Amber as a nsec bunker.") - }, - confirmButton = { - Button( - onClick = { - showDialog = false - requestPermissionLauncher.launch("android.permission.POST_NOTIFICATIONS") - } - ) { - Text(text = "Allow") - } - }, - dismissButton = { - Button( - onClick = { - showDialog = false - LocalPreferences.updateShoulShowRationale(false) - } - ) { - Text(text = "Deny") - } - } - ) - } - Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background 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 a986d1d4..af9eb0ea 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/MainScreen.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/MainScreen.kt @@ -3,8 +3,13 @@ package com.greenart7c3.nostrsigner.ui import android.app.Activity.RESULT_OK import android.content.Context import android.content.Intent +import android.content.pm.PackageManager import android.net.Uri +import android.os.Build import android.widget.Toast +import androidx.activity.compose.ManagedActivityResultLauncher +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut @@ -25,6 +30,8 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.ExpandMore +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.ExperimentalMaterial3Api @@ -44,6 +51,7 @@ import androidx.compose.material3.TooltipDefaults import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.material3.rememberTooltipState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -64,6 +72,7 @@ import androidx.compose.ui.text.toUpperCase import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog +import androidx.core.content.ContextCompat import androidx.navigation.NavType import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable @@ -443,6 +452,39 @@ fun EditAppDialog(permission: ApplicationEntity, onClose: () -> Unit, onPost: (S } } +private fun askNotificationPermission( + context: Context, + requestPermissionLauncher: ManagedActivityResultLauncher, + onShouldShowRequestPermissionRationale: () -> Unit +) { + if (ContextCompat.checkSelfPermission(context, "android.permission.POST_NOTIFICATIONS") == PackageManager.PERMISSION_GRANTED) { + initNotifications() + return + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + val shouldShowRationale = LocalPreferences.shouldShowRationale() + if (shouldShowRationale == null) { + requestPermissionLauncher.launch("android.permission.POST_NOTIFICATIONS") + return + } + + if (!shouldShowRationale) { + return + } + + onShouldShowRequestPermissionRationale() + } else { + requestPermissionLauncher.launch("android.permission.POST_NOTIFICATIONS") + } +} + +private fun initNotifications() { + runBlocking { + PushNotificationUtils.init(LocalPreferences.allSavedAccounts()) + } +} + @OptIn(ExperimentalMaterial3Api::class) @Composable fun MainScreen( @@ -466,6 +508,63 @@ fun MainScreen( val interactionSource = remember { MutableInteractionSource() } val clipboardManager = LocalClipboardManager.current + val requestPermissionLauncher = rememberLauncherForActivityResult( + ActivityResultContracts.RequestPermission() + ) { isGranted: Boolean -> + if (isGranted) { + initNotifications() + } else { + if (LocalPreferences.shouldShowRationale() == null) { + LocalPreferences.updateShoulShowRationale(true) + } + } + } + val context = LocalContext.current + var showDialog by remember { mutableStateOf(false) } + + LaunchedEffect(Unit) { + askNotificationPermission( + context, + requestPermissionLauncher + ) { + showDialog = true + } + } + + if (showDialog) { + AlertDialog( + onDismissRequest = { + showDialog = false + }, + title = { + Text(text = "Permission Needed") + }, + text = { + Text(text = "Notifications are needed to use Amber as a nsec bunker.") + }, + confirmButton = { + Button( + onClick = { + showDialog = false + requestPermissionLauncher.launch("android.permission.POST_NOTIFICATIONS") + } + ) { + Text(text = "Allow") + } + }, + dismissButton = { + Button( + onClick = { + showDialog = false + LocalPreferences.updateShoulShowRationale(false) + } + ) { + Text(text = "Deny") + } + } + ) + } + Scaffold( floatingActionButton = { if (navBackStackEntry?.destination?.route == "Permissions") {