linter fix

This commit is contained in:
greenart7c3
2024-05-03 11:46:04 -03:00
parent 698195a93d
commit 1f3e7ae8fe
29 changed files with 59 additions and 439 deletions
@@ -63,6 +63,7 @@ class MainActivity : AppCompatActivity() {
override fun onResume() {
mainViewModel.showBunkerRequests(callingPackage)
@Suppress("KotlinConstantConditions")
if (BuildConfig.FLAVOR != "offline") {
val connectivityManager =
(getSystemService(ConnectivityManager::class.java) as ConnectivityManager)
@@ -90,7 +90,7 @@ object Client : RelayPool.Listener {
}
}
fun isSameRelaySetConfig(newRelayConfig: Array<Relay>?): Boolean {
private fun isSameRelaySetConfig(newRelayConfig: Array<Relay>?): Boolean {
if (relays.size != newRelayConfig?.size) return false
relays.forEach { oldRelayInfo ->
@@ -150,7 +150,7 @@ object Client : RelayPool.Listener {
newSporadicRelay(
relay,
feedTypes,
onConnected = { relay -> relay.send(signedEvent, null) },
onConnected = { mRelay -> mRelay.send(signedEvent, null) },
onDone = onDone,
onLoading = onLoading,
)
@@ -166,7 +166,7 @@ object Client : RelayPool.Listener {
onConnected: (Relay) -> Unit,
onDone: (() -> Unit)?,
) {
val relay = Relay(url, true, true, feedTypes ?: emptySet())
val relay = Relay(url, activeTypes = feedTypes ?: emptySet())
relay.onLoading = onLoading
RelayPool.addRelay(relay)
@@ -290,10 +290,6 @@ object Client : RelayPool.Listener {
return listeners.contains(listener)
}
fun unsubscribe(listener: Listener) {
listeners = listeners.minus(listener)
}
fun allSubscriptions(): Set<String> {
return subscriptions.keys
}
@@ -1,176 +0,0 @@
/**
* Copyright (c) 2024 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.greenart7c3.nostrsigner.relays
object Constants {
val activeTypes = setOf(FeedType.FOLLOWS, FeedType.PRIVATE_DMS)
val activeTypesChats = setOf(FeedType.FOLLOWS, FeedType.PUBLIC_CHATS, FeedType.PRIVATE_DMS)
val activeTypesGlobalChats =
setOf(FeedType.FOLLOWS, FeedType.PUBLIC_CHATS, FeedType.PRIVATE_DMS, FeedType.GLOBAL)
val activeTypesSearch = setOf(FeedType.SEARCH)
fun convertDefaultRelays(): Array<Relay> {
return defaultRelays.map { Relay(it.url, it.read, it.write, it.feedTypes) }.toTypedArray()
}
val defaultRelays =
arrayOf(
// Free relays for only DMs and Follows due to the amount of spam
RelaySetupInfo("wss://relay.damus.io", read = true, write = true, feedTypes = activeTypes),
// Chats
RelaySetupInfo(
"wss://nostr.bitcoiner.social",
read = true,
write = true,
feedTypes = activeTypesChats,
),
RelaySetupInfo(
"wss://relay.nostr.bg",
read = true,
write = true,
feedTypes = activeTypesChats,
),
RelaySetupInfo(
"wss://nostr.oxtr.dev",
read = true,
write = true,
feedTypes = activeTypesChats,
),
RelaySetupInfo(
"wss://nostr-pub.wellorder.net",
read = true,
write = true,
feedTypes = activeTypesChats,
),
RelaySetupInfo("wss://nostr.mom", read = true, write = true, feedTypes = activeTypesGlobalChats),
RelaySetupInfo("wss://nos.lol", read = true, write = true, feedTypes = activeTypesGlobalChats),
// Less Reliable
// NewRelayListViewModel.Relay("wss://nostr.orangepill.dev", read = true, write = true,
// feedTypes = activeTypes),
// NewRelayListViewModel.Relay("wss://nostr.onsats.org", read = true, write = true, feedTypes
// = activeTypes),
// NewRelayListViewModel.Relay("wss://nostr.sandwich.farm", read = true, write = true,
// feedTypes = activeTypes),
// NewRelayListViewModel.Relay("wss://relay.nostr.ch", read = true, write = true, feedTypes =
// activeTypes),
// NewRelayListViewModel.Relay("wss://nostr.zebedee.cloud", read = true, write = true,
// feedTypes = activeTypes),
// NewRelayListViewModel.Relay("wss://nostr.rocks", read = true, write = true, feedTypes =
// activeTypes),
// NewRelayListViewModel.Relay("wss://nostr.fmt.wiz.biz", read = true, write = true, feedTypes
// = activeTypes),
// NewRelayListViewModel.Relay("wss://brb.io", read = true, write = true, feedTypes =
// activeTypes),
// Paid relays
RelaySetupInfo(
"wss://relay.snort.social",
read = true,
write = false,
feedTypes = activeTypesGlobalChats,
),
RelaySetupInfo(
"wss://relay.nostr.com.au",
read = true,
write = false,
feedTypes = activeTypesGlobalChats,
),
RelaySetupInfo(
"wss://eden.nostr.land",
read = true,
write = false,
feedTypes = activeTypesGlobalChats,
),
RelaySetupInfo(
"wss://nostr.milou.lol",
read = true,
write = false,
feedTypes = activeTypesGlobalChats,
),
RelaySetupInfo(
"wss://puravida.nostr.land",
read = true,
write = false,
feedTypes = activeTypesGlobalChats,
),
RelaySetupInfo(
"wss://nostr.wine",
read = true,
write = false,
feedTypes = activeTypesGlobalChats,
),
RelaySetupInfo(
"wss://nostr.inosta.cc",
read = true,
write = false,
feedTypes = activeTypesGlobalChats,
),
RelaySetupInfo(
"wss://atlas.nostr.land",
read = true,
write = false,
feedTypes = activeTypesGlobalChats,
),
RelaySetupInfo(
"wss://relay.orangepill.dev",
read = true,
write = false,
feedTypes = activeTypesGlobalChats,
),
RelaySetupInfo(
"wss://relay.nostrati.com",
read = true,
write = false,
feedTypes = activeTypesGlobalChats,
),
// Supporting NIP-50
RelaySetupInfo(
"wss://relay.nostr.band",
read = true,
write = false,
feedTypes = activeTypesSearch,
),
RelaySetupInfo("wss://nostr.wine", read = true, write = false, feedTypes = activeTypesSearch),
RelaySetupInfo(
"wss://relay.noswhere.com",
read = true,
write = false,
feedTypes = activeTypesSearch,
),
)
val forcedRelayForSearch =
arrayOf(
RelaySetupInfo(
"wss://relay.nostr.band",
read = true,
write = false,
feedTypes = activeTypesSearch,
),
RelaySetupInfo("wss://nostr.wine", read = true, write = false, feedTypes = activeTypesSearch),
RelaySetupInfo(
"wss://relay.noswhere.com",
read = true,
write = false,
feedTypes = activeTypesSearch,
),
)
val forcedRelaysForSearchSet = forcedRelayForSearch.map { it.url }
}
@@ -25,34 +25,3 @@ class EOSETime(var time: Long) {
return time.toString()
}
}
class EOSERelayList(var relayList: Map<String, EOSETime> = emptyMap()) {
fun addOrUpdate(
relayUrl: String,
time: Long,
) {
val eose = relayList[relayUrl]
if (eose == null) {
relayList = relayList + Pair(relayUrl, EOSETime(time))
} else {
eose.time = time
}
}
}
class EOSEFollowList(var followList: Map<String, EOSERelayList> = emptyMap()) {
fun addOrUpdate(
listCode: String,
relayUrl: String,
time: Long,
) {
val relayList = followList[listCode]
if (relayList == null) {
val newList = EOSERelayList()
newList.addOrUpdate(relayUrl, time)
followList = followList + mapOf(listCode to newList)
} else {
relayList.addOrUpdate(relayUrl, time)
}
}
}
@@ -63,7 +63,7 @@ class JsonFilter(
}
}
since?.run {
if (!isEmpty()) {
if (isNotEmpty()) {
if (forRelay != null) {
val relaySince = get(forRelay)
if (relaySince != null) {
@@ -30,8 +30,6 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.launch
/**
@@ -45,9 +43,8 @@ object RelayPool : Relay.Listener {
private var lastStatus = RelayPoolStatus(0, 0)
private val _statusFlow =
MutableSharedFlow<RelayPoolStatus>(1, 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
val statusFlow: SharedFlow<RelayPoolStatus> = _statusFlow.asSharedFlow()
fun availableRelays(): Int {
private fun availableRelays(): Int {
return relays.size
}
@@ -55,7 +52,7 @@ object RelayPool : Relay.Listener {
return relays
}
fun connectedRelays(): Int {
private fun connectedRelays(): Int {
return relays.count { it.isConnected() }
}
@@ -92,10 +89,6 @@ object RelayPool : Relay.Listener {
relays.forEach { it.connectAndSendFiltersIfDisconnected() }
}
fun hasListeners(): Boolean {
return listeners.isNotEmpty()
}
@OptIn(DelicateCoroutinesApi::class)
fun sendToSelectedRelays(
list: List<Relay>,
@@ -107,8 +100,8 @@ object RelayPool : Relay.Listener {
relays.filter { it.url == relay.url }.forEach {
it.onLoading = onLoading
if (!it.isConnected()) {
it.connectAndRun {
it.send(signedEvent, onDone)
it.connectAndRun { relay ->
relay.send(signedEvent, onDone)
GlobalScope.launch(Dispatchers.IO) {
delay(60000)
if (relay.isConnected()) {
@@ -1,60 +0,0 @@
/**
* Copyright (c) 2024 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.greenart7c3.nostrsigner.relays
import android.util.LruCache
import androidx.compose.runtime.Immutable
@Immutable
data class RelaySetupInfo(
val url: String,
val read: Boolean,
val write: Boolean,
val errorCount: Int = 0,
val downloadCountInBytes: Int = 0,
val uploadCountInBytes: Int = 0,
val spamCount: Int = 0,
val feedTypes: Set<FeedType>,
val paidRelay: Boolean = false,
) {
val briefInfo: RelayBriefInfoCache.RelayBriefInfo = RelayBriefInfoCache.RelayBriefInfo(url)
}
object RelayBriefInfoCache {
val cache = LruCache<String, RelayBriefInfo?>(50)
@Immutable
data class RelayBriefInfo(
val url: String,
val displayUrl: String =
url.trim().removePrefix("wss://").removePrefix("ws://").removeSuffix("/").intern(),
val favIcon: String = "https://$displayUrl/favicon.ico".intern(),
)
fun get(url: String): RelayBriefInfo {
val info = cache[url]
if (info != null) return info
val newInfo = RelayBriefInfo(url)
cache.put(url, newInfo)
return newInfo
}
}
@@ -41,7 +41,7 @@ data class Subscription(
return Event.mapper.writeValueAsString(toJsonObject())
}
fun toJsonObject(): JsonNode {
private fun toJsonObject(): JsonNode {
val factory = Event.mapper.nodeFactory
return factory.objectNode().apply {
@@ -36,40 +36,40 @@ class TypedFilter(
val factory = Event.mapper.nodeFactory
return factory.objectNode().apply {
put("types", typesToJson(types))
put("filter", filterToJson(filter))
putIfAbsent("types", typesToJson(types))
putIfAbsent("filter", filterToJson(filter))
}
}
fun typesToJson(types: Set<FeedType>): ArrayNode {
private fun typesToJson(types: Set<FeedType>): ArrayNode {
val factory = Event.mapper.nodeFactory
return factory.arrayNode(types.size).apply { types.forEach { add(it.name.lowercase()) } }
}
fun filterToJson(filter: JsonFilter): JsonNode {
private fun filterToJson(filter: JsonFilter): JsonNode {
val factory = Event.mapper.nodeFactory
return factory.objectNode().apply {
filter.ids?.run {
put(
putIfAbsent(
"ids",
factory.arrayNode(filter.ids.size).apply { filter.ids.forEach { add(it) } },
)
}
filter.authors?.run {
put(
putIfAbsent(
"authors",
factory.arrayNode(filter.authors.size).apply { filter.authors.forEach { add(it) } },
)
}
filter.kinds?.run {
put(
putIfAbsent(
"kinds",
factory.arrayNode(filter.kinds.size).apply { filter.kinds.forEach { add(it) } },
)
}
filter.tags?.run {
entries.forEach { kv ->
put(
putIfAbsent(
"#${kv.key}",
factory.arrayNode(kv.value.size).apply { kv.value.forEach { add(it) } },
)
@@ -139,7 +139,7 @@ object AmberUtils {
}
}
suspend fun acceptOrRejectPermission(
fun acceptOrRejectPermission(
key: String,
intentData: IntentData,
kind: Int?,
@@ -21,7 +21,6 @@
package com.greenart7c3.nostrsigner.service
import androidx.compose.runtime.Stable
import com.greenart7c3.nostrsigner.checkNotInMainThread
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -31,14 +30,13 @@ import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.atomic.AtomicBoolean
/** This class is designed to have a waiting time between two calls of invalidate */
@Stable
class BundledUpdate(
val delay: Long,
val dispatcher: CoroutineDispatcher = Dispatchers.Default,
private val delay: Long,
private val dispatcher: CoroutineDispatcher = Dispatchers.Default,
) {
val scope = CoroutineScope(dispatcher + SupervisorJob())
@@ -76,51 +74,3 @@ class BundledUpdate(
scope.cancel()
}
}
/** This class is designed to have a waiting time between two calls of invalidate */
@Stable
class BundledInsert<T>(
val delay: Long,
val dispatcher: CoroutineDispatcher = Dispatchers.Default,
) {
val scope = CoroutineScope(dispatcher + SupervisorJob())
private var onlyOneInBlock = AtomicBoolean()
private var queue = LinkedBlockingQueue<T>()
fun invalidateList(
newObject: T,
onUpdate: suspend (Set<T>) -> Unit,
) {
checkNotInMainThread()
queue.put(newObject)
if (onlyOneInBlock.getAndSet(true)) {
return
}
scope.launch(dispatcher) {
try {
val mySet = mutableSetOf<T>()
queue.drainTo(mySet)
if (mySet.isNotEmpty()) {
onUpdate(mySet)
}
delay(delay)
val mySet2 = mutableSetOf<T>()
queue.drainTo(mySet2)
if (mySet2.isNotEmpty()) {
onUpdate(mySet2)
}
} finally {
withContext(NonCancellable) { onlyOneInBlock.set(false) }
}
}
}
fun cancel() {
scope.cancel()
}
}
@@ -6,7 +6,6 @@ import android.app.NotificationManager
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.util.Log
import androidx.core.app.NotificationCompat
@@ -19,16 +18,11 @@ import java.util.TimerTask
class ConnectivityService : Service() {
private val timer = Timer()
private val binder = MyBinder()
override fun onBind(intent: Intent): IBinder {
return null!!
}
inner class MyBinder : Binder() {
fun getService(): ConnectivityService = this@ConnectivityService
}
private fun createNotification(): Notification {
val channelId = "ServiceChannel"
val channel = NotificationChannel(channelId, "Checking Connectivity", NotificationManager.IMPORTANCE_DEFAULT)
@@ -80,7 +80,7 @@ class EventNotificationConsumer(private val applicationContext: Context) {
}
}
private suspend fun consumeIfMatchesAccount(
private fun consumeIfMatchesAccount(
pushWrappedEvent: GiftWrapEvent,
account: Account,
) {
@@ -36,7 +36,7 @@ object HttpClientManager {
val DEFAULT_TIMEOUT_ON_WIFI: Duration = Duration.ofSeconds(10L)
val DEFAULT_TIMEOUT_ON_MOBILE: Duration = Duration.ofSeconds(30L)
var proxyChangeListeners = ArrayList<() -> Unit>()
private var proxyChangeListeners = ArrayList<() -> Unit>()
private var defaultTimeout = DEFAULT_TIMEOUT_ON_WIFI
private var defaultHttpClient: OkHttpClient? = null
private var defaultHttpClientWithoutProxy: OkHttpClient? = null
@@ -41,7 +41,7 @@ import java.net.URLDecoder
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap
data class BunkerMetada(
data class BunkerMetadata(
val name: String,
val url: String,
val description: String,
@@ -258,7 +258,7 @@ object IntentUtils {
database.applicationDao().getAllApplications().forEach {
it.application.relays.forEach { url ->
if (url.isNotBlank()) {
if (!savedRelays.any { it.url == url }) {
if (!savedRelays.any { relay -> relay.url == url }) {
savedRelays.add(Relay(url))
}
}
@@ -569,12 +569,12 @@ object IntentUtils {
}
}
private fun metaDataFromJson(json: String): BunkerMetada {
private fun metaDataFromJson(json: String): BunkerMetadata {
val objectMapper =
jacksonObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
return objectMapper.readValue(json, BunkerMetada::class.java)
return objectMapper.readValue(json, BunkerMetadata::class.java)
}
private fun getIntentFromNostrConnect(
@@ -639,7 +639,7 @@ object IntentUtils {
}
}
suspend fun getIntentData(
fun getIntentData(
intent: Intent,
packageName: String?,
route: String?,
@@ -28,11 +28,8 @@ import com.greenart7c3.nostrsigner.relays.Subscription
import com.vitorpamplona.quartz.events.Event
import com.vitorpamplona.quartz.utils.TimeUtils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import java.util.UUID
import java.util.concurrent.atomic.AtomicBoolean
@@ -45,19 +42,10 @@ abstract class NostrDataSource(val debugName: String) {
data class Counter(var counter: Int)
private var eventCounter = mapOf<String, Counter>()
var changingFilters = AtomicBoolean()
private var changingFilters = AtomicBoolean()
private var active: Boolean = false
fun printCounter() {
eventCounter.forEach {
Log.d(
"STATE DUMP ${this.javaClass.simpleName}",
"Received Events ${it.key}: ${it.value.counter}",
)
}
}
fun isActive(): Boolean {
return active
}
@@ -72,7 +60,7 @@ abstract class NostrDataSource(val debugName: String) {
) {
if (subscriptions.containsKey(subscriptionId)) {
val key = "$debugName $subscriptionId ${event.kind}"
val keyValue = eventCounter.get(key)
val keyValue = eventCounter[key]
if (keyValue != null) {
keyValue.counter++
} else {
@@ -148,34 +136,12 @@ abstract class NostrDataSource(val debugName: String) {
Client.subscribe(clientListener)
}
fun destroy() {
// makes sure to run
Log.d(this.javaClass.simpleName, "${this.javaClass.simpleName} Unsubscribe")
stop()
Client.unsubscribe(clientListener)
scope.cancel()
bundler.cancel()
}
open fun start() {
println("DataSource: ${this.javaClass.simpleName} Start")
active = true
resetFilters()
}
@OptIn(DelicateCoroutinesApi::class)
open fun stop() {
active = false
println("DataSource: ${this.javaClass.simpleName} Stop")
GlobalScope.launch(Dispatchers.IO) {
subscriptions.values.forEach { subscription ->
Client.close(subscription.id)
subscription.typedFilters = null
}
}
}
open fun stopSync() {
active = false
println("DataSource: ${this.javaClass.simpleName} Stop")
@@ -192,11 +158,6 @@ abstract class NostrDataSource(val debugName: String) {
return newSubscription
}
fun dismissChannel(subscription: Subscription) {
Client.close(subscription.id)
subscriptions = subscriptions.minus(subscription.id)
}
// Refreshes observers in batches.
private val bundler = BundledUpdate(300, Dispatchers.IO)
@@ -212,11 +173,11 @@ abstract class NostrDataSource(val debugName: String) {
}
}
fun resetFilters() {
private fun resetFilters() {
scope.launch(Dispatchers.IO) { resetFiltersSuspend() }
}
fun resetFiltersSuspend() {
private fun resetFiltersSuspend() {
println("DataSource: ${this.javaClass.simpleName} resetFiltersSuspend $active")
checkNotInMainThread()
@@ -37,7 +37,7 @@ import com.vitorpamplona.quartz.events.Event
object NotificationDataSource : NostrDataSource("AccountData") {
private val eventNotificationConsumer = EventNotificationConsumer(NostrSigner.instance)
fun createNotificationsFilter(): TypedFilter {
private fun createNotificationsFilter(): TypedFilter {
var since = TimeUtils.now()
val accounts = LocalPreferences.allSavedAccounts()
accounts.forEach {
@@ -20,31 +20,20 @@
*/
package com.greenart7c3.nostrsigner.service
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.net.Uri
object PackageUtils {
@SuppressLint("QueryPermissionsNeeded")
private fun isPackageInstalled(
context: Context,
target: String,
): Boolean {
return context.packageManager.getInstalledApplications(0).find { info ->
info.packageName == target
info.packageName == "org.torproject.android"
} != null
}
fun isOrbotInstalled(context: Context): Boolean {
return isPackageInstalled(context, "org.torproject.android")
}
fun isExternalSignerInstalled(context: Context): Boolean {
val intent =
Intent().apply {
action = Intent.ACTION_VIEW
data = Uri.parse("nostrsigner:")
}
val infos = context.packageManager.queryIntentActivities(intent, 0)
return infos.size > 0
return isPackageInstalled(context)
}
}
@@ -54,12 +54,12 @@ class RegisterAccounts(
next.first.createAuthEvent(next.second, notificationToken) {
output.add(it)
recursiveAuthCreation(notificationToken, remainingTos.filter { next != it }, output, onReady)
recursiveAuthCreation(notificationToken, remainingTos.filter { remainingTo -> next != remainingTo }, output, onReady)
}
}
// creates proof that it controls all accounts
private suspend fun signEventsToProveControlOfAccounts(
private fun signEventsToProveControlOfAccounts(
accounts: List<AccountInfo>,
notificationToken: String,
onReady: (List<RelayAuthEvent>) -> Unit,
@@ -99,7 +99,7 @@ fun AccountScreen(
db.applicationDao().getAllApplications().forEach {
it.application.relays.forEach { url ->
if (url.isNotBlank()) {
if (!relays.any { it.url == url }) {
if (!relays.any { relay -> relay.url == url }) {
relays.add(Relay(url))
}
}
@@ -109,6 +109,7 @@ fun AccountScreen(
delay(1000)
Client.addRelays(relays.toTypedArray())
@Suppress("KotlinConstantConditions")
if (LocalPreferences.getNotificationType() == NotificationType.DIRECT && BuildConfig.FLAVOR != "offline") {
NostrSigner.instance.applicationContext.startService(
Intent(NostrSigner.instance.applicationContext, ConnectivityService::class.java),
@@ -276,7 +276,7 @@ fun EditPermission(
database.applicationDao().getAllApplications().forEach {
it.application.relays.forEach { url ->
if (url.isNotBlank()) {
if (!relays.any { it.url == url }) {
if (!relays.any { relay -> relay.url == url }) {
relays.add(Relay(url))
}
}
@@ -525,7 +525,7 @@ fun EditPermission(
database.applicationDao().getAllApplications().forEach {
it.application.relays.forEach { url ->
if (url.isNotBlank()) {
if (!relays.any { it.url == url }) {
if (!relays.any { relay -> relay.url == url }) {
relays.add(Relay(url))
}
}
@@ -97,7 +97,7 @@ fun HomeScreen(
}
}
class Result(
data class Result(
val `package`: String?,
val signature: String?,
val id: String?,
@@ -172,7 +172,7 @@ fun LoginPage(accountViewModel: AccountStateViewModel) {
},
leadingIcon = {
if (dialogOpen) {
simpleQrCodeScanner {
SimpleQrCodeScanner {
dialogOpen = false
if (!it.isNullOrEmpty()) {
key.value = TextFieldValue(it)
@@ -313,6 +313,7 @@ fun LoginPage(accountViewModel: AccountStateViewModel) {
Spacer(modifier = Modifier.height(10.dp))
@Suppress("KotlinConstantConditions")
if (BuildConfig.FLAVOR != "offline" && PackageUtils.isOrbotInstalled(context)) {
Row(verticalAlignment = Alignment.CenterVertically) {
Checkbox(
@@ -321,7 +321,7 @@ fun PermissionsFloatingActionButton(
val context = LocalContext.current
if (dialogOpen) {
simpleQrCodeScanner {
SimpleQrCodeScanner {
dialogOpen = false
if (!it.isNullOrEmpty()) {
val intent = Intent(Intent.ACTION_VIEW)
@@ -504,6 +504,7 @@ fun MainScreen(
val context = LocalContext.current
var showDialog by remember { mutableStateOf(false) }
@Suppress("KotlinConstantConditions")
if (BuildConfig.FLAVOR != "offline") {
LaunchedEffect(Unit) {
launch(Dispatchers.IO) {
@@ -553,6 +554,7 @@ fun MainScreen(
Scaffold(
floatingActionButton = {
@Suppress("KotlinConstantConditions")
if (destinationRoute == "Permissions" && BuildConfig.FLAVOR != "offline") {
PermissionsFloatingActionButton(
accountStateViewModel,
@@ -662,6 +664,7 @@ fun MainScreen(
) { padding ->
var localRoute by remember { mutableStateOf(route.value ?: Route.Home.route) }
@Suppress("KotlinConstantConditions")
if (BuildConfig.FLAVOR != "offline") {
LaunchedEffect(Unit, route.value) {
launch(Dispatchers.Main) {
@@ -9,7 +9,7 @@ import com.journeyapps.barcodescanner.ScanContract
import com.journeyapps.barcodescanner.ScanOptions
@Composable
fun simpleQrCodeScanner(onScan: (String?) -> Unit) {
fun SimpleQrCodeScanner(onScan: (String?) -> Unit) {
val lifecycleOwner = LocalLifecycleOwner.current
val qrLauncher =
@@ -165,7 +165,7 @@ fun SettingsScreen(
Modifier
.padding(8.dp),
) {
settingsRow(
SettingsRow(
R.string.notification_type,
R.string.select_the_type_of_notification_you_want_to_receive,
notificationItems,
@@ -224,6 +224,8 @@ fun SettingsScreen(
},
)
}
@Suppress("KotlinConstantConditions")
if (BuildConfig.FLAVOR != "offline") {
Box(
Modifier
@@ -345,10 +347,10 @@ fun SettingsScreen(
}
@Composable
fun settingsRow(
fun SettingsRow(
name: Int,
description: Int,
selectedItens: ImmutableList<TitleExplainer>,
selectedItems: ImmutableList<TitleExplainer>,
selectedIndex: Int,
onSelect: (Int) -> Unit,
) {
@@ -376,8 +378,8 @@ fun settingsRow(
TextSpinner(
label = "",
placeholder = selectedItens[selectedIndex].title,
options = selectedItens,
placeholder = selectedItems[selectedIndex].title,
options = selectedItems,
onSelect = onSelect,
modifier =
Modifier
@@ -66,11 +66,9 @@ import com.greenart7c3.nostrsigner.service.toShortenHex
import com.greenart7c3.nostrsigner.ui.Result
import com.greenart7c3.nostrsigner.ui.theme.ButtonBorder
import com.vitorpamplona.quartz.events.LnZapRequestEvent
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@OptIn(DelicateCoroutinesApi::class)
@Composable
fun MultiEventHomeScreen(
intents: List<IntentData>,
@@ -5,10 +5,8 @@ import androidx.compose.material.icons.automirrored.filled.ViewList
import androidx.compose.material.icons.automirrored.outlined.ViewList
import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material.icons.filled.ViewList
import androidx.compose.material.icons.outlined.Home
import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material.icons.outlined.ViewList
import androidx.compose.runtime.Immutable
import androidx.compose.ui.graphics.vector.ImageVector
@@ -38,7 +38,7 @@ class Notifications : FirebaseMessagingService() {
super.onMessageReceived(remoteMessage)
}
private suspend fun parseMessage(params: Map<String, String>): GiftWrapEvent? {
private fun parseMessage(params: Map<String, String>): GiftWrapEvent? {
params["encryptedEvent"]?.let { eventStr ->
(Event.fromJson(eventStr) as? GiftWrapEvent)?.let {
return it