Skip to content

Commit

Permalink
feat: Add Option To Sort Bookmarks (#18)
Browse files Browse the repository at this point in the history
Add `Sort` menu which allows users to sort bookmarks based on criteria.
The default sort will be set to "Newest First".

Currently, 4 sort options are available:
- `Newest First` - Sort by newest bookmarks.
- `Oldest First` - Sort by oldest bookmarks.
- `A-Z (Bookmark Title)` - Sort alphabetically by bookmark title
  (ascending).
- `Z-A (Bookmark Title)` - Sort alphabetically by bookmark title
  (descending).
  • Loading branch information
vkhitrin authored Dec 8, 2024
1 parent ce6e6b6 commit 88df760
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 2 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ Potential improvements:
- [Application] Allow user-provided TLS certificate.
- [Distribution] Flatpack release.
- [Distribution] compiled binary in GitHub release.
- [UI] Sort bookmarks.

Things to consider:

Expand All @@ -77,6 +76,7 @@ Things to consider:
- [Application] Consider leveraging linkding's `/check` endpoint when adding bookmarks.
- [Application] Do not block on when executing local database queries.
- [UI] Loading indicator when performing long HTTP calls.
- [UI] Dynamically generate tags that affect filter.

## Thanks

Expand Down
5 changes: 5 additions & 0 deletions i18n/en/cosmicding.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ added-bookmark-to-account = Added bookmark {$bkmrk} to {$acc}
api-key = API Key
appearance = Appearance
archived = Archived
bookmark-date-newest = Newest First
bookmark-date-oldest = Oldest First
bookmark-alphabetical-ascending = A-Z (Bookmark Title)
bookmark-alphabetical-descending = Z-A (Bookmark Title)
bookmarks = Bookmarks
bookmarks-with-count = Bookmarks ({$count})
cancel = Cancel
Expand Down Expand Up @@ -59,6 +63,7 @@ settings = Settings
shared = Shared
shared-disabled = Shared (Disabled)
snapshot = Snapshot
sort = Sort
successful = successful
tags = Tags
tags-subtext = Enter any number of tags separated by space.
Expand Down
Binary file modified res/screenshots/bookmarks.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
47 changes: 46 additions & 1 deletion src/app.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::config::{AppTheme, Config, CONFIG_VERSION};
use crate::config::{AppTheme, Config, SortOption, CONFIG_VERSION};
use crate::db::{self, SqliteDatabase};
use crate::fl;
use crate::http::{self};
Expand Down Expand Up @@ -102,6 +102,7 @@ pub enum Message {
SetBookmarkTitle(String),
SetBookmarkURL(String),
SetBookmarkUnread(bool),
SortOption(SortOption),
StartRefreshAccountProfile(Account),
StartRefreshBookmarksForAccount(Account),
StartRefreshBookmarksForAllAccounts,
Expand Down Expand Up @@ -197,6 +198,7 @@ impl Application for Cosmicding {
&self.key_binds,
!self.accounts_view.accounts.is_empty(),
!self.bookmarks_view.bookmarks.is_empty(),
self.config.sort_option,
)]
}

Expand Down Expand Up @@ -366,6 +368,12 @@ impl Application for Cosmicding {
config_set!(app_theme, app_theme);
return self.update_config();
}
Message::SortOption(sort_option) => {
config_set!(sort_option, sort_option);
if !self.bookmarks_view.bookmarks.is_empty() {
return self.update(Message::LoadBookmarks);
}
}
Message::SystemThemeModeChange => {
return self.update_config();
}
Expand Down Expand Up @@ -894,13 +902,48 @@ impl Application for Cosmicding {
Message::LoadBookmarks => {
self.bookmarks_view.bookmarks =
block_on(async { db::SqliteDatabase::fetch_bookmarks(&mut self.db).await });
match self.config.sort_option {
SortOption::BookmarksDateNewest => {
self.bookmarks_view.bookmarks.sort_by(|a, b| {
b.clone()
.date_added
.unwrap()
.cmp(&a.clone().date_added.unwrap())
});
}
SortOption::BookmarksDateOldest => {
self.bookmarks_view.bookmarks.sort_by(|a, b| {
a.clone()
.date_added
.unwrap()
.cmp(&b.clone().date_added.unwrap())
});
}
SortOption::BookmarkAlphabeticalAscending => {
self.bookmarks_view.bookmarks.sort_by(|a, b| {
a.clone()
.title
.to_lowercase()
.cmp(&b.clone().title.to_lowercase())
});
}
SortOption::BookmarkAlphabeticalDescending => {
self.bookmarks_view.bookmarks.sort_by(|a, b| {
b.clone()
.title
.to_lowercase()
.cmp(&a.clone().title.to_lowercase())
});
}
}
}
Message::StartupCompleted => {
for account in self.accounts_view.accounts.clone() {
commands.push(self.update(Message::StartRefreshAccountProfile(account)));
}
commands.push(Task::perform(
async {
// Initial delay for refresh
tokio::time::sleep(Duration::from_secs(1)).await;
crate::app::Message::StartRefreshBookmarksForAllAccounts
},
Expand Down Expand Up @@ -1030,6 +1073,7 @@ pub enum MenuAction {
Empty,
RefreshBookmarks,
Settings,
SetSortBookmarks(SortOption),
}

impl _MenuAction for MenuAction {
Expand All @@ -1043,6 +1087,7 @@ impl _MenuAction for MenuAction {
MenuAction::Settings => Message::ToggleContextPage(ContextPage::Settings),
MenuAction::AddBookmark => Message::AddBookmarkForm,
MenuAction::RefreshBookmarks => Message::StartRefreshBookmarksForAllAccounts,
MenuAction::SetSortBookmarks(option) => Message::SortOption(*option),
}
}
}
10 changes: 10 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,26 @@ impl AppTheme {
}
}

#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum SortOption {
BookmarksDateNewest,
BookmarksDateOldest,
BookmarkAlphabeticalAscending,
BookmarkAlphabeticalDescending,
}

#[derive(Debug, Clone, CosmicConfigEntry, Eq, PartialEq)]
#[version = 1]
pub struct Config {
pub app_theme: AppTheme,
pub sort_option: SortOption,
}

impl Default for Config {
fn default() -> Self {
Self {
app_theme: AppTheme::System,
sort_option: SortOption::BookmarksDateNewest,
}
}
}
51 changes: 51 additions & 0 deletions src/menu.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::collections::HashMap;

use crate::config::SortOption;
use cosmic::widget::menu::key_bind::KeyBind;
use cosmic::{
widget::menu::{items, root, Item, ItemHeight, ItemWidth, MenuBar, Tree},
Expand All @@ -16,6 +17,7 @@ pub fn menu_bar<'a>(
key_binds: &HashMap<KeyBind, MenuAction>,
accounts_present: bool,
bookmarks_present: bool,
sort_option: SortOption,
) -> Element<'a, Message> {
MenuBar::new(vec![
Tree::with_children(
Expand Down Expand Up @@ -48,6 +50,55 @@ pub fn menu_bar<'a>(
],
),
),
// TODO: (vkhitrin) dynamically generate enabled/disabled entries
// instead of writing manual code
Tree::with_children(
root(fl!("sort")),
items(
key_binds,
if bookmarks_present {
vec![
Item::CheckBox(
fl!("bookmark-date-newest"),
matches!(sort_option, SortOption::BookmarksDateNewest),
MenuAction::SetSortBookmarks(SortOption::BookmarksDateNewest),
),
Item::CheckBox(
fl!("bookmark-date-oldest"),
matches!(sort_option, SortOption::BookmarksDateOldest),
MenuAction::SetSortBookmarks(SortOption::BookmarksDateOldest),
),
Item::Divider,
Item::CheckBox(
fl!("bookmark-alphabetical-ascending"),
matches!(sort_option, SortOption::BookmarkAlphabeticalAscending),
MenuAction::SetSortBookmarks(SortOption::BookmarkAlphabeticalAscending),
),
Item::CheckBox(
fl!("bookmark-alphabetical-descending"),
matches!(sort_option, SortOption::BookmarkAlphabeticalDescending),
MenuAction::SetSortBookmarks(
SortOption::BookmarkAlphabeticalDescending,
),
),
]
} else {
vec![
Item::ButtonDisabled(fl!("bookmark-date-newest"), MenuAction::Empty),
Item::ButtonDisabled(fl!("bookmark-date-oldest"), MenuAction::Empty),
Item::Divider,
Item::ButtonDisabled(
fl!("bookmark-alphabetical-ascending"),
MenuAction::Empty,
),
Item::ButtonDisabled(
fl!("bookmark-alphabetical-descending"),
MenuAction::Empty,
),
]
},
),
),
])
.item_height(ItemHeight::Dynamic(40))
.item_width(ItemWidth::Uniform(240))
Expand Down

0 comments on commit 88df760

Please sign in to comment.