mirror of
https://github.com/greenart7c3/Amber.git
synced 2026-10-06 11:28:22 +00:00
Ask the user to configure connection type if not configured
This commit is contained in:
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user