Ask the user to configure connection type if not configured

This commit is contained in:
greenart7c3
2024-09-11 09:05:58 -03:00
parent 46a6a7c46f
commit 1ff3d4e67d
8 changed files with 143 additions and 72 deletions
@@ -118,6 +118,12 @@ object LocalPreferences {
}.apply()
}
suspend fun isNotificationTypeConfigured(): Boolean {
val context = NostrSigner.getInstance()
val prefs = encryptedPreferences(context)
return prefs.contains(PrefKeys.NOTIFICATION_TYPE)
}
suspend fun loadSettingsFromEncryptedStorage(): AmberSettings {
val context = NostrSigner.getInstance()
@@ -130,7 +136,7 @@ object LocalPreferences {
} ?: listOf(RelaySetupInfo("wss://relay.nsec.app", read = true, write = true, feedTypes = COMMON_FEED_TYPES)),
lastBiometricsTime = getLong(PrefKeys.LAST_BIOMETRICS_TIME, 0),
useAuth = getBoolean(PrefKeys.USE_AUTH, false),
notificationType = parseNotificationType(getInt(PrefKeys.NOTIFICATION_TYPE, 0)),
notificationType = parseNotificationType(getInt(PrefKeys.NOTIFICATION_TYPE, 1)),
biometricsTimeType = parseBiometricsTimeType(getInt(PrefKeys.BIOMETRICS_TYPE, 0)),
)
}
@@ -19,10 +19,15 @@ import com.vitorpamplona.ammolite.relays.RelayPool
import com.vitorpamplona.ammolite.relays.RelaySetupInfo
import com.vitorpamplona.ammolite.service.HttpClientManager
import java.util.concurrent.ConcurrentHashMap
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
class NostrSigner : Application() {
val applicationIOScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
private var databases = ConcurrentHashMap<String, AppDatabase>()
lateinit var settings: AmberSettings
@@ -163,6 +168,11 @@ class NostrSigner : Application() {
}
}
override fun onTerminate() {
super.onTerminate()
applicationIOScope.cancel()
}
companion object {
@Volatile
private var instance: NostrSigner? = null
@@ -11,6 +11,6 @@ data class AmberSettings(
val defaultRelays: List<RelaySetupInfo> = listOf(RelaySetupInfo("wss://relay.nsec.app", read = true, write = true, feedTypes = COMMON_FEED_TYPES)),
val lastBiometricsTime: Long = 0,
val useAuth: Boolean = false,
val notificationType: NotificationType = NotificationType.PUSH,
val notificationType: NotificationType = NotificationType.DIRECT,
val biometricsTimeType: BiometricsTimeType = BiometricsTimeType.EVERY_TIME,
)
@@ -9,6 +9,8 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.icons.Icons
@@ -18,6 +20,7 @@ import androidx.compose.material3.Button
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@@ -26,7 +29,6 @@ import androidx.compose.runtime.collectAsState
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.Alignment
import androidx.compose.ui.Modifier
@@ -74,71 +76,94 @@ fun AccountScreen(
MainLoginPage(accountStateViewModel)
}
is AccountState.LoggedIn -> {
var intentData by remember {
mutableStateOf<IntentData?>(null)
var isNotificationsConfigured by remember {
mutableStateOf(false)
}
LaunchedEffect(intent, intents) {
IntentUtils.getIntentData(context, intent, packageName, intent.getStringExtra("route"), state.account) {
intentData = it
LaunchedEffect(Unit) {
launch(Dispatchers.IO) {
isNotificationsConfigured = LocalPreferences.isNotificationTypeConfigured()
}
val data =
intents.firstOrNull {
it.currentAccount.isNotBlank()
}
}
data?.bunkerRequest?.let {
if (it.currentAccount.isNotBlank()) {
if (LocalPreferences.currentAccount(context) != it.currentAccount) {
accountStateViewModel.switchUser(it.currentAccount, null)
if (isNotificationsConfigured) {
var intentData by remember {
mutableStateOf<IntentData?>(null)
}
LaunchedEffect(intent, intents) {
IntentUtils.getIntentData(context, intent, packageName, intent.getStringExtra("route"), state.account) {
intentData = it
}
val data =
intents.firstOrNull {
it.currentAccount.isNotBlank()
}
data?.bunkerRequest?.let {
if (it.currentAccount.isNotBlank()) {
if (LocalPreferences.currentAccount(context) != it.currentAccount) {
accountStateViewModel.switchUser(it.currentAccount, null)
}
}
}
}
}
if (intentData != null) {
if (intents.none { item -> item.id == intentData!!.id }) {
val oldIntents = intents.toMutableList()
oldIntents.add(intentData!!)
flow.value = oldIntents
}
}
val newIntents =
intents.ifEmpty {
if (intentData == null) {
listOf()
} else {
listOf(intentData)
}
}.mapNotNull { it }
val database = NostrSigner.getInstance().getDatabase(state.account.keyPair.pubKey.toNpub())
val localRoute = mutableStateOf(newIntents.firstNotNullOfOrNull { it.route } ?: state.route)
val scope = rememberCoroutineScope()
SideEffect {
scope.launch(Dispatchers.IO) {
PushNotificationUtils.accountState = accountStateViewModel
try {
NostrSigner.getInstance().applicationContext.startForegroundService(
Intent(NostrSigner.getInstance().applicationContext, ConnectivityService::class.java),
)
} catch (e: Exception) {
Log.d("NostrSigner", "Failed to start ConnectivityService", e)
}
@Suppress("KotlinConstantConditions")
if (NostrSigner.getInstance().settings.notificationType == NotificationType.DIRECT && BuildConfig.FLAVOR != "offline") {
NostrSigner.getInstance().checkForNewRelays()
NotificationDataSource.start()
delay(5000)
if (intentData != null) {
if (intents.none { item -> item.id == intentData!!.id }) {
val oldIntents = intents.toMutableList()
oldIntents.add(intentData!!)
flow.value = oldIntents
}
}
val newIntents =
intents.ifEmpty {
if (intentData == null) {
listOf()
} else {
listOf(intentData)
}
}.mapNotNull { it }
val database = NostrSigner.getInstance().getDatabase(state.account.keyPair.pubKey.toNpub())
val localRoute = mutableStateOf(newIntents.firstNotNullOfOrNull { it.route } ?: state.route)
SideEffect {
NostrSigner.getInstance().applicationIOScope.launch(Dispatchers.IO) {
PushNotificationUtils.accountState = accountStateViewModel
try {
NostrSigner.getInstance().applicationContext.startForegroundService(
Intent(NostrSigner.getInstance().applicationContext, ConnectivityService::class.java),
)
} catch (e: Exception) {
Log.d("NostrSigner", "Failed to start ConnectivityService", e)
}
@Suppress("KotlinConstantConditions")
if (NostrSigner.getInstance().settings.notificationType == NotificationType.DIRECT && BuildConfig.FLAVOR != "offline") {
NostrSigner.getInstance().checkForNewRelays()
NotificationDataSource.start()
delay(5000)
}
}
}
AmberListenerSingleton.accountStateViewModel = accountStateViewModel
DisplayErrorMessages(accountStateViewModel)
MainScreen(state.account, accountStateViewModel, newIntents, packageName, appName, localRoute, database)
} else {
AmberListenerSingleton.accountStateViewModel = accountStateViewModel
DisplayErrorMessages(accountStateViewModel)
Scaffold { innerPadding ->
NotificationTypeScreen(
Modifier
.fillMaxSize()
.padding(innerPadding),
onDone = {
isNotificationsConfigured = true
},
)
}
}
AmberListenerSingleton.accountStateViewModel = accountStateViewModel
DisplayErrorMessages(accountStateViewModel)
MainScreen(state.account, accountStateViewModel, newIntents, packageName, appName, localRoute, database)
}
}
}
@@ -109,7 +109,7 @@ fun EditPermission(
}
LaunchedEffect(Unit) {
scope.launch(Dispatchers.IO) {
launch(Dispatchers.IO) {
permissions.addAll(database.applicationDao().getAllByKey(selectedPackage).sortedBy { "${it.type}-${it.kind}" })
applicationData = database.applicationDao().getByKey(selectedPackage)!!.application
checked = applicationData.useSecret
@@ -524,7 +524,9 @@ private suspend fun askNotificationPermission(
onShouldShowRequestPermissionRationale: () -> Unit,
) {
if (ContextCompat.checkSelfPermission(context, "android.permission.POST_NOTIFICATIONS") == PackageManager.PERMISSION_GRANTED) {
initNotifications(context)
initNotifications(
context = context,
)
return
}
@@ -572,7 +574,9 @@ fun MainScreen(
) { isGranted: Boolean ->
if (isGranted) {
scope.launch(Dispatchers.IO) {
initNotifications(context)
initNotifications(
context = context,
)
}
} else {
if (LocalPreferences.shouldShowRationale(context) == null) {
@@ -587,11 +591,12 @@ fun MainScreen(
LaunchedEffect(Unit) {
launch(Dispatchers.IO) {
askNotificationPermission(
context,
requestPermissionLauncher,
) {
showDialog = true
}
context = context,
requestPermissionLauncher = requestPermissionLauncher,
onShouldShowRequestPermissionRationale = {
showDialog = true
},
)
}
}
}
@@ -821,7 +826,9 @@ fun MainScreen(
Modifier
.fillMaxSize()
.padding(padding),
navController = navController,
onDone = {
navController.navigateUp()
},
)
}
},
@@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
@@ -20,11 +21,11 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.greenart7c3.nostrsigner.BuildConfig
import com.greenart7c3.nostrsigner.LocalPreferences
import com.greenart7c3.nostrsigner.NostrSigner
import com.greenart7c3.nostrsigner.R
import com.greenart7c3.nostrsigner.relays.AmberListenerSingleton
import com.greenart7c3.nostrsigner.service.ConnectivityService
import com.greenart7c3.nostrsigner.service.NotificationDataSource
import com.greenart7c3.nostrsigner.service.PushNotificationUtils
@@ -38,17 +39,35 @@ import kotlinx.coroutines.launch
@Composable
fun NotificationTypeScreen(
modifier: Modifier = Modifier,
navController: NavController,
onDone: () -> Unit,
) {
val context = LocalContext.current
LaunchedEffect(Unit) {
launch(Dispatchers.IO) {
if (!LocalPreferences.isNotificationTypeConfigured()) {
AmberListenerSingleton.accountStateViewModel?.toast(
context.getString(R.string.notification_settings),
context.getString(R.string.please_configure_your_notification_settings_before_continuing),
)
}
}
}
val scope = rememberCoroutineScope()
var notificationItemsIndex by remember {
mutableIntStateOf(NostrSigner.getInstance().settings.notificationType.screenCode)
}
val notificationItems =
persistentListOf(
TitleExplainer(stringResource(NotificationType.PUSH.resourceId)),
TitleExplainer(stringResource(NotificationType.DIRECT.resourceId)),
TitleExplainer(
stringResource(NotificationType.PUSH.resourceId),
stringResource(R.string.push_notifications_explainer),
),
TitleExplainer(
stringResource(NotificationType.DIRECT.resourceId),
stringResource(R.string.direct_notifications_explainer),
),
)
Surface(
modifier.fillMaxSize(),
@@ -112,7 +131,7 @@ fun NotificationTypeScreen(
),
)
scope.launch(Dispatchers.Main) {
navController.navigateUp()
onDone()
}
}
}
+4
View File
@@ -364,4 +364,8 @@
<string name="event_kind_24242">Blobs stored on mediaservers</string>
<string name="event_kind_30040">Modular Article Header</string>
<string name="event_kind_30041">Modular Article Content</string>
<string name="push_notifications_explainer">Using push notifications is significantly slower and less private</string>
<string name="direct_notifications_explainer">Keep the relays connections open all the time. Using this option is faster and will result in a better experience</string>
<string name="notification_settings">Notification Settings</string>
<string name="please_configure_your_notification_settings_before_continuing">Please configure your notification settings before continuing.</string>
</resources>