mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-10-06 22:53:34 +02:00
Displays the amount and list of reports in the Profile page.
This commit is contained in:
@@ -0,0 +1,18 @@
|
|||||||
|
package com.vitorpamplona.amethyst.ui.dal
|
||||||
|
|
||||||
|
import com.vitorpamplona.amethyst.model.LocalCache
|
||||||
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
|
import com.vitorpamplona.amethyst.model.User
|
||||||
|
import com.vitorpamplona.amethyst.service.model.LnZapEvent
|
||||||
|
|
||||||
|
object UserProfileReportsFeedFilter: FeedFilter<Note>() {
|
||||||
|
var user: User? = null
|
||||||
|
|
||||||
|
fun loadUserProfile(userId: String) {
|
||||||
|
user = LocalCache.getOrCreateUser(userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun feed(): List<Note> {
|
||||||
|
return user?.reports?.values?.flatten()?.sortedBy { it.event?.createdAt }?.reversed() ?: emptyList()
|
||||||
|
}
|
||||||
|
}
|
@@ -105,8 +105,9 @@ fun NoteCompose(
|
|||||||
|
|
||||||
var moreActionsExpanded by remember { mutableStateOf(false) }
|
var moreActionsExpanded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
val noteEvent = note?.event
|
||||||
|
|
||||||
if (note?.event == null) {
|
if (noteEvent == null) {
|
||||||
BlankNote(modifier.combinedClickable(
|
BlankNote(modifier.combinedClickable(
|
||||||
onClick = { },
|
onClick = { },
|
||||||
onLongClick = { popupExpanded = true },
|
onLongClick = { popupExpanded = true },
|
||||||
@@ -127,7 +128,7 @@ fun NoteCompose(
|
|||||||
routeForLastRead?.let {
|
routeForLastRead?.let {
|
||||||
val lastTime = NotificationCache.load(it, context)
|
val lastTime = NotificationCache.load(it, context)
|
||||||
|
|
||||||
val createdAt = note.event?.createdAt
|
val createdAt = noteEvent.createdAt
|
||||||
if (createdAt != null) {
|
if (createdAt != null) {
|
||||||
NotificationCache.markAsRead(it, createdAt, context)
|
NotificationCache.markAsRead(it, createdAt, context)
|
||||||
isNew = createdAt > lastTime
|
isNew = createdAt > lastTime
|
||||||
@@ -138,7 +139,7 @@ fun NoteCompose(
|
|||||||
Column(modifier =
|
Column(modifier =
|
||||||
modifier.combinedClickable(
|
modifier.combinedClickable(
|
||||||
onClick = {
|
onClick = {
|
||||||
if (note.event !is ChannelMessageEvent) {
|
if (noteEvent !is ChannelMessageEvent) {
|
||||||
navController.navigate("Note/${note.idHex}"){
|
navController.navigate("Note/${note.idHex}"){
|
||||||
launchSingleTop = true
|
launchSingleTop = true
|
||||||
}
|
}
|
||||||
@@ -174,7 +175,7 @@ fun NoteCompose(
|
|||||||
|
|
||||||
NoteAuthorPicture(note, navController, account.userProfile(), 55.dp)
|
NoteAuthorPicture(note, navController, account.userProfile(), 55.dp)
|
||||||
|
|
||||||
if (note.event is RepostEvent) {
|
if (noteEvent is RepostEvent) {
|
||||||
note.replyTo?.lastOrNull()?.let {
|
note.replyTo?.lastOrNull()?.let {
|
||||||
Box(
|
Box(
|
||||||
Modifier
|
Modifier
|
||||||
@@ -190,7 +191,7 @@ fun NoteCompose(
|
|||||||
|
|
||||||
// boosted picture
|
// boosted picture
|
||||||
val baseChannel = note.channel
|
val baseChannel = note.channel
|
||||||
if (note.event is ChannelMessageEvent && baseChannel != null) {
|
if (noteEvent is ChannelMessageEvent && baseChannel != null) {
|
||||||
val channelState by baseChannel.live.observeAsState()
|
val channelState by baseChannel.live.observeAsState()
|
||||||
val channel = channelState?.channel
|
val channel = channelState?.channel
|
||||||
|
|
||||||
@@ -222,7 +223,7 @@ fun NoteCompose(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (note.event is RepostEvent) {
|
if (noteEvent is RepostEvent) {
|
||||||
note.replyTo?.lastOrNull()?.let {
|
note.replyTo?.lastOrNull()?.let {
|
||||||
RelayBadges(it)
|
RelayBadges(it)
|
||||||
}
|
}
|
||||||
@@ -236,9 +237,9 @@ fun NoteCompose(
|
|||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
NoteUsernameDisplay(note, Modifier.weight(1f))
|
NoteUsernameDisplay(note, Modifier.weight(1f))
|
||||||
|
|
||||||
if (note.event !is RepostEvent) {
|
if (noteEvent !is RepostEvent) {
|
||||||
Text(
|
Text(
|
||||||
timeAgo(note.event?.createdAt),
|
timeAgo(noteEvent.createdAt),
|
||||||
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
|
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
|
||||||
maxLines = 1
|
maxLines = 1
|
||||||
)
|
)
|
||||||
@@ -265,15 +266,15 @@ fun NoteCompose(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (note.event is TextNoteEvent && (note.replyTo != null || note.mentions != null)) {
|
if (noteEvent is TextNoteEvent && (note.replyTo != null || note.mentions != null)) {
|
||||||
ReplyInformation(note.replyTo, note.mentions, navController)
|
ReplyInformation(note.replyTo, note.mentions, navController)
|
||||||
} else if (note.event is ChannelMessageEvent && (note.replyTo != null || note.mentions != null)) {
|
} else if (noteEvent is ChannelMessageEvent && (note.replyTo != null || note.mentions != null)) {
|
||||||
note.channel?.let {
|
note.channel?.let {
|
||||||
ReplyInformationChannel(note.replyTo, note.mentions, it, navController)
|
ReplyInformationChannel(note.replyTo, note.mentions, it, navController)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (note.event is ReactionEvent || note.event is RepostEvent) {
|
if (noteEvent is ReactionEvent || noteEvent is RepostEvent) {
|
||||||
note.replyTo?.lastOrNull()?.let {
|
note.replyTo?.lastOrNull()?.let {
|
||||||
NoteCompose(
|
NoteCompose(
|
||||||
it,
|
it,
|
||||||
@@ -285,16 +286,35 @@ fun NoteCompose(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reposts have trash in their contents.
|
// Reposts have trash in their contents.
|
||||||
if (note.event is ReactionEvent) {
|
if (noteEvent is ReactionEvent) {
|
||||||
val refactorReactionText =
|
val refactorReactionText =
|
||||||
if (note.event?.content == "+") "❤" else note.event?.content ?: " "
|
if (noteEvent.content == "+") "❤" else noteEvent.content ?: " "
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = refactorReactionText
|
text = refactorReactionText
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
} else if (noteEvent is ReportEvent) {
|
||||||
|
val reportType = noteEvent.reportType.map {
|
||||||
|
when (it) {
|
||||||
|
ReportEvent.ReportType.EXPLICIT -> "Explicit Content"
|
||||||
|
ReportEvent.ReportType.SPAM -> "Spam"
|
||||||
|
ReportEvent.ReportType.IMPERSONATION -> "Impersonation"
|
||||||
|
ReportEvent.ReportType.ILLEGAL -> "Illegal Behavior"
|
||||||
|
else -> "Unkown"
|
||||||
|
}
|
||||||
|
}.joinToString(", ")
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = reportType
|
||||||
|
)
|
||||||
|
|
||||||
|
Divider(
|
||||||
|
modifier = Modifier.padding(top = 10.dp),
|
||||||
|
thickness = 0.25.dp
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
val eventContent = note.event?.content
|
val eventContent = noteEvent.content
|
||||||
val canPreview = note.author == account.userProfile()
|
val canPreview = note.author == account.userProfile()
|
||||||
|| (note.author?.let { account.userProfile().isFollowing(it) } ?: true )
|
|| (note.author?.let { account.userProfile().isFollowing(it) } ?: true )
|
||||||
|| !noteForReports.hasAnyReports()
|
|| !noteForReports.hasAnyReports()
|
||||||
@@ -303,7 +323,7 @@ fun NoteCompose(
|
|||||||
TranslateableRichTextViewer(
|
TranslateableRichTextViewer(
|
||||||
eventContent,
|
eventContent,
|
||||||
canPreview,
|
canPreview,
|
||||||
note.event?.tags,
|
noteEvent.tags,
|
||||||
accountViewModel,
|
accountViewModel,
|
||||||
navController
|
navController
|
||||||
)
|
)
|
||||||
|
@@ -58,6 +58,7 @@ import com.vitorpamplona.amethyst.ui.components.InvoiceRequest
|
|||||||
import com.vitorpamplona.amethyst.ui.dal.UserProfileFollowersFeedFilter
|
import com.vitorpamplona.amethyst.ui.dal.UserProfileFollowersFeedFilter
|
||||||
import com.vitorpamplona.amethyst.ui.dal.UserProfileFollowsFeedFilter
|
import com.vitorpamplona.amethyst.ui.dal.UserProfileFollowsFeedFilter
|
||||||
import com.vitorpamplona.amethyst.ui.dal.UserProfileNoteFeedFilter
|
import com.vitorpamplona.amethyst.ui.dal.UserProfileNoteFeedFilter
|
||||||
|
import com.vitorpamplona.amethyst.ui.dal.UserProfileReportsFeedFilter
|
||||||
import com.vitorpamplona.amethyst.ui.dal.UserProfileZapsFeedFilter
|
import com.vitorpamplona.amethyst.ui.dal.UserProfileZapsFeedFilter
|
||||||
import com.vitorpamplona.amethyst.ui.note.UserPicture
|
import com.vitorpamplona.amethyst.ui.note.UserPicture
|
||||||
import com.vitorpamplona.amethyst.ui.note.showAmount
|
import com.vitorpamplona.amethyst.ui.note.showAmount
|
||||||
@@ -79,6 +80,7 @@ fun ProfileScreen(userId: String?, accountViewModel: AccountViewModel, navContro
|
|||||||
UserProfileFollowersFeedFilter.loadUserProfile(account, userId)
|
UserProfileFollowersFeedFilter.loadUserProfile(account, userId)
|
||||||
UserProfileFollowsFeedFilter.loadUserProfile(account, userId)
|
UserProfileFollowsFeedFilter.loadUserProfile(account, userId)
|
||||||
UserProfileZapsFeedFilter.loadUserProfile(userId)
|
UserProfileZapsFeedFilter.loadUserProfile(userId)
|
||||||
|
UserProfileReportsFeedFilter.loadUserProfile(userId)
|
||||||
|
|
||||||
NostrUserProfileDataSource.loadUserProfile(userId)
|
NostrUserProfileDataSource.loadUserProfile(userId)
|
||||||
|
|
||||||
@@ -101,6 +103,9 @@ fun ProfileScreen(userId: String?, accountViewModel: AccountViewModel, navContro
|
|||||||
lifeCycleOwner.lifecycle.addObserver(observer)
|
lifeCycleOwner.lifecycle.addObserver(observer)
|
||||||
onDispose {
|
onDispose {
|
||||||
lifeCycleOwner.lifecycle.removeObserver(observer)
|
lifeCycleOwner.lifecycle.removeObserver(observer)
|
||||||
|
println("Profile Dispose")
|
||||||
|
NostrUserProfileDataSource.loadUserProfile(null)
|
||||||
|
NostrUserProfileDataSource.stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,6 +208,17 @@ fun ProfileScreen(userId: String?, accountViewModel: AccountViewModel, navContro
|
|||||||
Tab(
|
Tab(
|
||||||
selected = pagerState.currentPage == 4,
|
selected = pagerState.currentPage == 4,
|
||||||
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(4) } },
|
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(4) } },
|
||||||
|
text = {
|
||||||
|
val userState by baseUser.liveReports.observeAsState()
|
||||||
|
val userReports = userState?.user?.reports?.values?.flatten()?.count()
|
||||||
|
|
||||||
|
Text(text = "${userReports} Reports")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Tab(
|
||||||
|
selected = pagerState.currentPage == 5,
|
||||||
|
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(5) } },
|
||||||
text = {
|
text = {
|
||||||
val userState by baseUser.liveRelays.observeAsState()
|
val userState by baseUser.liveRelays.observeAsState()
|
||||||
val userRelaysBeingUsed =
|
val userRelaysBeingUsed =
|
||||||
@@ -216,7 +232,7 @@ fun ProfileScreen(userId: String?, accountViewModel: AccountViewModel, navContro
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
HorizontalPager(
|
HorizontalPager(
|
||||||
count = 5,
|
count = 6,
|
||||||
state = pagerState,
|
state = pagerState,
|
||||||
modifier = with(LocalDensity.current) {
|
modifier = with(LocalDensity.current) {
|
||||||
Modifier.height((columnSize.height - tabsSize.height).toDp())
|
Modifier.height((columnSize.height - tabsSize.height).toDp())
|
||||||
@@ -227,7 +243,8 @@ fun ProfileScreen(userId: String?, accountViewModel: AccountViewModel, navContro
|
|||||||
1 -> TabFollows(baseUser, accountViewModel, navController)
|
1 -> TabFollows(baseUser, accountViewModel, navController)
|
||||||
2 -> TabFollowers(baseUser, accountViewModel, navController)
|
2 -> TabFollowers(baseUser, accountViewModel, navController)
|
||||||
3 -> TabReceivedZaps(baseUser, accountViewModel, navController)
|
3 -> TabReceivedZaps(baseUser, accountViewModel, navController)
|
||||||
4 -> TabRelays(baseUser, accountViewModel, navController)
|
4 -> TabReports(baseUser, accountViewModel, navController)
|
||||||
|
5 -> TabRelays(baseUser, accountViewModel, navController)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -515,6 +532,26 @@ fun TabReceivedZaps(user: User, accountViewModel: AccountViewModel, navControlle
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun TabReports(user: User, accountViewModel: AccountViewModel, navController: NavController) {
|
||||||
|
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||||
|
if (accountState != null) {
|
||||||
|
val feedViewModel: NostrUserProfileReportFeedViewModel = viewModel()
|
||||||
|
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
feedViewModel.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(Modifier.fillMaxHeight()) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(vertical = 0.dp)
|
||||||
|
) {
|
||||||
|
FeedView(feedViewModel, accountViewModel, navController, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TabRelays(user: User, accountViewModel: AccountViewModel, navController: NavController) {
|
fun TabRelays(user: User, accountViewModel: AccountViewModel, navController: NavController) {
|
||||||
val feedViewModel: RelayFeedViewModel = viewModel()
|
val feedViewModel: RelayFeedViewModel = viewModel()
|
||||||
|
Reference in New Issue
Block a user