Adds the default bookmark option to be inside the bookmark list screen
This commit is contained in:
@@ -1554,6 +1554,15 @@ class Account(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun removeBookmark(note: Note) {
|
||||||
|
if (!isWriteable() || note.isDraft()) return
|
||||||
|
|
||||||
|
val event = bookmarkState.removeBookmark(note)
|
||||||
|
if (event != null) {
|
||||||
|
sendMyPublicAndPrivateOutbox(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun createAuthEvent(
|
suspend fun createAuthEvent(
|
||||||
relay: NormalizedRelayUrl,
|
relay: NormalizedRelayUrl,
|
||||||
challenge: String,
|
challenge: String,
|
||||||
|
|||||||
+25
@@ -20,6 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.model.nip51Lists
|
package com.vitorpamplona.amethyst.model.nip51Lists
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Stable
|
||||||
import com.vitorpamplona.amethyst.model.AddressableNote
|
import com.vitorpamplona.amethyst.model.AddressableNote
|
||||||
import com.vitorpamplona.amethyst.model.LocalCache
|
import com.vitorpamplona.amethyst.model.LocalCache
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
@@ -40,7 +41,9 @@ import kotlinx.coroutines.flow.flowOn
|
|||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onStart
|
import kotlinx.coroutines.flow.onStart
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
import java.lang.reflect.Modifier.isPrivate
|
||||||
|
|
||||||
|
@Stable
|
||||||
class BookmarkListState(
|
class BookmarkListState(
|
||||||
val signer: NostrSigner,
|
val signer: NostrSigner,
|
||||||
val cache: LocalCache,
|
val cache: LocalCache,
|
||||||
@@ -274,4 +277,26 @@ class BookmarkListState(
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun removeBookmark(note: Note): BookmarkListEvent? {
|
||||||
|
val bookmarkList = getBookmarkList()
|
||||||
|
|
||||||
|
return if (bookmarkList != null) {
|
||||||
|
if (note is AddressableNote) {
|
||||||
|
BookmarkListEvent.remove(
|
||||||
|
earlierVersion = bookmarkList,
|
||||||
|
bookmarkIdTag = AddressBookmark(note.address, note.relayHintUrl()),
|
||||||
|
signer = signer,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
BookmarkListEvent.remove(
|
||||||
|
earlierVersion = bookmarkList,
|
||||||
|
bookmarkIdTag = EventBookmark(note.idHex, note.relayHintUrl()),
|
||||||
|
signer = signer,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,12 +58,12 @@ import com.vitorpamplona.amethyst.ui.note.nip22Comments.ReplyCommentPostScreen
|
|||||||
import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel
|
import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountSwitcherAndLeftDrawerLayout
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountSwitcherAndLeftDrawerLayout
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.default.BookmarkListScreen
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.display.BookmarkGroupScreen
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.display.BookmarkGroupScreen
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.list.ListOfBookmarkGroupsScreen
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.list.ListOfBookmarkGroupsScreen
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.list.metadata.BookmarkGroupMetadataScreen
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.list.metadata.BookmarkGroupMetadataScreen
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.membershipManagement.ArticleBookmarkListManagementScreen
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.membershipManagement.ArticleBookmarkListManagementScreen
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.membershipManagement.PostBookmarkListManagementScreen
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.membershipManagement.PostBookmarkListManagementScreen
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarks.BookmarkListScreen
|
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.ChatroomByAuthorScreen
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.ChatroomByAuthorScreen
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.ChatroomScreen
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.ChatroomScreen
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.NewGroupDMScreen
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.NewGroupDMScreen
|
||||||
|
|||||||
-9
@@ -46,7 +46,6 @@ import androidx.compose.material.icons.Icons
|
|||||||
import androidx.compose.material.icons.automirrored.filled.Send
|
import androidx.compose.material.icons.automirrored.filled.Send
|
||||||
import androidx.compose.material.icons.filled.AccountCircle
|
import androidx.compose.material.icons.filled.AccountCircle
|
||||||
import androidx.compose.material.icons.filled.Delete
|
import androidx.compose.material.icons.filled.Delete
|
||||||
import androidx.compose.material.icons.outlined.BookmarkBorder
|
|
||||||
import androidx.compose.material.icons.outlined.CloudUpload
|
import androidx.compose.material.icons.outlined.CloudUpload
|
||||||
import androidx.compose.material.icons.outlined.CollectionsBookmark
|
import androidx.compose.material.icons.outlined.CollectionsBookmark
|
||||||
import androidx.compose.material.icons.outlined.Drafts
|
import androidx.compose.material.icons.outlined.Drafts
|
||||||
@@ -458,14 +457,6 @@ fun ListContent(
|
|||||||
|
|
||||||
NavigationRow(
|
NavigationRow(
|
||||||
title = R.string.bookmarks,
|
title = R.string.bookmarks,
|
||||||
icon = Icons.Outlined.BookmarkBorder,
|
|
||||||
tint = MaterialTheme.colorScheme.onBackground,
|
|
||||||
nav = nav,
|
|
||||||
route = Route.Bookmarks,
|
|
||||||
)
|
|
||||||
|
|
||||||
NavigationRow(
|
|
||||||
title = R.string.bookmark_lists,
|
|
||||||
icon = Icons.Outlined.CollectionsBookmark,
|
icon = Icons.Outlined.CollectionsBookmark,
|
||||||
tint = MaterialTheme.colorScheme.onBackground,
|
tint = MaterialTheme.colorScheme.onBackground,
|
||||||
nav = nav,
|
nav = nav,
|
||||||
|
|||||||
+4
-4
@@ -18,7 +18,7 @@
|
|||||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
* 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.
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarks
|
package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.default
|
||||||
|
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@@ -44,8 +44,8 @@ import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
|||||||
import com.vitorpamplona.amethyst.ui.navigation.topbars.TopBarWithBackButton
|
import com.vitorpamplona.amethyst.ui.navigation.topbars.TopBarWithBackButton
|
||||||
import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView
|
import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarks.dal.BookmarkPrivateFeedViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.default.dal.BookmarkPrivateFeedViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarks.dal.BookmarkPublicFeedViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.default.dal.BookmarkPublicFeedViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.stringRes
|
import com.vitorpamplona.amethyst.ui.stringRes
|
||||||
import com.vitorpamplona.amethyst.ui.theme.TabRowHeight
|
import com.vitorpamplona.amethyst.ui.theme.TabRowHeight
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -93,7 +93,7 @@ private fun RenderBookmarkScreen(
|
|||||||
isInvertedLayout = false,
|
isInvertedLayout = false,
|
||||||
topBar = {
|
topBar = {
|
||||||
Column {
|
Column {
|
||||||
TopBarWithBackButton(stringRes(id = R.string.bookmarks), nav::popBack)
|
TopBarWithBackButton(stringRes(id = R.string.bookmarks_title), nav::popBack)
|
||||||
TabRow(
|
TabRow(
|
||||||
containerColor = Color.Transparent,
|
containerColor = Color.Transparent,
|
||||||
contentColor = MaterialTheme.colorScheme.onBackground,
|
contentColor = MaterialTheme.colorScheme.onBackground,
|
||||||
+1
-1
@@ -18,7 +18,7 @@
|
|||||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
* 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.
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarks.dal
|
package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.default.dal
|
||||||
|
|
||||||
import com.vitorpamplona.amethyst.model.Account
|
import com.vitorpamplona.amethyst.model.Account
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
+1
-1
@@ -18,7 +18,7 @@
|
|||||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
* 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.
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarks.dal
|
package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.default.dal
|
||||||
|
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
+1
-1
@@ -18,7 +18,7 @@
|
|||||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
* 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.
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarks.dal
|
package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.default.dal
|
||||||
|
|
||||||
import com.vitorpamplona.amethyst.model.Account
|
import com.vitorpamplona.amethyst.model.Account
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
+1
-1
@@ -18,7 +18,7 @@
|
|||||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
* 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.
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarks.dal
|
package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.default.dal
|
||||||
|
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
+2
-2
@@ -42,7 +42,6 @@ import androidx.compose.material3.Scaffold
|
|||||||
import androidx.compose.material3.Tab
|
import androidx.compose.material3.Tab
|
||||||
import androidx.compose.material3.TabRow
|
import androidx.compose.material3.TabRow
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@@ -59,6 +58,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
|||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.ui.components.ClickableBox
|
import com.vitorpamplona.amethyst.ui.components.ClickableBox
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||||
|
import com.vitorpamplona.amethyst.ui.navigation.topbars.ShorterTopAppBar
|
||||||
import com.vitorpamplona.amethyst.ui.note.ArrowBackIcon
|
import com.vitorpamplona.amethyst.ui.note.ArrowBackIcon
|
||||||
import com.vitorpamplona.amethyst.ui.note.VerticalDotsIcon
|
import com.vitorpamplona.amethyst.ui.note.VerticalDotsIcon
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
@@ -118,7 +118,7 @@ fun BookmarkGroupScreenView(
|
|||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
Column {
|
Column {
|
||||||
TopAppBar(
|
ShorterTopAppBar(
|
||||||
title = {
|
title = {
|
||||||
TitleAndDescription(bookmarkGroupViewModel)
|
TitleAndDescription(bookmarkGroupViewModel)
|
||||||
},
|
},
|
||||||
|
|||||||
+75
-33
@@ -20,34 +20,43 @@
|
|||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.list
|
package com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.list
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.outlined.BookmarkBorder
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.ListItem
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
|
import com.vitorpamplona.amethyst.model.nip51Lists.BookmarkListState
|
||||||
import com.vitorpamplona.amethyst.model.nip51Lists.labeledBookmarkLists.LabeledBookmarkList
|
import com.vitorpamplona.amethyst.model.nip51Lists.labeledBookmarkLists.LabeledBookmarkList
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.BookmarkType
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.BookmarkType
|
||||||
import com.vitorpamplona.amethyst.ui.stringRes
|
import com.vitorpamplona.amethyst.ui.stringRes
|
||||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||||
import com.vitorpamplona.amethyst.ui.theme.FeedPadding
|
import com.vitorpamplona.amethyst.ui.theme.FeedPadding
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size40dp
|
import com.vitorpamplona.amethyst.ui.theme.Size40Modifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ListOfBookmarkGroupsFeedView(
|
fun ListOfBookmarkGroupsFeedView(
|
||||||
|
defaultBookmarks: BookmarkListState,
|
||||||
groupListFeedSource: StateFlow<List<LabeledBookmarkList>>,
|
groupListFeedSource: StateFlow<List<LabeledBookmarkList>>,
|
||||||
|
openDefaultBookmarks: () -> Unit,
|
||||||
onOpenItem: (String, BookmarkType) -> Unit,
|
onOpenItem: (String, BookmarkType) -> Unit,
|
||||||
onRenameItem: (targetBookmarkGroup: LabeledBookmarkList) -> Unit,
|
onRenameItem: (targetBookmarkGroup: LabeledBookmarkList) -> Unit,
|
||||||
onItemDescriptionChange: (bookmarkGroup: LabeledBookmarkList) -> Unit,
|
onItemDescriptionChange: (bookmarkGroup: LabeledBookmarkList) -> Unit,
|
||||||
@@ -56,40 +65,73 @@ fun ListOfBookmarkGroupsFeedView(
|
|||||||
) {
|
) {
|
||||||
val bookmarkGroupFeedState by groupListFeedSource.collectAsStateWithLifecycle()
|
val bookmarkGroupFeedState by groupListFeedSource.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
if (bookmarkGroupFeedState.isEmpty()) {
|
LazyColumn(
|
||||||
BookmarkGroupsFeedEmpty(message = stringRes(R.string.bookmark_list_feed_empty_msg))
|
state = rememberLazyListState(),
|
||||||
} else {
|
contentPadding = FeedPadding,
|
||||||
LazyColumn(
|
) {
|
||||||
state = rememberLazyListState(),
|
item {
|
||||||
contentPadding = FeedPadding,
|
DefaultBookmarkList(defaultBookmarks, openDefaultBookmarks)
|
||||||
) {
|
HorizontalDivider(thickness = DividerThickness)
|
||||||
itemsIndexed(
|
}
|
||||||
bookmarkGroupFeedState,
|
|
||||||
key = { _: Int, item: LabeledBookmarkList -> item.identifier },
|
itemsIndexed(
|
||||||
) { _, groupItem ->
|
bookmarkGroupFeedState,
|
||||||
BookmarkGroupItem(
|
key = { _: Int, item: LabeledBookmarkList -> item.identifier },
|
||||||
modifier = Modifier.fillMaxSize().animateItem(),
|
) { _, groupItem ->
|
||||||
bookmarkList = groupItem,
|
BookmarkGroupItem(
|
||||||
onClick = { bookmarkType -> onOpenItem(groupItem.identifier, bookmarkType) },
|
modifier = Modifier.fillMaxSize().animateItem(),
|
||||||
onRename = { onRenameItem(groupItem) },
|
bookmarkList = groupItem,
|
||||||
onDescriptionChange = { onItemDescriptionChange(groupItem) },
|
onClick = { bookmarkType -> onOpenItem(groupItem.identifier, bookmarkType) },
|
||||||
onClone = { cloneName, cloneDescription -> onItemClone(groupItem, cloneName, cloneDescription) },
|
onRename = { onRenameItem(groupItem) },
|
||||||
onDelete = { onDeleteItem(groupItem) },
|
onDescriptionChange = { onItemDescriptionChange(groupItem) },
|
||||||
)
|
onClone = { cloneName, cloneDescription -> onItemClone(groupItem, cloneName, cloneDescription) },
|
||||||
HorizontalDivider(thickness = DividerThickness)
|
onDelete = { onDeleteItem(groupItem) },
|
||||||
}
|
)
|
||||||
|
HorizontalDivider(thickness = DividerThickness)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BookmarkGroupsFeedEmpty(message: String = stringRes(R.string.feed_is_empty)) {
|
fun DefaultBookmarkList(
|
||||||
Column(
|
defaultBookmarks: BookmarkListState,
|
||||||
Modifier.fillMaxSize().padding(horizontal = Size40dp),
|
openDefaultBookmarks: () -> Unit,
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
) {
|
||||||
verticalArrangement = Arrangement.Center,
|
val bookmarkState by defaultBookmarks.bookmarks.collectAsStateWithLifecycle()
|
||||||
) {
|
|
||||||
Text(message)
|
ListItem(
|
||||||
Spacer(modifier = StdVertSpacer)
|
modifier = Modifier.clickable(onClick = openDefaultBookmarks),
|
||||||
}
|
headlineContent = {
|
||||||
|
Text(stringRes(R.string.bookmarks_title), maxLines = 1, overflow = TextOverflow.Ellipsis)
|
||||||
|
},
|
||||||
|
supportingContent = {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
stringRes(R.string.bookmarks_explainer),
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
maxLines = 2,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
leadingContent = {
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Outlined.BookmarkBorder,
|
||||||
|
contentDescription = stringRes(R.string.bookmark_list_icon_label),
|
||||||
|
modifier = Size40Modifier,
|
||||||
|
)
|
||||||
|
Spacer(StdVertSpacer)
|
||||||
|
BookmarkMembershipStatusAndNumberDisplay(
|
||||||
|
modifier = Modifier.align(Alignment.CenterHorizontally),
|
||||||
|
postBookmarksSize = bookmarkState.public.size + bookmarkState.private.size,
|
||||||
|
articleBookmarksSize = 0,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -34,6 +34,7 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
|
import com.vitorpamplona.amethyst.model.nip51Lists.BookmarkListState
|
||||||
import com.vitorpamplona.amethyst.model.nip51Lists.labeledBookmarkLists.LabeledBookmarkList
|
import com.vitorpamplona.amethyst.model.nip51Lists.labeledBookmarkLists.LabeledBookmarkList
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
||||||
@@ -49,7 +50,9 @@ fun ListOfBookmarkGroupsScreen(
|
|||||||
nav: INav,
|
nav: INav,
|
||||||
) {
|
) {
|
||||||
ListOfBookmarkGroupsFeed(
|
ListOfBookmarkGroupsFeed(
|
||||||
|
defaultBookmarks = accountViewModel.account.bookmarkState,
|
||||||
listSource = accountViewModel.account.labeledBookmarkLists.listFeedFlow,
|
listSource = accountViewModel.account.labeledBookmarkLists.listFeedFlow,
|
||||||
|
openDefaultBookmarks = { nav.nav(Route.Bookmarks) },
|
||||||
addBookmarkGroup = { nav.nav(Route.BookmarkGroupMetadataEdit()) },
|
addBookmarkGroup = { nav.nav(Route.BookmarkGroupMetadataEdit()) },
|
||||||
openBookmarkGroup = { identifier, bookmarkType ->
|
openBookmarkGroup = { identifier, bookmarkType ->
|
||||||
nav.nav(Route.BookmarkGroupView(identifier, bookmarkType))
|
nav.nav(Route.BookmarkGroupView(identifier, bookmarkType))
|
||||||
@@ -84,7 +87,9 @@ fun ListOfBookmarkGroupsScreen(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ListOfBookmarkGroupsFeed(
|
fun ListOfBookmarkGroupsFeed(
|
||||||
|
defaultBookmarks: BookmarkListState,
|
||||||
listSource: StateFlow<List<LabeledBookmarkList>>,
|
listSource: StateFlow<List<LabeledBookmarkList>>,
|
||||||
|
openDefaultBookmarks: () -> Unit,
|
||||||
addBookmarkGroup: () -> Unit,
|
addBookmarkGroup: () -> Unit,
|
||||||
openBookmarkGroup: (identifier: String, bookmarkType: BookmarkType) -> Unit,
|
openBookmarkGroup: (identifier: String, bookmarkType: BookmarkType) -> Unit,
|
||||||
renameBookmarkGroup: (bookmarkGroup: LabeledBookmarkList) -> Unit,
|
renameBookmarkGroup: (bookmarkGroup: LabeledBookmarkList) -> Unit,
|
||||||
@@ -109,7 +114,9 @@ fun ListOfBookmarkGroupsFeed(
|
|||||||
).fillMaxHeight(),
|
).fillMaxHeight(),
|
||||||
) {
|
) {
|
||||||
ListOfBookmarkGroupsFeedView(
|
ListOfBookmarkGroupsFeedView(
|
||||||
|
defaultBookmarks = defaultBookmarks,
|
||||||
groupListFeedSource = listSource,
|
groupListFeedSource = listSource,
|
||||||
|
openDefaultBookmarks = openDefaultBookmarks,
|
||||||
onOpenItem = openBookmarkGroup,
|
onOpenItem = openBookmarkGroup,
|
||||||
onRenameItem = renameBookmarkGroup,
|
onRenameItem = renameBookmarkGroup,
|
||||||
onItemDescriptionChange = changeBookmarkGroupDescription,
|
onItemDescriptionChange = changeBookmarkGroupDescription,
|
||||||
|
|||||||
-105
@@ -1,105 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 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.bookmarkgroups.list
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.material3.AlertDialog
|
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.TextField
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import com.vitorpamplona.amethyst.R
|
|
||||||
import com.vitorpamplona.amethyst.ui.stringRes
|
|
||||||
import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun NewBookmarkGroupCreationDialog(
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
onDismiss: () -> Unit,
|
|
||||||
onCreateGroup: (name: String, description: String?) -> Unit,
|
|
||||||
) {
|
|
||||||
val newGroupName = remember { mutableStateOf("") }
|
|
||||||
val newGroupDescription = remember { mutableStateOf<String?>(null) }
|
|
||||||
|
|
||||||
AlertDialog(
|
|
||||||
modifier = modifier,
|
|
||||||
onDismissRequest = onDismiss,
|
|
||||||
title = {
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = "New Bookmark Group",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
text = {
|
|
||||||
Column(
|
|
||||||
verticalArrangement = Arrangement.spacedBy(5.dp),
|
|
||||||
) {
|
|
||||||
// For the new bookmark group name
|
|
||||||
TextField(
|
|
||||||
value = newGroupName.value,
|
|
||||||
onValueChange = { newGroupName.value = it },
|
|
||||||
label = {
|
|
||||||
Text(text = "Group name")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
Spacer(modifier = DoubleVertSpacer)
|
|
||||||
// For the group description
|
|
||||||
TextField(
|
|
||||||
value =
|
|
||||||
(if (newGroupDescription.value != null) newGroupDescription.value else "").toString(),
|
|
||||||
onValueChange = { newGroupDescription.value = it },
|
|
||||||
label = {
|
|
||||||
Text(text = "Group description(optional)")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
confirmButton = {
|
|
||||||
Button(
|
|
||||||
onClick = {
|
|
||||||
onCreateGroup(newGroupName.value, newGroupDescription.value)
|
|
||||||
onDismiss()
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
Text("Create Group")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dismissButton = {
|
|
||||||
Button(
|
|
||||||
onClick = onDismiss,
|
|
||||||
) {
|
|
||||||
Text(stringRes(R.string.cancel))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
+80
-45
@@ -44,7 +44,6 @@ import com.vitorpamplona.amethyst.ui.navigation.topbars.TopBarWithBackButton
|
|||||||
import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote
|
import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.BookmarkType
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.BookmarkType
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.list.BookmarkGroupsFeedEmpty
|
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.list.NewListButton
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.list.NewListButton
|
||||||
import com.vitorpamplona.amethyst.ui.stringRes
|
import com.vitorpamplona.amethyst.ui.stringRes
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.Address
|
import com.vitorpamplona.quartz.nip01Core.core.Address
|
||||||
@@ -75,8 +74,6 @@ private fun ListManagementView(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: INav,
|
nav: INav,
|
||||||
) {
|
) {
|
||||||
val bookmarkGroups by accountViewModel.account.labeledBookmarkLists.listFeedFlow
|
|
||||||
.collectAsStateWithLifecycle()
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
topBar = {
|
topBar = {
|
||||||
@@ -95,48 +92,86 @@ private fun ListManagementView(
|
|||||||
).consumeWindowInsets(contentPadding)
|
).consumeWindowInsets(contentPadding)
|
||||||
.imePadding(),
|
.imePadding(),
|
||||||
) {
|
) {
|
||||||
if (bookmarkGroups.isEmpty()) {
|
ListManagementViewBody(note, accountViewModel, nav)
|
||||||
BookmarkGroupsFeedEmpty(message = stringRes(R.string.bookmark_list_feed_empty_msg))
|
}
|
||||||
} else {
|
}
|
||||||
LazyColumn(
|
}
|
||||||
state = rememberLazyListState(),
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
@Composable
|
||||||
) {
|
private fun ListManagementViewBody(
|
||||||
itemsIndexed(items = bookmarkGroups, key = { _: Int, item: LabeledBookmarkList -> item.identifier }) { _, bookmarkList ->
|
note: AddressableNote,
|
||||||
val maybePublicBookmark = bookmarkList.publicArticleBookmarks.firstOrNull { it.address == note.address }
|
accountViewModel: AccountViewModel,
|
||||||
val maybePrivateBookmark = bookmarkList.privateArticleBookmarks.firstOrNull { it.address == note.address }
|
nav: INav,
|
||||||
BookmarkGroupManagementItem(
|
) {
|
||||||
modifier = Modifier.fillMaxWidth().animateItem(),
|
val bookmarkGroups by accountViewModel.account.labeledBookmarkLists.listFeedFlow
|
||||||
listTitle = bookmarkList.title,
|
.collectAsStateWithLifecycle()
|
||||||
isPublicMemberBookmark = maybePublicBookmark != null,
|
|
||||||
isPrivateMemberBookmark = maybePrivateBookmark != null,
|
val defaultBookmarks by accountViewModel.account.bookmarkState.bookmarks
|
||||||
totalPostBookmarkSize = bookmarkList.publicPostBookmarks.size + bookmarkList.privatePostBookmarks.size,
|
.collectAsStateWithLifecycle()
|
||||||
totalArticleBookmarkSize = bookmarkList.publicArticleBookmarks.size + bookmarkList.privateArticleBookmarks.size,
|
|
||||||
onClick = { nav.nav(Route.BookmarkGroupView(bookmarkList.identifier, BookmarkType.ArticleBookmark)) },
|
LazyColumn(
|
||||||
onAddBookmarkToGroup = { shouldBePrivate ->
|
state = rememberLazyListState(),
|
||||||
accountViewModel.launchSigner {
|
modifier = Modifier.fillMaxWidth(),
|
||||||
accountViewModel.account.labeledBookmarkLists.addBookmarkToList(
|
) {
|
||||||
bookmark = AddressBookmark(address = note.address, relayHint = note.relayHintUrl()),
|
item {
|
||||||
bookmarkListIdentifier = bookmarkList.identifier,
|
val maybePublicBookmark = defaultBookmarks.public.contains(note)
|
||||||
isBookmarkPrivate = shouldBePrivate,
|
val maybePrivateBookmark = defaultBookmarks.private.contains(note)
|
||||||
account = accountViewModel.account,
|
|
||||||
)
|
BookmarkGroupManagementItem(
|
||||||
}
|
modifier = Modifier.fillMaxWidth().animateItem(),
|
||||||
},
|
listTitle = stringRes(R.string.bookmarks_title),
|
||||||
onRemoveBookmarkFromGroup = {
|
isPublicMemberBookmark = maybePublicBookmark,
|
||||||
accountViewModel.launchSigner {
|
isPrivateMemberBookmark = maybePrivateBookmark,
|
||||||
accountViewModel.account.labeledBookmarkLists.removeBookmarkFromList(
|
totalPostBookmarkSize = defaultBookmarks.public.size + defaultBookmarks.private.size,
|
||||||
bookmark = AddressBookmark(address = note.address),
|
totalArticleBookmarkSize = 0,
|
||||||
bookmarkListIdentifier = bookmarkList.identifier,
|
onClick = {
|
||||||
isBookmarkPrivate = maybePrivateBookmark != null,
|
nav.nav(Route.Bookmarks)
|
||||||
account = accountViewModel.account,
|
},
|
||||||
)
|
onAddBookmarkToGroup = { shouldBePrivate ->
|
||||||
}
|
accountViewModel.launchSigner {
|
||||||
},
|
accountViewModel.account.addBookmark(note, shouldBePrivate)
|
||||||
)
|
}
|
||||||
}
|
},
|
||||||
}
|
onRemoveBookmarkFromGroup = {
|
||||||
}
|
accountViewModel.launchSigner {
|
||||||
|
accountViewModel.account.removeBookmark(note)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
itemsIndexed(items = bookmarkGroups, key = { _: Int, item: LabeledBookmarkList -> item.identifier }) { _, bookmarkList ->
|
||||||
|
val maybePublicBookmark = bookmarkList.publicArticleBookmarks.firstOrNull { it.address == note.address }
|
||||||
|
val maybePrivateBookmark = bookmarkList.privateArticleBookmarks.firstOrNull { it.address == note.address }
|
||||||
|
BookmarkGroupManagementItem(
|
||||||
|
modifier = Modifier.fillMaxWidth().animateItem(),
|
||||||
|
listTitle = bookmarkList.title,
|
||||||
|
isPublicMemberBookmark = maybePublicBookmark != null,
|
||||||
|
isPrivateMemberBookmark = maybePrivateBookmark != null,
|
||||||
|
totalPostBookmarkSize = bookmarkList.publicPostBookmarks.size + bookmarkList.privatePostBookmarks.size,
|
||||||
|
totalArticleBookmarkSize = bookmarkList.publicArticleBookmarks.size + bookmarkList.privateArticleBookmarks.size,
|
||||||
|
onClick = { nav.nav(Route.BookmarkGroupView(bookmarkList.identifier, BookmarkType.ArticleBookmark)) },
|
||||||
|
onAddBookmarkToGroup = { shouldBePrivate ->
|
||||||
|
accountViewModel.launchSigner {
|
||||||
|
accountViewModel.account.labeledBookmarkLists.addBookmarkToList(
|
||||||
|
bookmark = AddressBookmark(address = note.address, relayHint = note.relayHintUrl()),
|
||||||
|
bookmarkListIdentifier = bookmarkList.identifier,
|
||||||
|
isBookmarkPrivate = shouldBePrivate,
|
||||||
|
account = accountViewModel.account,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRemoveBookmarkFromGroup = {
|
||||||
|
accountViewModel.launchSigner {
|
||||||
|
accountViewModel.account.labeledBookmarkLists.removeBookmarkFromList(
|
||||||
|
bookmark = AddressBookmark(address = note.address),
|
||||||
|
bookmarkListIdentifier = bookmarkList.identifier,
|
||||||
|
isBookmarkPrivate = maybePrivateBookmark != null,
|
||||||
|
account = accountViewModel.account,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+82
-45
@@ -44,7 +44,8 @@ import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
|||||||
import com.vitorpamplona.amethyst.ui.navigation.topbars.TopBarWithBackButton
|
import com.vitorpamplona.amethyst.ui.navigation.topbars.TopBarWithBackButton
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.BookmarkType
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.BookmarkType
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.list.BookmarkGroupsFeedEmpty
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.membershipManagement.ListManagementView
|
||||||
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.membershipManagement.ListManagementViewBody
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.list.NewListButton
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.list.NewListButton
|
||||||
import com.vitorpamplona.amethyst.ui.stringRes
|
import com.vitorpamplona.amethyst.ui.stringRes
|
||||||
import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.EventBookmark
|
import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.EventBookmark
|
||||||
@@ -74,8 +75,6 @@ private fun ListManagementView(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: INav,
|
nav: INav,
|
||||||
) {
|
) {
|
||||||
val bookmarkGroups by accountViewModel.account.labeledBookmarkLists.listFeedFlow
|
|
||||||
.collectAsStateWithLifecycle()
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
topBar = {
|
topBar = {
|
||||||
@@ -94,48 +93,86 @@ private fun ListManagementView(
|
|||||||
).consumeWindowInsets(contentPadding)
|
).consumeWindowInsets(contentPadding)
|
||||||
.imePadding(),
|
.imePadding(),
|
||||||
) {
|
) {
|
||||||
if (bookmarkGroups.isEmpty()) {
|
ListManagementViewBody(note, accountViewModel, nav)
|
||||||
BookmarkGroupsFeedEmpty(message = stringRes(R.string.bookmark_list_feed_empty_msg))
|
}
|
||||||
} else {
|
}
|
||||||
LazyColumn(
|
}
|
||||||
state = rememberLazyListState(),
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
@Composable
|
||||||
) {
|
private fun ListManagementViewBody(
|
||||||
itemsIndexed(items = bookmarkGroups, key = { _: Int, item: LabeledBookmarkList -> item.identifier }) { _, bookmarkList ->
|
note: Note,
|
||||||
val maybePublicBookmark = bookmarkList.publicPostBookmarks.firstOrNull { it.eventId == note.idHex }
|
accountViewModel: AccountViewModel,
|
||||||
val maybePrivateBookmark = bookmarkList.privatePostBookmarks.firstOrNull { it.eventId == note.idHex }
|
nav: INav,
|
||||||
BookmarkGroupManagementItem(
|
) {
|
||||||
modifier = Modifier.fillMaxWidth().animateItem(),
|
val bookmarkGroups by accountViewModel.account.labeledBookmarkLists.listFeedFlow
|
||||||
listTitle = bookmarkList.title,
|
.collectAsStateWithLifecycle()
|
||||||
isPublicMemberBookmark = maybePublicBookmark != null,
|
|
||||||
isPrivateMemberBookmark = maybePrivateBookmark != null,
|
val defaultBookmarks by accountViewModel.account.bookmarkState.bookmarks
|
||||||
totalPostBookmarkSize = bookmarkList.publicPostBookmarks.size + bookmarkList.privatePostBookmarks.size,
|
.collectAsStateWithLifecycle()
|
||||||
totalArticleBookmarkSize = bookmarkList.publicArticleBookmarks.size + bookmarkList.privateArticleBookmarks.size,
|
|
||||||
onClick = { nav.nav(Route.BookmarkGroupView(bookmarkList.identifier, BookmarkType.PostBookmark)) },
|
LazyColumn(
|
||||||
onAddBookmarkToGroup = { shouldBePrivate ->
|
state = rememberLazyListState(),
|
||||||
accountViewModel.launchSigner {
|
modifier = Modifier.fillMaxWidth(),
|
||||||
accountViewModel.account.labeledBookmarkLists.addBookmarkToList(
|
) {
|
||||||
bookmark = EventBookmark(eventId = note.idHex, relay = note.relayHintUrl(), author = note.author?.pubkeyHex),
|
item {
|
||||||
bookmarkListIdentifier = bookmarkList.identifier,
|
val maybePublicBookmark = defaultBookmarks.public.contains(note)
|
||||||
isBookmarkPrivate = shouldBePrivate,
|
val maybePrivateBookmark = defaultBookmarks.private.contains(note)
|
||||||
account = accountViewModel.account,
|
|
||||||
)
|
BookmarkGroupManagementItem(
|
||||||
}
|
modifier = Modifier.fillMaxWidth().animateItem(),
|
||||||
},
|
listTitle = stringRes(R.string.bookmarks_title),
|
||||||
onRemoveBookmarkFromGroup = {
|
isPublicMemberBookmark = maybePublicBookmark,
|
||||||
accountViewModel.launchSigner {
|
isPrivateMemberBookmark = maybePrivateBookmark,
|
||||||
accountViewModel.account.labeledBookmarkLists.removeBookmarkFromList(
|
totalPostBookmarkSize = defaultBookmarks.public.size + defaultBookmarks.private.size,
|
||||||
bookmark = EventBookmark(eventId = note.idHex),
|
totalArticleBookmarkSize = 0,
|
||||||
bookmarkListIdentifier = bookmarkList.identifier,
|
onClick = {
|
||||||
isBookmarkPrivate = maybePrivateBookmark != null,
|
nav.nav(Route.Bookmarks)
|
||||||
account = accountViewModel.account,
|
},
|
||||||
)
|
onAddBookmarkToGroup = { shouldBePrivate ->
|
||||||
}
|
accountViewModel.launchSigner {
|
||||||
},
|
accountViewModel.account.addBookmark(note, shouldBePrivate)
|
||||||
)
|
}
|
||||||
}
|
},
|
||||||
}
|
onRemoveBookmarkFromGroup = {
|
||||||
}
|
accountViewModel.launchSigner {
|
||||||
|
accountViewModel.account.removeBookmark(note)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
itemsIndexed(items = bookmarkGroups, key = { _: Int, item: LabeledBookmarkList -> item.identifier }) { _, bookmarkList ->
|
||||||
|
val maybePublicBookmark = bookmarkList.publicPostBookmarks.firstOrNull { it.eventId == note.idHex }
|
||||||
|
val maybePrivateBookmark = bookmarkList.privatePostBookmarks.firstOrNull { it.eventId == note.idHex }
|
||||||
|
BookmarkGroupManagementItem(
|
||||||
|
modifier = Modifier.fillMaxWidth().animateItem(),
|
||||||
|
listTitle = bookmarkList.title,
|
||||||
|
isPublicMemberBookmark = maybePublicBookmark != null,
|
||||||
|
isPrivateMemberBookmark = maybePrivateBookmark != null,
|
||||||
|
totalPostBookmarkSize = bookmarkList.publicPostBookmarks.size + bookmarkList.privatePostBookmarks.size,
|
||||||
|
totalArticleBookmarkSize = bookmarkList.publicArticleBookmarks.size + bookmarkList.privateArticleBookmarks.size,
|
||||||
|
onClick = { nav.nav(Route.BookmarkGroupView(bookmarkList.identifier, BookmarkType.PostBookmark)) },
|
||||||
|
onAddBookmarkToGroup = { shouldBePrivate ->
|
||||||
|
accountViewModel.launchSigner {
|
||||||
|
accountViewModel.account.labeledBookmarkLists.addBookmarkToList(
|
||||||
|
bookmark = EventBookmark(eventId = note.idHex, relay = note.relayHintUrl(), author = note.author?.pubkeyHex),
|
||||||
|
bookmarkListIdentifier = bookmarkList.identifier,
|
||||||
|
isBookmarkPrivate = shouldBePrivate,
|
||||||
|
account = accountViewModel.account,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRemoveBookmarkFromGroup = {
|
||||||
|
accountViewModel.launchSigner {
|
||||||
|
accountViewModel.account.labeledBookmarkLists.removeBookmarkFromList(
|
||||||
|
bookmark = EventBookmark(eventId = note.idHex),
|
||||||
|
bookmarkListIdentifier = bookmarkList.identifier,
|
||||||
|
isBookmarkPrivate = maybePrivateBookmark != null,
|
||||||
|
account = accountViewModel.account,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -36,5 +36,5 @@ fun BookmarkTabHeader(
|
|||||||
) {
|
) {
|
||||||
val userBookmarks by observeUserBookmarkCount(baseUser, accountViewModel)
|
val userBookmarks by observeUserBookmarkCount(baseUser, accountViewModel)
|
||||||
|
|
||||||
Text(text = "$userBookmarks ${stringRes(R.string.bookmarks)}")
|
Text(text = "$userBookmarks ${stringRes(R.string.bookmarks_title)}")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -391,6 +391,8 @@
|
|||||||
|
|
||||||
<string name="manual_zaps">Manual Zap Splits</string>
|
<string name="manual_zaps">Manual Zap Splits</string>
|
||||||
<string name="bookmarks">Bookmarks</string>
|
<string name="bookmarks">Bookmarks</string>
|
||||||
|
<string name="bookmarks_title">Default Bookmarks</string>
|
||||||
|
<string name="bookmarks_explainer">Your default Bookmarks that many clients support</string>
|
||||||
<string name="drafts">Drafts</string>
|
<string name="drafts">Drafts</string>
|
||||||
<string name="private_bookmarks">Private Bookmarks</string>
|
<string name="private_bookmarks">Private Bookmarks</string>
|
||||||
<string name="public_bookmarks">Public Bookmarks</string>
|
<string name="public_bookmarks">Public Bookmarks</string>
|
||||||
|
|||||||
+15
@@ -148,6 +148,21 @@ class BookmarkListEvent(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun remove(
|
||||||
|
earlierVersion: BookmarkListEvent,
|
||||||
|
bookmarkIdTag: BookmarkIdTag,
|
||||||
|
signer: NostrSigner,
|
||||||
|
createdAt: Long = TimeUtils.now(),
|
||||||
|
): BookmarkListEvent {
|
||||||
|
val privateTags = earlierVersion.privateTags(signer) ?: throw SignerExceptions.UnauthorizedDecryptionException()
|
||||||
|
return resign(
|
||||||
|
privateTags = privateTags.remove(bookmarkIdTag.toTagIdOnly()),
|
||||||
|
tags = earlierVersion.tags.remove(bookmarkIdTag.toTagIdOnly()),
|
||||||
|
signer = signer,
|
||||||
|
createdAt = createdAt,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun resign(
|
suspend fun resign(
|
||||||
tags: TagArray,
|
tags: TagArray,
|
||||||
privateTags: TagArray,
|
privateTags: TagArray,
|
||||||
|
|||||||
Reference in New Issue
Block a user