mirror of
https://github.com/greenart7c3/Amber.git
synced 2026-10-05 19:08:23 +00:00
linter fix
This commit is contained in:
@@ -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 }
|
||||
}
|
||||
-31
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user