From 2b7ef79d21e83084471ef8a9f8bf14dbde676dfe Mon Sep 17 00:00:00 2001 From: Believethehype <1097224+believethehype@users.noreply.github.com> Date: Mon, 13 May 2024 21:57:33 +0200 Subject: [PATCH] send dvm id to render list --- .../ui/dal/NIP90ContentDiscoveryFilter.kt | 46 +++++++++ .../amethyst/ui/navigation/AppNavigation.kt | 16 ++++ .../amethyst/ui/navigation/AppTopBar.kt | 2 + .../amethyst/ui/navigation/Routes.kt | 8 ++ .../amethyst/ui/note/NoteCompose.kt | 19 ++-- .../amethyst/ui/screen/FeedViewModel.kt | 10 ++ .../loggedIn/NIP90ContentDiscoveryScreen.kt | 96 +++++++++++++++++++ 7 files changed, 190 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/com/vitorpamplona/amethyst/ui/dal/NIP90ContentDiscoveryFilter.kt create mode 100644 app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NIP90ContentDiscoveryScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/NIP90ContentDiscoveryFilter.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/NIP90ContentDiscoveryFilter.kt new file mode 100644 index 000000000..25161069a --- /dev/null +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/NIP90ContentDiscoveryFilter.kt @@ -0,0 +1,46 @@ +/** + * 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.vitorpamplona.amethyst.ui.dal + +import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.model.LocalCache +import com.vitorpamplona.amethyst.model.Note + +class NIP90ContentDiscoveryFilter(val account: Account) : FeedFilter() { + override fun feedKey(): String { + return account.userProfile().latestBookmarkList?.id ?: "" + } + + // TODO + override fun feed(): List { + val bookmarks = account.userProfile().latestBookmarkList + + val notes = + bookmarks?.taggedEvents()?.mapNotNull { LocalCache.checkGetOrCreateNote(it) } ?: emptyList() + val addresses = + bookmarks?.taggedAddresses()?.map { LocalCache.getOrCreateAddressableNote(it) } ?: emptyList() + + return notes + .plus(addresses) + .toSet() + .sortedWith(DefaultFeedOrder) + } +} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt index ebbcc0ff5..e16d97ba3 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt @@ -68,6 +68,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.HashtagScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.HiddenUsersScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.HomeScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.LoadRedirectScreen +import com.vitorpamplona.amethyst.ui.screen.loggedIn.NIP90ContentDiscoveryScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.NotificationScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.ProfileScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.SearchScreen @@ -218,8 +219,23 @@ fun AppNavigation( composable(Route.BlockedUsers.route, content = { HiddenUsersScreen(accountViewModel, nav) }) composable(Route.Bookmarks.route, content = { BookmarkListScreen(accountViewModel, nav) }) + composable(Route.Drafts.route, content = { DraftListScreen(accountViewModel, nav) }) + Route.ContentDiscovery.let { route -> + composable( + route.route, + route.arguments, + content = { + NIP90ContentDiscoveryScreen( + DVMID = it.arguments?.getString("id"), + accountViewModel = accountViewModel, + nav = nav, + ) + }, + ) + } + Route.Profile.let { route -> composable( route.route, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt index 32974b149..268d043f4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt @@ -188,6 +188,8 @@ private fun RenderTopRouteBar( Route.Settings.base -> TopBarWithBackButton(stringResource(id = R.string.application_preferences), navPopBack) Route.Bookmarks.base -> TopBarWithBackButton(stringResource(id = R.string.bookmarks), navPopBack) Route.Drafts.base -> TopBarWithBackButton(stringResource(id = R.string.drafts), navPopBack) + Route.ContentDiscovery.base -> TopBarWithBackButton(stringResource(id = R.string.discover_content), navPopBack) + else -> { if (id != null) { when (currentRoute) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt index 0d5ccb18e..b9d0089c8 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt @@ -148,6 +148,14 @@ sealed class Route( contentDescriptor = R.string.route_home, ) + object ContentDiscovery : + Route( + icon = R.drawable.ic_bookmarks, + contentDescriptor = R.string.discover_content, + route = "ContentDiscovery/{id}", + arguments = listOf(navArgument("id") { type = NavType.StringType }).toImmutableList(), + ) + object Drafts : Route( route = "Drafts", diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index 5a8ea4785..8b0d0dc87 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -398,13 +398,18 @@ fun ClickableNote( .combinedClickable( onClick = { scope.launch { - val redirectToNote = - if (baseNote.event is RepostEvent || baseNote.event is GenericRepostEvent) { - baseNote.replyTo?.lastOrNull() ?: baseNote - } else { - baseNote - } - routeFor(redirectToNote, accountViewModel.userProfile())?.let { nav(it) } + if (baseNote.event is AppDefinitionEvent) { + // nav(Route.ContentDiscovery.route + "/${(baseNote.event as AppDefinitionEvent).pubKey()}") + nav("ContentDiscovery/${(baseNote.event as AppDefinitionEvent).pubKey()}") + } else { + val redirectToNote = + if (baseNote.event is RepostEvent || baseNote.event is GenericRepostEvent) { + baseNote.replyTo?.lastOrNull() ?: baseNote + } else { + baseNote + } + routeFor(redirectToNote, accountViewModel.userProfile())?.let { nav(it) } + } } }, onLongClick = showPopup, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt index 58d8dec22..a10a8a1a0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt @@ -281,6 +281,16 @@ class NostrBookmarkPrivateFeedViewModel(val account: Account) : } } +@Stable +class NostrNIP90ContentDiscoveryFeedViewModel(val account: Account) : + FeedViewModel(BookmarkPrivateFeedFilter(account)) { + class Factory(val account: Account) : ViewModelProvider.Factory { + override fun create(modelClass: Class): NostrNIP90ContentDiscoveryFeedViewModel { + return NostrNIP90ContentDiscoveryFeedViewModel(account) as NostrNIP90ContentDiscoveryFeedViewModel + } + } +} + @Stable class NostrDraftEventsFeedViewModel(val account: Account) : FeedViewModel(DraftEventsFeedFilter(account)) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NIP90ContentDiscoveryScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NIP90ContentDiscoveryScreen.kt new file mode 100644 index 000000000..ee7fd853a --- /dev/null +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NIP90ContentDiscoveryScreen.kt @@ -0,0 +1,96 @@ +/** + * 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.vitorpamplona.amethyst.ui.screen.loggedIn + +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Modifier +import androidx.lifecycle.viewmodel.compose.viewModel +import com.vitorpamplona.amethyst.ui.screen.NostrNIP90ContentDiscoveryFeedViewModel +import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView + +@Composable +fun NIP90ContentDiscoveryScreen( + DVMID: String?, + accountViewModel: AccountViewModel, + nav: (String) -> Unit, +) { + val resultFeedViewModel: NostrNIP90ContentDiscoveryFeedViewModel = + viewModel( + key = "NostrNIP90ContentDiscoveryFeedViewModel", + factory = NostrNIP90ContentDiscoveryFeedViewModel.Factory(accountViewModel.account), + ) + + val userState by accountViewModel.account.decryptBookmarks.observeAsState() + + LaunchedEffect(userState) { + resultFeedViewModel.invalidateData() + } + + RenderNostrNIP90ContentDiscoveryScreen(DVMID, accountViewModel, nav, resultFeedViewModel) +} + +@Composable +@OptIn(ExperimentalFoundationApi::class) +private fun RenderNostrNIP90ContentDiscoveryScreen( + DVMID: String?, + accountViewModel: AccountViewModel, + nav: (String) -> Unit, + resultFeedViewModel: NostrNIP90ContentDiscoveryFeedViewModel, +) { + Column(Modifier.fillMaxHeight()) { + val pagerState = rememberPagerState { 2 } + val coroutineScope = rememberCoroutineScope() + + if (DVMID != null) { + Text(text = "Debug: DVM KEY:\n " + DVMID) + } + // TODO Send KIND 5300 Event with p tag = DVMID + + /*note.event?.let { + ReactionEvent.create(emojiUrl, it, signer) { + Client.send(it) + LocalCache.consume(it) + } + }*/ + + // TODO PARSE AND LOAD RESULTS FROM KIND 6300 REPLY to resultfeedmodel (RN this still is the bookmark list) + // TODO Render Results + + HorizontalPager(state = pagerState) { + RefresheableFeedView( + resultFeedViewModel, + null, + accountViewModel = accountViewModel, + nav = nav, + ) + } + } +}