mirror of
https://github.com/greenart7c3/Amber.git
synced 2026-10-05 10:58:23 +00:00
Move profile fetch to its own file
This commit is contained in:
@@ -10,11 +10,6 @@ import androidx.work.ExistingPeriodicWorkPolicy
|
|||||||
import androidx.work.OneTimeWorkRequest
|
import androidx.work.OneTimeWorkRequest
|
||||||
import androidx.work.PeriodicWorkRequestBuilder
|
import androidx.work.PeriodicWorkRequestBuilder
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import coil3.ImageLoader
|
|
||||||
import coil3.SingletonImageLoader
|
|
||||||
import coil3.network.okhttp.OkHttpNetworkFetcherFactory
|
|
||||||
import coil3.request.crossfade
|
|
||||||
import coil3.util.DebugLogger
|
|
||||||
import com.greenart7c3.nostrsigner.database.AppDatabase
|
import com.greenart7c3.nostrsigner.database.AppDatabase
|
||||||
import com.greenart7c3.nostrsigner.models.Account
|
import com.greenart7c3.nostrsigner.models.Account
|
||||||
import com.greenart7c3.nostrsigner.models.AmberSettings
|
import com.greenart7c3.nostrsigner.models.AmberSettings
|
||||||
@@ -26,7 +21,6 @@ import com.greenart7c3.nostrsigner.relays.AmberRelayStats
|
|||||||
import com.greenart7c3.nostrsigner.service.ClearLogsWorker
|
import com.greenart7c3.nostrsigner.service.ClearLogsWorker
|
||||||
import com.greenart7c3.nostrsigner.service.ConnectivityService
|
import com.greenart7c3.nostrsigner.service.ConnectivityService
|
||||||
import com.greenart7c3.nostrsigner.service.NotificationDataSource
|
import com.greenart7c3.nostrsigner.service.NotificationDataSource
|
||||||
import com.greenart7c3.nostrsigner.service.ProfileDataSource
|
|
||||||
import com.greenart7c3.nostrsigner.service.RelayDisconnectService
|
import com.greenart7c3.nostrsigner.service.RelayDisconnectService
|
||||||
import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES
|
import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES
|
||||||
import com.vitorpamplona.ammolite.relays.MutableSubscriptionCache
|
import com.vitorpamplona.ammolite.relays.MutableSubscriptionCache
|
||||||
@@ -35,7 +29,6 @@ import com.vitorpamplona.ammolite.relays.Relay
|
|||||||
import com.vitorpamplona.ammolite.relays.RelaySetupInfo
|
import com.vitorpamplona.ammolite.relays.RelaySetupInfo
|
||||||
import com.vitorpamplona.ammolite.relays.RelaySetupInfoToConnect
|
import com.vitorpamplona.ammolite.relays.RelaySetupInfoToConnect
|
||||||
import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle
|
import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle
|
||||||
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
|
|
||||||
import com.vitorpamplona.quartz.nip01Core.tags.people.PTag
|
import com.vitorpamplona.quartz.nip01Core.tags.people.PTag
|
||||||
import com.vitorpamplona.quartz.nip34Git.issue.GitIssueEvent
|
import com.vitorpamplona.quartz.nip34Git.issue.GitIssueEvent
|
||||||
import com.vitorpamplona.quartz.nip34Git.repository.GitRepositoryEvent
|
import com.vitorpamplona.quartz.nip34Git.repository.GitRepositoryEvent
|
||||||
@@ -70,8 +63,6 @@ class Amber : Application() {
|
|||||||
HttpClientManager.getHttpClient(useProxy)
|
HttpClientManager.getHttpClient(useProxy)
|
||||||
}
|
}
|
||||||
val client: NostrClient = NostrClient(factory)
|
val client: NostrClient = NostrClient(factory)
|
||||||
var profileClient = ConcurrentHashMap<String, NostrClient>()
|
|
||||||
val profileDataSource = ConcurrentHashMap<String, ProfileDataSource>()
|
|
||||||
val applicationIOScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
val applicationIOScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||||
private var databases = ConcurrentHashMap<String, AppDatabase>()
|
private var databases = ConcurrentHashMap<String, AppDatabase>()
|
||||||
var settings: AmberSettings = AmberSettings()
|
var settings: AmberSettings = AmberSettings()
|
||||||
@@ -339,93 +330,6 @@ class Amber : Application() {
|
|||||||
applicationIOScope.cancel()
|
applicationIOScope.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fetchProfileData(
|
|
||||||
account: Account,
|
|
||||||
onPictureFound: (String) -> Unit,
|
|
||||||
) {
|
|
||||||
@Suppress("KotlinConstantConditions")
|
|
||||||
if (BuildConfig.FLAVOR == "offline") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
SingletonImageLoader.setSafe {
|
|
||||||
ImageLoader.Builder(this)
|
|
||||||
.crossfade(true)
|
|
||||||
.logger(DebugLogger())
|
|
||||||
.components {
|
|
||||||
add(
|
|
||||||
OkHttpNetworkFetcherFactory(
|
|
||||||
callFactory = {
|
|
||||||
HttpClientManager.getHttpClient(settings.useProxy)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
val lastMetaData = LocalPreferences.getLastMetadataUpdate(this, account.npub)
|
|
||||||
val lastCheck = LocalPreferences.getLastCheck(this, account.npub)
|
|
||||||
val oneDayAgo = TimeUtils.oneDayAgo()
|
|
||||||
val fifteenMinutesAgo = TimeUtils.fifteenMinutesAgo()
|
|
||||||
if ((lastMetaData == 0L || oneDayAgo > lastMetaData) && (lastCheck == 0L || fifteenMinutesAgo > lastCheck)) {
|
|
||||||
Log.d(TAG, "Fetching profile data for ${account.npub}")
|
|
||||||
LocalPreferences.setLastCheck(this, account.npub, TimeUtils.now())
|
|
||||||
val relays = LocalPreferences.loadSettingsFromEncryptedStorage().defaultProfileRelays.map {
|
|
||||||
RelaySetupInfoToConnect(
|
|
||||||
url = it.url,
|
|
||||||
read = it.read,
|
|
||||||
write = it.write,
|
|
||||||
feedTypes = it.feedTypes,
|
|
||||||
forceProxy = settings.useProxy,
|
|
||||||
)
|
|
||||||
}.toTypedArray()
|
|
||||||
profileClient.getOrPut(account.hexKey, defaultValue = { NostrClient(factory) }).reconnect(relays)
|
|
||||||
profileDataSource.getOrPut(
|
|
||||||
account.hexKey,
|
|
||||||
defaultValue = {
|
|
||||||
ProfileDataSource(
|
|
||||||
client = profileClient.get(account.hexKey)!!,
|
|
||||||
account = account,
|
|
||||||
onReceiveEvent = { event ->
|
|
||||||
applicationIOScope.launch {
|
|
||||||
if (event.kind == MetadataEvent.KIND) {
|
|
||||||
(event as MetadataEvent).contactMetaData()?.let { metadata ->
|
|
||||||
metadata.name?.let { name ->
|
|
||||||
account.name = name
|
|
||||||
applicationIOScope.launch {
|
|
||||||
LocalPreferences.saveToEncryptedStorage(account = account, context = this@Amber)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
metadata.profilePicture()?.let { url ->
|
|
||||||
LocalPreferences.saveProfileUrlToEncryptedStorage(url, account.npub)
|
|
||||||
LocalPreferences.setLastMetadataUpdate(this@Amber, account.npub, TimeUtils.now())
|
|
||||||
onPictureFound(url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
profileDataSource[account.hexKey]?.stop()
|
|
||||||
profileClient[account.hexKey]?.getAll()?.forEach {
|
|
||||||
Log.d(TAG, "disconnecting profile relay ${it.url}")
|
|
||||||
it.disconnect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
profileDataSource.get(account.hexKey)?.start()
|
|
||||||
} else {
|
|
||||||
Log.d(TAG, "Using cached profile data for ${account.npub}")
|
|
||||||
LocalPreferences.loadProfileUrlFromEncryptedStorage(account.npub)?.let {
|
|
||||||
onPictureFound(it)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun sendFeedBack(
|
suspend fun sendFeedBack(
|
||||||
subject: String,
|
subject: String,
|
||||||
body: String,
|
body: String,
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
package com.greenart7c3.nostrsigner.service
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import coil3.ImageLoader
|
||||||
|
import coil3.SingletonImageLoader
|
||||||
|
import coil3.network.okhttp.OkHttpNetworkFetcherFactory
|
||||||
|
import coil3.request.crossfade
|
||||||
|
import coil3.util.DebugLogger
|
||||||
|
import com.greenart7c3.nostrsigner.Amber
|
||||||
|
import com.greenart7c3.nostrsigner.Amber.Companion.TAG
|
||||||
|
import com.greenart7c3.nostrsigner.BuildConfig
|
||||||
|
import com.greenart7c3.nostrsigner.LocalPreferences
|
||||||
|
import com.greenart7c3.nostrsigner.models.Account
|
||||||
|
import com.greenart7c3.nostrsigner.okhttp.HttpClientManager
|
||||||
|
import com.vitorpamplona.ammolite.relays.NostrClient
|
||||||
|
import com.vitorpamplona.ammolite.relays.RelaySetupInfoToConnect
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
|
||||||
|
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class ProfileFetcherService {
|
||||||
|
fun fetchProfileData(
|
||||||
|
account: Account,
|
||||||
|
onPictureFound: (String) -> Unit,
|
||||||
|
) {
|
||||||
|
@Suppress("KotlinConstantConditions")
|
||||||
|
if (BuildConfig.FLAVOR == "offline") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
SingletonImageLoader.setSafe {
|
||||||
|
ImageLoader.Builder(Amber.instance)
|
||||||
|
.crossfade(true)
|
||||||
|
.logger(DebugLogger())
|
||||||
|
.components {
|
||||||
|
add(
|
||||||
|
OkHttpNetworkFetcherFactory(
|
||||||
|
callFactory = {
|
||||||
|
HttpClientManager.getHttpClient(Amber.instance.settings.useProxy)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
val lastMetaData = LocalPreferences.getLastMetadataUpdate(Amber.instance, account.npub)
|
||||||
|
val lastCheck = LocalPreferences.getLastCheck(Amber.instance, account.npub)
|
||||||
|
val oneDayAgo = TimeUtils.oneDayAgo()
|
||||||
|
val fifteenMinutesAgo = TimeUtils.fifteenMinutesAgo()
|
||||||
|
if ((lastMetaData == 0L || oneDayAgo > lastMetaData) && (lastCheck == 0L || fifteenMinutesAgo > lastCheck)) {
|
||||||
|
Log.d(TAG, "Fetching profile data for ${account.npub}")
|
||||||
|
LocalPreferences.setLastCheck(Amber.instance, account.npub, TimeUtils.now())
|
||||||
|
val relays = LocalPreferences.loadSettingsFromEncryptedStorage().defaultProfileRelays.map {
|
||||||
|
RelaySetupInfoToConnect(
|
||||||
|
url = it.url,
|
||||||
|
read = it.read,
|
||||||
|
write = it.write,
|
||||||
|
feedTypes = it.feedTypes,
|
||||||
|
forceProxy = Amber.instance.settings.useProxy,
|
||||||
|
)
|
||||||
|
}.toTypedArray()
|
||||||
|
val client = NostrClient(Amber.instance.factory)
|
||||||
|
client.reconnect(relays)
|
||||||
|
val profileDataSource = ProfileDataSource(
|
||||||
|
client = client,
|
||||||
|
account = account,
|
||||||
|
onReceiveEvent = { event ->
|
||||||
|
Amber.instance.applicationIOScope.launch {
|
||||||
|
if (event.kind == MetadataEvent.KIND) {
|
||||||
|
(event as MetadataEvent).contactMetaData()?.let { metadata ->
|
||||||
|
metadata.name?.let { name ->
|
||||||
|
account.name = name
|
||||||
|
Amber.instance.applicationIOScope.launch {
|
||||||
|
LocalPreferences.saveToEncryptedStorage(account = account, context = Amber.instance)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata.profilePicture()?.let { url ->
|
||||||
|
LocalPreferences.saveProfileUrlToEncryptedStorage(url, account.npub)
|
||||||
|
LocalPreferences.setLastMetadataUpdate(Amber.instance, account.npub, TimeUtils.now())
|
||||||
|
onPictureFound(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
profileDataSource.start()
|
||||||
|
Amber.instance.applicationIOScope.launch {
|
||||||
|
delay(60000)
|
||||||
|
profileDataSource.stop()
|
||||||
|
client.getAll().forEach {
|
||||||
|
Log.d(TAG, "disconnecting profile relay ${it.url}")
|
||||||
|
it.disconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "Using cached profile data for ${account.npub}")
|
||||||
|
LocalPreferences.loadProfileUrlFromEncryptedStorage(account.npub)?.let {
|
||||||
|
onPictureFound(it)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -63,6 +63,7 @@ import com.greenart7c3.nostrsigner.models.IntentData
|
|||||||
import com.greenart7c3.nostrsigner.models.IntentResultType
|
import com.greenart7c3.nostrsigner.models.IntentResultType
|
||||||
import com.greenart7c3.nostrsigner.relays.AmberRelayStats
|
import com.greenart7c3.nostrsigner.relays.AmberRelayStats
|
||||||
import com.greenart7c3.nostrsigner.service.NotificationDataSource
|
import com.greenart7c3.nostrsigner.service.NotificationDataSource
|
||||||
|
import com.greenart7c3.nostrsigner.service.ProfileFetcherService
|
||||||
import com.greenart7c3.nostrsigner.ui.actions.AccountBackupScreen
|
import com.greenart7c3.nostrsigner.ui.actions.AccountBackupScreen
|
||||||
import com.greenart7c3.nostrsigner.ui.actions.AccountsBottomSheet
|
import com.greenart7c3.nostrsigner.ui.actions.AccountsBottomSheet
|
||||||
import com.greenart7c3.nostrsigner.ui.actions.ActiveRelaysScreen
|
import com.greenart7c3.nostrsigner.ui.actions.ActiveRelaysScreen
|
||||||
@@ -173,7 +174,7 @@ fun MainScreen(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
Amber.instance.fetchProfileData(
|
ProfileFetcherService().fetchProfileData(
|
||||||
account = account,
|
account = account,
|
||||||
onPictureFound = {
|
onPictureFound = {
|
||||||
profileUrl = it
|
profileUrl = it
|
||||||
|
|||||||
@@ -39,11 +39,11 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.window.core.layout.WindowWidthSizeClass
|
import androidx.window.core.layout.WindowWidthSizeClass
|
||||||
import coil3.compose.AsyncImage
|
import coil3.compose.AsyncImage
|
||||||
import com.greenart7c3.nostrsigner.Amber
|
|
||||||
import com.greenart7c3.nostrsigner.BuildConfig
|
import com.greenart7c3.nostrsigner.BuildConfig
|
||||||
import com.greenart7c3.nostrsigner.R
|
import com.greenart7c3.nostrsigner.R
|
||||||
import com.greenart7c3.nostrsigner.models.Account
|
import com.greenart7c3.nostrsigner.models.Account
|
||||||
import com.greenart7c3.nostrsigner.models.Permission
|
import com.greenart7c3.nostrsigner.models.Permission
|
||||||
|
import com.greenart7c3.nostrsigner.service.ProfileFetcherService
|
||||||
import com.greenart7c3.nostrsigner.service.toShortenHex
|
import com.greenart7c3.nostrsigner.service.toShortenHex
|
||||||
import com.greenart7c3.nostrsigner.ui.RememberType
|
import com.greenart7c3.nostrsigner.ui.RememberType
|
||||||
import com.greenart7c3.nostrsigner.ui.navigation.Route
|
import com.greenart7c3.nostrsigner.ui.navigation.Route
|
||||||
@@ -58,7 +58,7 @@ fun ProfilePicture(account: Account) {
|
|||||||
var profileUrl by remember { mutableStateOf<String?>(null) }
|
var profileUrl by remember { mutableStateOf<String?>(null) }
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
launch(Dispatchers.IO) {
|
launch(Dispatchers.IO) {
|
||||||
Amber.instance.fetchProfileData(
|
ProfileFetcherService().fetchProfileData(
|
||||||
account = account,
|
account = account,
|
||||||
onPictureFound = {
|
onPictureFound = {
|
||||||
profileUrl = it
|
profileUrl = it
|
||||||
|
|||||||
Reference in New Issue
Block a user