mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-09-27 21:36:28 +02:00
Spam filter in new private messages
This commit is contained in:
@@ -6,7 +6,6 @@ import com.vitorpamplona.amethyst.model.Account
|
|||||||
import com.vitorpamplona.amethyst.model.DefaultChannels
|
import com.vitorpamplona.amethyst.model.DefaultChannels
|
||||||
import com.vitorpamplona.amethyst.model.toByteArray
|
import com.vitorpamplona.amethyst.model.toByteArray
|
||||||
import com.vitorpamplona.amethyst.service.NostrAccountDataSource
|
import com.vitorpamplona.amethyst.service.NostrAccountDataSource
|
||||||
import com.vitorpamplona.amethyst.service.NostrChannelDataSource
|
|
||||||
import com.vitorpamplona.amethyst.service.NostrChatroomListDataSource
|
import com.vitorpamplona.amethyst.service.NostrChatroomListDataSource
|
||||||
import com.vitorpamplona.amethyst.service.NostrGlobalDataSource
|
import com.vitorpamplona.amethyst.service.NostrGlobalDataSource
|
||||||
import com.vitorpamplona.amethyst.service.NostrHomeDataSource
|
import com.vitorpamplona.amethyst.service.NostrHomeDataSource
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.screen
|
package com.vitorpamplona.amethyst.ui.screen
|
||||||
|
|
||||||
import android.os.Handler
|
|
||||||
import android.os.Looper
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.vitorpamplona.amethyst.model.LocalCache
|
import com.vitorpamplona.amethyst.model.LocalCache
|
||||||
@@ -15,10 +13,6 @@ import com.vitorpamplona.amethyst.service.NostrGlobalDataSource
|
|||||||
import com.vitorpamplona.amethyst.service.NostrHomeDataSource
|
import com.vitorpamplona.amethyst.service.NostrHomeDataSource
|
||||||
import com.vitorpamplona.amethyst.service.NostrThreadDataSource
|
import com.vitorpamplona.amethyst.service.NostrThreadDataSource
|
||||||
import com.vitorpamplona.amethyst.service.NostrUserProfileDataSource
|
import com.vitorpamplona.amethyst.service.NostrUserProfileDataSource
|
||||||
import com.vitorpamplona.amethyst.service.NostrUserProfileFollowersDataSource
|
|
||||||
import com.vitorpamplona.amethyst.service.NostrUserProfileFollowsDataSource
|
|
||||||
import kotlin.time.ExperimentalTime
|
|
||||||
import kotlin.time.measureTimedValue
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
@@ -31,21 +25,42 @@ import kotlinx.coroutines.launch
|
|||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class NostrChannelFeedViewModel: FeedViewModel(NostrChannelDataSource)
|
class NostrChannelFeedViewModel: FeedViewModel(NostrChannelDataSource)
|
||||||
class NostrChatroomListFeedViewModel: FeedViewModel(NostrChatroomListDataSource)
|
|
||||||
class NostrChatRoomFeedViewModel: FeedViewModel(NostrChatRoomDataSource)
|
class NostrChatRoomFeedViewModel: FeedViewModel(NostrChatRoomDataSource)
|
||||||
class NostrHomeFeedViewModel: FeedViewModel(NostrHomeDataSource)
|
class NostrHomeFeedViewModel: FeedViewModel(NostrHomeDataSource)
|
||||||
class NostrGlobalFeedViewModel: FeedViewModel(NostrGlobalDataSource)
|
class NostrGlobalFeedViewModel: FeedViewModel(NostrGlobalDataSource)
|
||||||
class NostrThreadFeedViewModel: FeedViewModel(NostrThreadDataSource)
|
class NostrThreadFeedViewModel: FeedViewModel(NostrThreadDataSource)
|
||||||
class NostrUserProfileFeedViewModel: FeedViewModel(NostrUserProfileDataSource)
|
class NostrUserProfileFeedViewModel: FeedViewModel(NostrUserProfileDataSource)
|
||||||
|
|
||||||
|
class NostrChatroomListKnownFeedViewModel: FeedViewModel(NostrChatroomListDataSource) {
|
||||||
|
override fun newListFromDataSource(): List<Note> {
|
||||||
|
// Filter: all channels + PMs the account has replied to
|
||||||
|
return super.newListFromDataSource().filter {
|
||||||
|
val me = NostrChatroomListDataSource.account.userProfile()
|
||||||
|
it.channel != null || me.messages[it.author]?.firstOrNull { me == it.author } != null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class NostrChatroomListNewFeedViewModel: FeedViewModel(NostrChatroomListDataSource) {
|
||||||
|
override fun newListFromDataSource(): List<Note> {
|
||||||
|
// Filter: no channels + PMs the account has never replied to
|
||||||
|
return super.newListFromDataSource().filter {
|
||||||
|
val me = NostrChatroomListDataSource.account.userProfile()
|
||||||
|
it.channel == null && me.messages[it.author]?.firstOrNull { me == it.author } == null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
abstract class FeedViewModel(val dataSource: NostrDataSource<Note>): ViewModel() {
|
abstract class FeedViewModel(val dataSource: NostrDataSource<Note>): ViewModel() {
|
||||||
private val _feedContent = MutableStateFlow<FeedState>(FeedState.Loading)
|
private val _feedContent = MutableStateFlow<FeedState>(FeedState.Loading)
|
||||||
val feedContent = _feedContent.asStateFlow()
|
val feedContent = _feedContent.asStateFlow()
|
||||||
|
|
||||||
|
open fun newListFromDataSource(): List<Note> {
|
||||||
|
return dataSource.loadTop()
|
||||||
|
}
|
||||||
|
|
||||||
fun refresh() {
|
fun refresh() {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
val notes = dataSource.loadTop()
|
val notes = newListFromDataSource()
|
||||||
|
|
||||||
val oldNotesState = feedContent.value
|
val oldNotesState = feedContent.value
|
||||||
if (oldNotesState is FeedState.Loaded) {
|
if (oldNotesState is FeedState.Loaded) {
|
||||||
|
@@ -3,35 +3,100 @@ package com.vitorpamplona.amethyst.ui.screen
|
|||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.material.Tab
|
||||||
|
import androidx.compose.material.TabRow
|
||||||
|
import androidx.compose.material.TabRowDefaults
|
||||||
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.livedata.observeAsState
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.vitorpamplona.amethyst.service.NostrChatroomListDataSource
|
import com.google.accompanist.pager.ExperimentalPagerApi
|
||||||
|
import com.google.accompanist.pager.HorizontalPager
|
||||||
|
import com.google.accompanist.pager.pagerTabIndicatorOffset
|
||||||
|
import com.google.accompanist.pager.rememberPagerState
|
||||||
|
import com.vitorpamplona.amethyst.model.User
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@OptIn(ExperimentalPagerApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun ChatroomListScreen(accountViewModel: AccountViewModel, navController: NavController) {
|
fun ChatroomListScreen(accountViewModel: AccountViewModel, navController: NavController) {
|
||||||
val account by accountViewModel.accountLiveData.observeAsState()
|
val account by accountViewModel.accountLiveData.observeAsState()
|
||||||
|
|
||||||
if (account != null) {
|
if (account != null) {
|
||||||
val feedViewModel: NostrChatroomListFeedViewModel = viewModel()
|
val pagerState = rememberPagerState()
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
LaunchedEffect(Unit) {
|
|
||||||
feedViewModel.refresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
Column(Modifier.fillMaxHeight()) {
|
Column(Modifier.fillMaxHeight()) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.padding(vertical = 0.dp)
|
modifier = Modifier.padding(vertical = 0.dp)
|
||||||
) {
|
) {
|
||||||
ChatroomListFeedView(feedViewModel, accountViewModel, navController)
|
TabRow(
|
||||||
|
selectedTabIndex = pagerState.currentPage,
|
||||||
|
indicator = { tabPositions ->
|
||||||
|
TabRowDefaults.Indicator(
|
||||||
|
Modifier.pagerTabIndicatorOffset(pagerState, tabPositions),
|
||||||
|
color = MaterialTheme.colors.primary
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Tab(
|
||||||
|
selected = pagerState.currentPage == 0,
|
||||||
|
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(0) } },
|
||||||
|
text = {
|
||||||
|
Text(text = "Known")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Tab(
|
||||||
|
selected = pagerState.currentPage == 1,
|
||||||
|
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(1) } },
|
||||||
|
text = {
|
||||||
|
Text(text = "New Requests")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
HorizontalPager(count = 2, state = pagerState) {
|
||||||
|
when (pagerState.currentPage) {
|
||||||
|
0 -> TabKnown(accountViewModel, navController)
|
||||||
|
1 -> TabNew(accountViewModel, navController)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun TabKnown(accountViewModel: AccountViewModel, navController: NavController) {
|
||||||
|
val feedViewModel: NostrChatroomListKnownFeedViewModel = viewModel()
|
||||||
|
|
||||||
|
|
||||||
|
Column(Modifier.fillMaxHeight()) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(vertical = 0.dp)
|
||||||
|
) {
|
||||||
|
ChatroomListFeedView(feedViewModel, accountViewModel, navController)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun TabNew(accountViewModel: AccountViewModel, navController: NavController) {
|
||||||
|
val feedViewModel: NostrChatroomListNewFeedViewModel = viewModel()
|
||||||
|
|
||||||
|
Column(Modifier.fillMaxHeight()) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(vertical = 0.dp)
|
||||||
|
) {
|
||||||
|
ChatroomListFeedView(feedViewModel, accountViewModel, navController)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user