mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-04-09 04:18:11 +02:00
Moving away from handlers and into coroutines.
This commit is contained in:
parent
9d52180550
commit
8771584deb
@ -13,6 +13,7 @@ import java.util.Collections
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import nostr.postr.events.Event
|
||||
|
||||
@ -99,17 +100,18 @@ class Note(val idHex: String) {
|
||||
val live: NoteLiveData = NoteLiveData(this)
|
||||
|
||||
// Refreshes observers in batches.
|
||||
val filterHandler = Handler(Looper.getMainLooper())
|
||||
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||
var handlerWaiting = false
|
||||
@Synchronized
|
||||
fun invalidateData() {
|
||||
if (handlerWaiting) return
|
||||
|
||||
handlerWaiting = true
|
||||
filterHandler.postDelayed({
|
||||
scope.launch {
|
||||
delay(100)
|
||||
live.refresh()
|
||||
handlerWaiting = false
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,18 +122,12 @@ class NoteLiveData(val note: Note): LiveData<NoteState>(NoteState(note)) {
|
||||
|
||||
override fun onActive() {
|
||||
super.onActive()
|
||||
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||
scope.launch {
|
||||
NostrSingleEventDataSource.add(note.idHex)
|
||||
}
|
||||
NostrSingleEventDataSource.add(note.idHex)
|
||||
}
|
||||
|
||||
override fun onInactive() {
|
||||
super.onInactive()
|
||||
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||
scope.launch {
|
||||
NostrSingleEventDataSource.remove(note.idHex)
|
||||
}
|
||||
NostrSingleEventDataSource.remove(note.idHex)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ object UrlCachedPreviewer {
|
||||
return
|
||||
}
|
||||
|
||||
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||
val scope = CoroutineScope(Job() + Dispatchers.IO)
|
||||
scope.launch {
|
||||
BahaUrlPreview(url, object : IUrlPreviewCallback {
|
||||
override fun onComplete(urlInfo: UrlInfoItem) {
|
||||
|
@ -11,6 +11,7 @@ import java.util.concurrent.ConcurrentHashMap
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import nostr.postr.events.ContactListEvent
|
||||
|
||||
@ -112,18 +113,18 @@ class User(val pubkey: ByteArray) {
|
||||
val live: UserLiveData = UserLiveData(this)
|
||||
|
||||
// Refreshes observers in batches.
|
||||
val filterHandler = Handler(Looper.getMainLooper())
|
||||
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||
var handlerWaiting = false
|
||||
@Synchronized
|
||||
fun invalidateData() {
|
||||
if (handlerWaiting) return
|
||||
|
||||
handlerWaiting = true
|
||||
filterHandler.postDelayed({
|
||||
println("User Refresh")
|
||||
scope.launch {
|
||||
delay(100)
|
||||
live.refresh()
|
||||
handlerWaiting = false
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,24 +154,18 @@ class UserMetadata {
|
||||
}
|
||||
|
||||
class UserLiveData(val user: User): LiveData<UserState>(UserState(user)) {
|
||||
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||
|
||||
fun refresh() {
|
||||
postValue(UserState(user))
|
||||
}
|
||||
|
||||
override fun onActive() {
|
||||
super.onActive()
|
||||
scope.launch {
|
||||
NostrSingleUserDataSource.add(user.pubkeyHex)
|
||||
}
|
||||
NostrSingleUserDataSource.add(user.pubkeyHex)
|
||||
}
|
||||
|
||||
override fun onInactive() {
|
||||
super.onInactive()
|
||||
scope.launch {
|
||||
NostrSingleUserDataSource.remove(user.pubkeyHex)
|
||||
}
|
||||
NostrSingleUserDataSource.remove(user.pubkeyHex)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ object NostrAccountDataSource: NostrDataSource<Note>("AccountData") {
|
||||
return JsonFilter(
|
||||
kinds = listOf(MetadataEvent.kind),
|
||||
authors = listOf(account.userProfile().pubkeyHex),
|
||||
limit = 1
|
||||
limit = 3
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ import kotlin.time.measureTimedValue
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import nostr.postr.events.ContactListEvent
|
||||
import nostr.postr.events.DeletionEvent
|
||||
@ -118,7 +119,7 @@ abstract class NostrDataSource<T>(val debugName: String) {
|
||||
val returningList = feed().take(100)
|
||||
|
||||
// prepare previews
|
||||
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||
val scope = CoroutineScope(Job() + Dispatchers.IO)
|
||||
scope.launch {
|
||||
loadPreviews(returningList)
|
||||
}
|
||||
@ -147,17 +148,18 @@ abstract class NostrDataSource<T>(val debugName: String) {
|
||||
channelIds.remove(channel.id)
|
||||
}
|
||||
|
||||
val filterHandler = Handler(Looper.getMainLooper())
|
||||
val scope = CoroutineScope(Job() + Dispatchers.IO)
|
||||
var handlerWaiting = false
|
||||
@Synchronized
|
||||
fun invalidateFilters() {
|
||||
if (handlerWaiting) return
|
||||
|
||||
handlerWaiting = true
|
||||
filterHandler.postDelayed({
|
||||
scope.launch {
|
||||
delay(200)
|
||||
resetFilters()
|
||||
handlerWaiting = false
|
||||
}, 200)
|
||||
}
|
||||
}
|
||||
|
||||
fun resetFilters() {
|
||||
|
@ -16,7 +16,7 @@ object NostrSingleUserDataSource: NostrDataSource<Note>("SingleUserFeed") {
|
||||
JsonFilter(
|
||||
kinds = listOf(MetadataEvent.kind),
|
||||
authors = listOf(it.substring(0, 8)),
|
||||
limit = 1
|
||||
limit = 10
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,10 @@ fun DrawerContent(navController: NavHostController,
|
||||
accountViewModel: AccountViewModel,
|
||||
accountStateViewModel: AccountStateViewModel) {
|
||||
|
||||
val accountUserState by accountViewModel.userLiveData.observeAsState()
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = accountState?.account ?: return
|
||||
|
||||
val accountUserState by account.userProfile().live.observeAsState()
|
||||
val accountUser = accountUserState?.user
|
||||
|
||||
Surface(
|
||||
@ -64,14 +67,18 @@ fun DrawerContent(navController: NavHostController,
|
||||
model = banner,
|
||||
contentDescription = "Profile Image",
|
||||
contentScale = ContentScale.FillWidth,
|
||||
modifier = Modifier.fillMaxWidth().height(150.dp)
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(150.dp)
|
||||
)
|
||||
} else {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.profile_banner),
|
||||
contentDescription = "Profile Banner",
|
||||
contentScale = ContentScale.FillWidth,
|
||||
modifier = Modifier.fillMaxWidth().height(150.dp)
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(150.dp)
|
||||
)
|
||||
}
|
||||
|
||||
@ -106,12 +113,15 @@ fun DrawerContent(navController: NavHostController,
|
||||
fun ProfileContent(accountUser: User?, modifier: Modifier = Modifier, scaffoldState: ScaffoldState, navController: NavController) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
println("AAA " + accountUser?.profilePicture())
|
||||
|
||||
Column(modifier = modifier) {
|
||||
AsyncImage(
|
||||
model = accountUser?.profilePicture() ?: "https://robohash.org/ohno.png",
|
||||
contentDescription = "Profile Image",
|
||||
modifier = Modifier
|
||||
.width(100.dp).height(100.dp)
|
||||
.width(100.dp)
|
||||
.height(100.dp)
|
||||
.clip(shape = CircleShape)
|
||||
.border(3.dp, MaterialTheme.colors.background, CircleShape)
|
||||
.background(MaterialTheme.colors.background)
|
||||
@ -205,7 +215,8 @@ fun NavigationRow(navController: NavHostController, scaffoldState: ScaffoldState
|
||||
})
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 15.dp, horizontal = 25.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
|
@ -14,6 +14,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
@ -26,24 +27,28 @@ class CardFeedViewModel(val dataSource: NostrDataSource<Note>): ViewModel() {
|
||||
private var lastNotes: List<Note>? = null
|
||||
|
||||
fun refresh() {
|
||||
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||
val scope = CoroutineScope(Job() + Dispatchers.IO)
|
||||
scope.launch {
|
||||
val notes = dataSource.loadTop()
|
||||
refreshSuspended()
|
||||
}
|
||||
}
|
||||
|
||||
val lastNotesCopy = lastNotes
|
||||
private fun refreshSuspended() {
|
||||
val notes = dataSource.loadTop()
|
||||
|
||||
val oldNotesState = feedContent.value
|
||||
if (lastNotesCopy != null && oldNotesState is CardFeedState.Loaded) {
|
||||
val newCards = convertToCard(notes.minus(lastNotesCopy))
|
||||
if (newCards.isNotEmpty()) {
|
||||
lastNotes = notes
|
||||
updateFeed((oldNotesState.feed + newCards).sortedBy { it.createdAt() }.reversed())
|
||||
}
|
||||
} else {
|
||||
val cards = convertToCard(notes)
|
||||
val lastNotesCopy = lastNotes
|
||||
|
||||
val oldNotesState = feedContent.value
|
||||
if (lastNotesCopy != null && oldNotesState is CardFeedState.Loaded) {
|
||||
val newCards = convertToCard(notes.minus(lastNotesCopy))
|
||||
if (newCards.isNotEmpty()) {
|
||||
lastNotes = notes
|
||||
updateFeed(cards)
|
||||
updateFeed((oldNotesState.feed + newCards).sortedBy { it.createdAt() }.reversed())
|
||||
}
|
||||
} else {
|
||||
val cards = convertToCard(notes)
|
||||
lastNotes = notes
|
||||
updateFeed(cards)
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,31 +81,28 @@ class CardFeedViewModel(val dataSource: NostrDataSource<Note>): ViewModel() {
|
||||
}
|
||||
|
||||
fun updateFeed(notes: List<Card>) {
|
||||
if (notes.isEmpty()) {
|
||||
_feedContent.update { CardFeedState.Empty }
|
||||
} else {
|
||||
_feedContent.update { CardFeedState.Loaded(notes) }
|
||||
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||
scope.launch {
|
||||
if (notes.isEmpty()) {
|
||||
_feedContent.update { CardFeedState.Empty }
|
||||
} else {
|
||||
_feedContent.update { CardFeedState.Loaded(notes) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun refreshCurrentList() {
|
||||
val state = feedContent.value
|
||||
if (state is CardFeedState.Loaded) {
|
||||
_feedContent.update { CardFeedState.Loaded(state.feed) }
|
||||
}
|
||||
}
|
||||
|
||||
val filterHandler = Handler(Looper.getMainLooper())
|
||||
val scope = CoroutineScope(Job() + Dispatchers.IO)
|
||||
var handlerWaiting = false
|
||||
@Synchronized
|
||||
fun invalidateData() {
|
||||
if (handlerWaiting) return
|
||||
|
||||
handlerWaiting = true
|
||||
filterHandler.postDelayed({
|
||||
scope.launch {
|
||||
delay(100)
|
||||
refresh()
|
||||
handlerWaiting = false
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
|
||||
private val cacheListener: (LocalCacheState) -> Unit = {
|
||||
|
@ -23,6 +23,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
@ -42,26 +43,33 @@ abstract class FeedViewModel(val dataSource: NostrDataSource<Note>): ViewModel()
|
||||
val feedContent = _feedContent.asStateFlow()
|
||||
|
||||
fun refresh() {
|
||||
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||
val scope = CoroutineScope(Job() + Dispatchers.IO)
|
||||
scope.launch {
|
||||
val notes = dataSource.loadTop()
|
||||
refreshSuspended()
|
||||
}
|
||||
}
|
||||
|
||||
val oldNotesState = feedContent.value
|
||||
if (oldNotesState is FeedState.Loaded) {
|
||||
if (notes != oldNotesState.feed) {
|
||||
updateFeed(notes)
|
||||
}
|
||||
} else {
|
||||
private fun refreshSuspended() {
|
||||
val notes = dataSource.loadTop()
|
||||
|
||||
val oldNotesState = feedContent.value
|
||||
if (oldNotesState is FeedState.Loaded) {
|
||||
if (notes != oldNotesState.feed) {
|
||||
updateFeed(notes)
|
||||
}
|
||||
} else {
|
||||
updateFeed(notes)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateFeed(notes: List<Note>) {
|
||||
if (notes.isEmpty()) {
|
||||
_feedContent.update { FeedState.Empty }
|
||||
} else {
|
||||
_feedContent.update { FeedState.Loaded(notes) }
|
||||
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||
scope.launch {
|
||||
if (notes.isEmpty()) {
|
||||
_feedContent.update { FeedState.Empty }
|
||||
} else {
|
||||
_feedContent.update { FeedState.Loaded(notes) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,17 +80,18 @@ abstract class FeedViewModel(val dataSource: NostrDataSource<Note>): ViewModel()
|
||||
}
|
||||
}
|
||||
|
||||
val filterHandler = Handler(Looper.getMainLooper())
|
||||
val scope = CoroutineScope(Job() + Dispatchers.IO)
|
||||
var handlerWaiting = false
|
||||
@Synchronized
|
||||
fun invalidateData() {
|
||||
if (handlerWaiting) return
|
||||
|
||||
handlerWaiting = true
|
||||
filterHandler.postDelayed({
|
||||
scope.launch {
|
||||
delay(100)
|
||||
refresh()
|
||||
handlerWaiting = false
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
|
||||
private val cacheListener: (LocalCacheState) -> Unit = {
|
||||
|
@ -14,6 +14,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
@ -32,26 +33,33 @@ open class UserFeedViewModel(val dataSource: NostrDataSource<User>): ViewModel()
|
||||
val feedContent = _feedContent.asStateFlow()
|
||||
|
||||
fun refresh() {
|
||||
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||
val scope = CoroutineScope(Job() + Dispatchers.IO)
|
||||
scope.launch {
|
||||
val notes = dataSource.loadTop()
|
||||
refreshSuspended()
|
||||
}
|
||||
}
|
||||
|
||||
val oldNotesState = feedContent.value
|
||||
if (oldNotesState is UserFeedState.Loaded) {
|
||||
if (notes != oldNotesState.feed) {
|
||||
updateFeed(notes)
|
||||
}
|
||||
} else {
|
||||
private fun refreshSuspended() {
|
||||
val notes = dataSource.loadTop()
|
||||
|
||||
val oldNotesState = feedContent.value
|
||||
if (oldNotesState is UserFeedState.Loaded) {
|
||||
if (notes != oldNotesState.feed) {
|
||||
updateFeed(notes)
|
||||
}
|
||||
} else {
|
||||
updateFeed(notes)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateFeed(notes: List<User>) {
|
||||
if (notes.isEmpty()) {
|
||||
_feedContent.update { UserFeedState.Empty }
|
||||
} else {
|
||||
_feedContent.update { UserFeedState.Loaded(notes) }
|
||||
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||
scope.launch {
|
||||
if (notes.isEmpty()) {
|
||||
_feedContent.update { UserFeedState.Empty }
|
||||
} else {
|
||||
_feedContent.update { UserFeedState.Loaded(notes) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,17 +70,18 @@ open class UserFeedViewModel(val dataSource: NostrDataSource<User>): ViewModel()
|
||||
}
|
||||
}
|
||||
|
||||
val filterHandler = Handler(Looper.getMainLooper())
|
||||
val scope = CoroutineScope(Job() + Dispatchers.IO)
|
||||
var handlerWaiting = false
|
||||
@Synchronized
|
||||
fun invalidateData() {
|
||||
if (handlerWaiting) return
|
||||
|
||||
handlerWaiting = true
|
||||
filterHandler.postDelayed({
|
||||
scope.launch {
|
||||
delay(100)
|
||||
refresh()
|
||||
handlerWaiting = false
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
|
||||
private val cacheListener: (LocalCacheState) -> Unit = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user