mirror of
https://github.com/aljazceru/notedeck.git
synced 2025-12-19 09:34:19 +01:00
feat(settings): allow sorting thread replies newest first
This commit is contained in:
@@ -5,6 +5,7 @@ mod token_handler;
|
|||||||
mod zoom;
|
mod zoom;
|
||||||
|
|
||||||
pub use app_size::AppSizeHandler;
|
pub use app_size::AppSizeHandler;
|
||||||
|
pub use settings_handler::Settings;
|
||||||
pub use settings_handler::SettingsHandler;
|
pub use settings_handler::SettingsHandler;
|
||||||
pub use theme_handler::ThemeHandler;
|
pub use theme_handler::ThemeHandler;
|
||||||
pub use token_handler::TokenHandler;
|
pub use token_handler::TokenHandler;
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ pub struct Settings {
|
|||||||
pub locale: String,
|
pub locale: String,
|
||||||
pub zoom_factor: f32,
|
pub zoom_factor: f32,
|
||||||
pub show_source_client: String,
|
pub show_source_client: String,
|
||||||
|
pub show_replies_newest_first: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Settings {
|
impl Default for Settings {
|
||||||
@@ -38,10 +39,12 @@ impl Default for Settings {
|
|||||||
theme: DEFAULT_THEME,
|
theme: DEFAULT_THEME,
|
||||||
locale: DEFAULT_LOCALE.to_string(),
|
locale: DEFAULT_LOCALE.to_string(),
|
||||||
zoom_factor: DEFAULT_ZOOM_FACTOR,
|
zoom_factor: DEFAULT_ZOOM_FACTOR,
|
||||||
show_source_client: "Hide".to_string(),
|
show_source_client: DEFAULT_SHOW_SOURCE_CLIENT.to_string(),
|
||||||
|
show_replies_newest_first: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SettingsHandler {
|
pub struct SettingsHandler {
|
||||||
directory: Directory,
|
directory: Directory,
|
||||||
current_settings: Option<Settings>,
|
current_settings: Option<Settings>,
|
||||||
@@ -129,7 +132,7 @@ impl SettingsHandler {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_settings_mut(&mut self) -> &mut Settings {
|
pub fn get_settings_mut(&mut self) -> &mut Settings {
|
||||||
if self.current_settings.is_none() {
|
if self.current_settings.is_none() {
|
||||||
self.current_settings = Some(Settings::default());
|
self.current_settings = Some(Settings::default());
|
||||||
}
|
}
|
||||||
@@ -162,6 +165,11 @@ impl SettingsHandler {
|
|||||||
self.save();
|
self.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_show_replies_newest_first(&mut self, value: bool) {
|
||||||
|
self.get_settings_mut().show_replies_newest_first = value;
|
||||||
|
self.save();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update_batch<F>(&mut self, update_fn: F)
|
pub fn update_batch<F>(&mut self, update_fn: F)
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut Settings),
|
F: FnOnce(&mut Settings),
|
||||||
@@ -204,6 +212,13 @@ impl SettingsHandler {
|
|||||||
.unwrap_or(DEFAULT_SHOW_SOURCE_CLIENT.to_string())
|
.unwrap_or(DEFAULT_SHOW_SOURCE_CLIENT.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn show_replies_newest_first(&self) -> bool {
|
||||||
|
self.current_settings
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| s.show_replies_newest_first)
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_loaded(&self) -> bool {
|
pub fn is_loaded(&self) -> bool {
|
||||||
self.current_settings.is_some()
|
self.current_settings.is_some()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,18 +14,13 @@ use crate::{
|
|||||||
view_state::ViewState,
|
view_state::ViewState,
|
||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
use egui_extras::{Size, StripBuilder};
|
use egui_extras::{Size, StripBuilder};
|
||||||
use enostr::{ClientMessage, PoolRelay, Pubkey, RelayEvent, RelayMessage, RelayPool};
|
use enostr::{ClientMessage, PoolRelay, Pubkey, RelayEvent, RelayMessage, RelayPool};
|
||||||
use nostrdb::Transaction;
|
use nostrdb::Transaction;
|
||||||
use notedeck::{
|
use notedeck::{
|
||||||
tr, ui::is_narrow, Accounts, AppAction, AppContext, DataPath, DataPathType, FilterState,
|
tr, ui::is_narrow, Accounts, AppAction, AppContext, DataPath, DataPathType, FilterState, Images, JobsCache, Localization, SettingsHandler, UnknownIds
|
||||||
Images, JobsCache, Localization, UnknownIds,
|
|
||||||
};
|
|
||||||
use notedeck_ui::{
|
|
||||||
media::{MediaViewer, MediaViewerFlags, MediaViewerState},
|
|
||||||
NoteOptions,
|
|
||||||
};
|
};
|
||||||
|
use notedeck_ui::{media::{MediaViewer, MediaViewerFlags, MediaViewerState}, NoteOptions};
|
||||||
use std::collections::{BTreeSet, HashMap};
|
use std::collections::{BTreeSet, HashMap};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@@ -443,6 +438,11 @@ impl Damus {
|
|||||||
let mut options = AppOptions::default();
|
let mut options = AppOptions::default();
|
||||||
let tmp_columns = !parsed_args.columns.is_empty();
|
let tmp_columns = !parsed_args.columns.is_empty();
|
||||||
options.set(AppOptions::TmpColumns, tmp_columns);
|
options.set(AppOptions::TmpColumns, tmp_columns);
|
||||||
|
options.set(AppOptions::Debug, app_context.args.debug);
|
||||||
|
options.set(
|
||||||
|
AppOptions::SinceOptimize,
|
||||||
|
parsed_args.is_flag_set(ColumnsFlag::SinceOptimize),
|
||||||
|
);
|
||||||
|
|
||||||
let decks_cache = if tmp_columns {
|
let decks_cache = if tmp_columns {
|
||||||
info!("DecksCache: loading from command line arguments");
|
info!("DecksCache: loading from command line arguments");
|
||||||
@@ -487,37 +487,11 @@ impl Damus {
|
|||||||
// cache.add_deck_default(*pk);
|
// cache.add_deck_default(*pk);
|
||||||
//}
|
//}
|
||||||
};
|
};
|
||||||
|
let settings_handler = &app_context.settings_handler;
|
||||||
|
|
||||||
let support = Support::new(app_context.path);
|
let support = Support::new(app_context.path);
|
||||||
let mut note_options = NoteOptions::default();
|
|
||||||
note_options.set(
|
let note_options = get_note_options(parsed_args, settings_handler);
|
||||||
NoteOptions::Textmode,
|
|
||||||
parsed_args.is_flag_set(ColumnsFlag::Textmode),
|
|
||||||
);
|
|
||||||
note_options.set(
|
|
||||||
NoteOptions::ScrambleText,
|
|
||||||
parsed_args.is_flag_set(ColumnsFlag::Scramble),
|
|
||||||
);
|
|
||||||
note_options.set(
|
|
||||||
NoteOptions::HideMedia,
|
|
||||||
parsed_args.is_flag_set(ColumnsFlag::NoMedia),
|
|
||||||
);
|
|
||||||
note_options.set(
|
|
||||||
NoteOptions::ShowNoteClientTop,
|
|
||||||
ShowSourceClientOption::Top == app_context.settings_handler.show_source_client().into()
|
|
||||||
|| parsed_args.is_flag_set(ColumnsFlag::ShowNoteClientTop),
|
|
||||||
);
|
|
||||||
note_options.set(
|
|
||||||
NoteOptions::ShowNoteClientBottom,
|
|
||||||
ShowSourceClientOption::Bottom
|
|
||||||
== app_context.settings_handler.show_source_client().into()
|
|
||||||
|| parsed_args.is_flag_set(ColumnsFlag::ShowNoteClientBottom),
|
|
||||||
);
|
|
||||||
options.set(AppOptions::Debug, app_context.args.debug);
|
|
||||||
options.set(
|
|
||||||
AppOptions::SinceOptimize,
|
|
||||||
parsed_args.is_flag_set(ColumnsFlag::SinceOptimize),
|
|
||||||
);
|
|
||||||
|
|
||||||
let jobs = JobsCache::default();
|
let jobs = JobsCache::default();
|
||||||
|
|
||||||
@@ -599,6 +573,39 @@ impl Damus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_note_options(args: ColumnsArgs, settings_handler: &&mut SettingsHandler) -> NoteOptions {
|
||||||
|
let mut note_options = NoteOptions::default();
|
||||||
|
|
||||||
|
note_options.set(
|
||||||
|
NoteOptions::Textmode,
|
||||||
|
args.is_flag_set(ColumnsFlag::Textmode),
|
||||||
|
);
|
||||||
|
note_options.set(
|
||||||
|
NoteOptions::ScrambleText,
|
||||||
|
args.is_flag_set(ColumnsFlag::Scramble),
|
||||||
|
);
|
||||||
|
note_options.set(
|
||||||
|
NoteOptions::HideMedia,
|
||||||
|
args.is_flag_set(ColumnsFlag::NoMedia),
|
||||||
|
);
|
||||||
|
note_options.set(
|
||||||
|
NoteOptions::ShowNoteClientTop,
|
||||||
|
ShowSourceClientOption::Top == settings_handler.show_source_client().into()
|
||||||
|
|| args.is_flag_set(ColumnsFlag::ShowNoteClientTop),
|
||||||
|
);
|
||||||
|
note_options.set(
|
||||||
|
NoteOptions::ShowNoteClientBottom,
|
||||||
|
ShowSourceClientOption::Bottom == settings_handler.show_source_client().into()
|
||||||
|
|| args.is_flag_set(ColumnsFlag::ShowNoteClientBottom),
|
||||||
|
);
|
||||||
|
|
||||||
|
note_options.set(
|
||||||
|
NoteOptions::RepliesNewestFirst,
|
||||||
|
settings_handler.show_replies_newest_first(),
|
||||||
|
);
|
||||||
|
note_options
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
fn circle_icon(ui: &mut egui::Ui, openness: f32, response: &egui::Response) {
|
fn circle_icon(ui: &mut egui::Ui, openness: f32, response: &egui::Response) {
|
||||||
let stroke = ui.style().interact(&response).fg_stroke;
|
let stroke = ui.style().interact(&response).fg_stroke;
|
||||||
@@ -620,6 +627,7 @@ fn render_damus_mobile(
|
|||||||
let mut app_action: Option<AppAction> = None;
|
let mut app_action: Option<AppAction> = None;
|
||||||
|
|
||||||
let active_col = app.columns_mut(app_ctx.i18n, app_ctx.accounts).selected as usize;
|
let active_col = app.columns_mut(app_ctx.i18n, app_ctx.accounts).selected as usize;
|
||||||
|
|
||||||
if !app.columns(app_ctx.accounts).columns().is_empty() {
|
if !app.columns(app_ctx.accounts).columns().is_empty() {
|
||||||
let r = nav::render_nav(
|
let r = nav::render_nav(
|
||||||
active_col,
|
active_col,
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ use crate::{
|
|||||||
note::{custom_zap::CustomZapView, NewPostAction, PostAction, PostType, QuoteRepostView},
|
note::{custom_zap::CustomZapView, NewPostAction, PostAction, PostType, QuoteRepostView},
|
||||||
profile::EditProfileView,
|
profile::EditProfileView,
|
||||||
search::{FocusState, SearchView},
|
search::{FocusState, SearchView},
|
||||||
settings::{SettingsAction, ShowSourceClientOption},
|
settings::SettingsAction,
|
||||||
support::SupportView,
|
support::SupportView,
|
||||||
wallet::{get_default_zap_state, WalletAction, WalletState, WalletView},
|
wallet::{get_default_zap_state, WalletAction, WalletState, WalletView},
|
||||||
AccountsView, PostReplyView, PostView, ProfileView, RelayView, SettingsView, ThreadView,
|
AccountsView, PostReplyView, PostView, ProfileView, RelayView, SettingsView, ThreadView,
|
||||||
@@ -586,24 +586,9 @@ fn render_nav_body(
|
|||||||
.map(RenderNavAction::RelayAction),
|
.map(RenderNavAction::RelayAction),
|
||||||
|
|
||||||
Route::Settings => {
|
Route::Settings => {
|
||||||
let mut show_note_client: ShowSourceClientOption = app.note_options.into();
|
let mut settings = ctx.settings_handler.get_settings_mut();
|
||||||
|
|
||||||
let mut theme: String = (if ui.visuals().dark_mode {
|
SettingsView::new(ctx.i18n, ctx.img_cache, &mut settings)
|
||||||
"Dark"
|
|
||||||
} else {
|
|
||||||
"Light"
|
|
||||||
})
|
|
||||||
.into();
|
|
||||||
|
|
||||||
let mut selected_language: String = ctx.i18n.get_current_locale().to_string();
|
|
||||||
|
|
||||||
SettingsView::new(
|
|
||||||
ctx.img_cache,
|
|
||||||
&mut selected_language,
|
|
||||||
&mut theme,
|
|
||||||
&mut show_note_client,
|
|
||||||
ctx.i18n,
|
|
||||||
)
|
|
||||||
.ui(ui)
|
.ui(ui)
|
||||||
.map(RenderNavAction::SettingsAction)
|
.map(RenderNavAction::SettingsAction)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use egui::{vec2, Button, Color32, ComboBox, Frame, Margin, RichText, ThemePreference};
|
use egui::{vec2, Button, Color32, ComboBox, Frame, Margin, RichText, ScrollArea, ThemePreference};
|
||||||
use notedeck::{tr, Images, LanguageIdentifier, Localization, NotedeckTextStyle, SettingsHandler};
|
use notedeck::{
|
||||||
|
tr, Images, LanguageIdentifier, Localization, NotedeckTextStyle, Settings, SettingsHandler,
|
||||||
|
};
|
||||||
use notedeck_ui::NoteOptions;
|
use notedeck_ui::NoteOptions;
|
||||||
use strum::Display;
|
use strum::Display;
|
||||||
|
|
||||||
@@ -97,6 +99,7 @@ pub enum SettingsAction {
|
|||||||
SetTheme(ThemePreference),
|
SetTheme(ThemePreference),
|
||||||
SetShowSourceClient(ShowSourceClientOption),
|
SetShowSourceClient(ShowSourceClientOption),
|
||||||
SetLocale(LanguageIdentifier),
|
SetLocale(LanguageIdentifier),
|
||||||
|
SetRepliestNewestFirst(bool),
|
||||||
OpenRelays,
|
OpenRelays,
|
||||||
OpenCacheFolder,
|
OpenCacheFolder,
|
||||||
ClearCacheFolder,
|
ClearCacheFolder,
|
||||||
@@ -135,6 +138,11 @@ impl SettingsAction {
|
|||||||
settings_handler.set_locale(language.to_string());
|
settings_handler.set_locale(language.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Self::SetRepliestNewestFirst(value) => {
|
||||||
|
app.note_options.set(NoteOptions::RepliesNewestFirst, value);
|
||||||
|
settings_handler.set_show_replies_newest_first(value);
|
||||||
|
settings_handler.save();
|
||||||
|
}
|
||||||
Self::OpenCacheFolder => {
|
Self::OpenCacheFolder => {
|
||||||
use opener;
|
use opener;
|
||||||
let _ = opener::open(img_cache.base_path.clone());
|
let _ = opener::open(img_cache.base_path.clone());
|
||||||
@@ -149,9 +157,7 @@ impl SettingsAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct SettingsView<'a> {
|
pub struct SettingsView<'a> {
|
||||||
theme: &'a mut String,
|
settings: &'a mut Settings,
|
||||||
selected_language: &'a mut String,
|
|
||||||
show_note_client: &'a mut ShowSourceClientOption,
|
|
||||||
i18n: &'a mut Localization,
|
i18n: &'a mut Localization,
|
||||||
img_cache: &'a mut Images,
|
img_cache: &'a mut Images,
|
||||||
}
|
}
|
||||||
@@ -181,30 +187,30 @@ where
|
|||||||
|
|
||||||
impl<'a> SettingsView<'a> {
|
impl<'a> SettingsView<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
img_cache: &'a mut Images,
|
|
||||||
selected_language: &'a mut String,
|
|
||||||
theme: &'a mut String,
|
|
||||||
show_note_client: &'a mut ShowSourceClientOption,
|
|
||||||
i18n: &'a mut Localization,
|
i18n: &'a mut Localization,
|
||||||
|
img_cache: &'a mut Images,
|
||||||
|
settings: &'a mut Settings,
|
||||||
|
// theme: &'a mut String,
|
||||||
|
// show_note_client: &'a mut ShowSourceClientOption,
|
||||||
|
// show_wide: &'a mut bool,
|
||||||
|
// show_replies_newest_first: &'a mut bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
show_note_client,
|
settings,
|
||||||
theme,
|
|
||||||
img_cache,
|
img_cache,
|
||||||
selected_language,
|
|
||||||
i18n,
|
i18n,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the localized name for a language identifier
|
/// Get the localized name for a language identifier
|
||||||
fn get_selected_language_name(&mut self) -> String {
|
fn get_selected_language_name(&mut self) -> String {
|
||||||
if let Ok(lang_id) = self.selected_language.parse::<LanguageIdentifier>() {
|
if let Ok(lang_id) = self.settings.locale.parse::<LanguageIdentifier>() {
|
||||||
self.i18n
|
self.i18n
|
||||||
.get_locale_native_name(&lang_id)
|
.get_locale_native_name(&lang_id)
|
||||||
.map(|s| s.to_owned())
|
.map(|s| s.to_owned())
|
||||||
.unwrap_or_else(|| lang_id.to_string())
|
.unwrap_or_else(|| lang_id.to_string())
|
||||||
} else {
|
} else {
|
||||||
self.selected_language.clone()
|
self.settings.locale.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,7 +295,7 @@ impl<'a> SettingsView<'a> {
|
|||||||
.map(|s| s.to_owned())
|
.map(|s| s.to_owned())
|
||||||
.unwrap_or_else(|| lang.to_string());
|
.unwrap_or_else(|| lang.to_string());
|
||||||
if ui
|
if ui
|
||||||
.selectable_value(self.selected_language, lang.to_string(), name)
|
.selectable_value(&mut self.settings.locale, lang.to_string(), name)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
action = Some(SettingsAction::SetLocale(lang.to_owned()))
|
action = Some(SettingsAction::SetLocale(lang.to_owned()))
|
||||||
@@ -304,10 +310,11 @@ impl<'a> SettingsView<'a> {
|
|||||||
"Theme:",
|
"Theme:",
|
||||||
"Label for theme, Appearance settings section",
|
"Label for theme, Appearance settings section",
|
||||||
));
|
));
|
||||||
|
|
||||||
if ui
|
if ui
|
||||||
.selectable_value(
|
.selectable_value(
|
||||||
self.theme,
|
&mut self.settings.theme,
|
||||||
THEME_LIGHT.into(),
|
ThemePreference::Light,
|
||||||
small_richtext(
|
small_richtext(
|
||||||
self.i18n,
|
self.i18n,
|
||||||
THEME_LIGHT.into(),
|
THEME_LIGHT.into(),
|
||||||
@@ -318,10 +325,11 @@ impl<'a> SettingsView<'a> {
|
|||||||
{
|
{
|
||||||
action = Some(SettingsAction::SetTheme(ThemePreference::Light));
|
action = Some(SettingsAction::SetTheme(ThemePreference::Light));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ui
|
if ui
|
||||||
.selectable_value(
|
.selectable_value(
|
||||||
self.theme,
|
&mut self.settings.theme,
|
||||||
THEME_DARK.into(),
|
ThemePreference::Dark,
|
||||||
small_richtext(
|
small_richtext(
|
||||||
self.i18n,
|
self.i18n,
|
||||||
THEME_DARK.into(),
|
THEME_DARK.into(),
|
||||||
@@ -435,11 +443,32 @@ impl<'a> SettingsView<'a> {
|
|||||||
|
|
||||||
let title = tr!(self.i18n, "Others", "Label for others settings section");
|
let title = tr!(self.i18n, "Others", "Label for others settings section");
|
||||||
settings_group(ui, title, |ui| {
|
settings_group(ui, title, |ui| {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label(small_richtext(
|
||||||
|
self.i18n,
|
||||||
|
"Sort replies newest first",
|
||||||
|
"Label for Sort replies newest first, others settings section",
|
||||||
|
));
|
||||||
|
|
||||||
|
if ui
|
||||||
|
.toggle_value(
|
||||||
|
&mut self.settings.show_replies_newest_first,
|
||||||
|
RichText::new(tr!(self.i18n, "ON", "ON"))
|
||||||
|
.text_style(NotedeckTextStyle::Small.text_style()),
|
||||||
|
)
|
||||||
|
.changed()
|
||||||
|
{
|
||||||
|
action = Some(SettingsAction::SetRepliestNewestFirst(
|
||||||
|
self.settings.show_replies_newest_first,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ui.horizontal_wrapped(|ui| {
|
ui.horizontal_wrapped(|ui| {
|
||||||
ui.label(small_richtext(
|
ui.label(small_richtext(
|
||||||
self.i18n,
|
self.i18n,
|
||||||
"Show source client",
|
"Source client",
|
||||||
"Label for Show source client, others settings section",
|
"Label for Source client, others settings section",
|
||||||
));
|
));
|
||||||
|
|
||||||
for option in [
|
for option in [
|
||||||
@@ -447,9 +476,12 @@ impl<'a> SettingsView<'a> {
|
|||||||
ShowSourceClientOption::Top,
|
ShowSourceClientOption::Top,
|
||||||
ShowSourceClientOption::Bottom,
|
ShowSourceClientOption::Bottom,
|
||||||
] {
|
] {
|
||||||
|
let mut current: ShowSourceClientOption =
|
||||||
|
self.settings.show_source_client.clone().into();
|
||||||
|
|
||||||
if ui
|
if ui
|
||||||
.selectable_value(
|
.selectable_value(
|
||||||
self.show_note_client,
|
&mut current,
|
||||||
option,
|
option,
|
||||||
RichText::new(option.label(self.i18n))
|
RichText::new(option.label(self.i18n))
|
||||||
.text_style(NotedeckTextStyle::Small.text_style()),
|
.text_style(NotedeckTextStyle::Small.text_style()),
|
||||||
@@ -491,6 +523,7 @@ impl<'a> SettingsView<'a> {
|
|||||||
Frame::default()
|
Frame::default()
|
||||||
.inner_margin(Margin::symmetric(10, 10))
|
.inner_margin(Margin::symmetric(10, 10))
|
||||||
.show(ui, |ui| {
|
.show(ui, |ui| {
|
||||||
|
ScrollArea::vertical().show(ui, |ui| {
|
||||||
if let Some(new_action) = self.appearance_section(ui) {
|
if let Some(new_action) = self.appearance_section(ui) {
|
||||||
action = Some(new_action);
|
action = Some(new_action);
|
||||||
}
|
}
|
||||||
@@ -513,6 +546,7 @@ impl<'a> SettingsView<'a> {
|
|||||||
action = Some(new_action);
|
action = Some(new_action);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
action
|
action
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,7 +115,10 @@ impl<'a, 'd> ThreadView<'a, 'd> {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.list;
|
.list;
|
||||||
|
|
||||||
let notes = note_builder.into_notes(&mut self.threads.seen_flags);
|
let notes = note_builder.into_notes(
|
||||||
|
self.note_options.contains(NoteOptions::RepliesNewestFirst),
|
||||||
|
&mut self.threads.seen_flags,
|
||||||
|
);
|
||||||
|
|
||||||
if !full_chain {
|
if !full_chain {
|
||||||
// TODO(kernelkind): insert UI denoting we don't have the full chain yet
|
// TODO(kernelkind): insert UI denoting we don't have the full chain yet
|
||||||
@@ -223,7 +226,11 @@ impl<'a> ThreadNoteBuilder<'a> {
|
|||||||
self.replies.push(note);
|
self.replies.push(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_notes(mut self, seen_flags: &mut NoteSeenFlags) -> ThreadNotes<'a> {
|
pub fn into_notes(
|
||||||
|
mut self,
|
||||||
|
replies_newer_first: bool,
|
||||||
|
seen_flags: &mut NoteSeenFlags,
|
||||||
|
) -> ThreadNotes<'a> {
|
||||||
let mut notes = Vec::new();
|
let mut notes = Vec::new();
|
||||||
|
|
||||||
let selected_is_root = self.chain.is_empty();
|
let selected_is_root = self.chain.is_empty();
|
||||||
@@ -246,6 +253,11 @@ impl<'a> ThreadNoteBuilder<'a> {
|
|||||||
unread_and_have_replies: false,
|
unread_and_have_replies: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if replies_newer_first {
|
||||||
|
self.replies
|
||||||
|
.sort_by(|a, b| b.created_at().cmp(&a.created_at()));
|
||||||
|
}
|
||||||
|
|
||||||
for reply in self.replies {
|
for reply in self.replies {
|
||||||
notes.push(ThreadNote {
|
notes.push(ThreadNote {
|
||||||
unread_and_have_replies: *seen_flags.get(reply.id()).unwrap_or(&false),
|
unread_and_have_replies: *seen_flags.get(reply.id()).unwrap_or(&false),
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ bitflags! {
|
|||||||
/// Show note's client in the note header
|
/// Show note's client in the note header
|
||||||
const ShowNoteClientTop = 1 << 12;
|
const ShowNoteClientTop = 1 << 12;
|
||||||
const ShowNoteClientBottom = 1 << 13;
|
const ShowNoteClientBottom = 1 << 13;
|
||||||
|
|
||||||
|
const RepliesNewestFirst = 1 << 14;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user