mirror of
https://github.com/aljazceru/notedeck.git
synced 2025-12-17 00:44:18 +01:00
feat(settings): add settings view
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -19,3 +19,5 @@ queries/damus-notifs.json
|
|||||||
.direnv/
|
.direnv/
|
||||||
scripts/macos_build_secrets.sh
|
scripts/macos_build_secrets.sh
|
||||||
/tags
|
/tags
|
||||||
|
.zed
|
||||||
|
.lsp
|
||||||
32
Cargo.lock
generated
32
Cargo.lock
generated
@@ -802,6 +802,17 @@ version = "0.2.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e79769241dcd44edf79a732545e8b5cec84c247ac060f5252cd51885d093a8fc"
|
checksum = "e79769241dcd44edf79a732545e8b5cec84c247ac060f5252cd51885d093a8fc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bstr"
|
||||||
|
version = "1.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"regex-automata 0.4.9",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "built"
|
name = "built"
|
||||||
version = "0.7.7"
|
version = "0.7.7"
|
||||||
@@ -3304,6 +3315,15 @@ version = "0.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
|
checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "normpath"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c8911957c4b1549ac0dc74e30db9c8b0e66ddcd6d7acc33098f4c63a64a6d7ed"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr"
|
name = "nostr"
|
||||||
version = "0.37.0"
|
version = "0.37.0"
|
||||||
@@ -3500,6 +3520,7 @@ dependencies = [
|
|||||||
"notedeck_ui",
|
"notedeck_ui",
|
||||||
"oot_bitset",
|
"oot_bitset",
|
||||||
"open",
|
"open",
|
||||||
|
"opener",
|
||||||
"poll-promise",
|
"poll-promise",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"profiling",
|
"profiling",
|
||||||
@@ -4002,6 +4023,17 @@ dependencies = [
|
|||||||
"pathdiff",
|
"pathdiff",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opener"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "771b9704f8cd8b424ec747a320b30b47517a6966ba2c7da90047c16f4a962223"
|
||||||
|
dependencies = [
|
||||||
|
"bstr",
|
||||||
|
"normpath",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-probe"
|
name = "openssl-probe"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ members = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
opener = "0.8.2"
|
||||||
base32 = "0.4.0"
|
base32 = "0.4.0"
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
rmpv = "1.3.0"
|
rmpv = "1.3.0"
|
||||||
|
|||||||
11
android
Executable file
11
android
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
root_dir=$PWD
|
||||||
|
|
||||||
|
cargo ndk --target arm64-v8a -o ./crates/notedeck_chrome/android/app/src/main/jniLibs/ build --profile release
|
||||||
|
|
||||||
|
cd ./crates/notedeck_chrome/android
|
||||||
|
|
||||||
|
./gradlew build && ./gradlew installDebug
|
||||||
|
|
||||||
|
cd $root_dir
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
|
use crate::{AccountData, RelaySpec};
|
||||||
use enostr::{Keypair, Pubkey, RelayPool};
|
use enostr::{Keypair, Pubkey, RelayPool};
|
||||||
use nostrdb::{Filter, Ndb, NoteBuilder, NoteKey, Subscription, Transaction};
|
use nostrdb::{Filter, Ndb, NoteBuilder, NoteKey, Subscription, Transaction};
|
||||||
use tracing::{debug, error, info};
|
use tracing::{debug, error, info};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use crate::{AccountData, RelaySpec};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct AccountRelayData {
|
pub(crate) struct AccountRelayData {
|
||||||
pub filter: Filter,
|
pub filter: Filter,
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ use poll_promise::Promise;
|
|||||||
use egui::ColorImage;
|
use egui::ColorImage;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::{create_dir_all, File};
|
use std::fs::{self, create_dir_all, File};
|
||||||
use std::sync::mpsc::Receiver;
|
use std::sync::mpsc::Receiver;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
use std::time::{Duration, Instant, SystemTime};
|
use std::time::{Duration, Instant, SystemTime};
|
||||||
|
use std::{io, thread};
|
||||||
|
|
||||||
use hex::ToHex;
|
use hex::ToHex;
|
||||||
use sha2::Digest;
|
use sha2::Digest;
|
||||||
@@ -220,6 +222,7 @@ pub struct MediaCache {
|
|||||||
pub cache_dir: path::PathBuf,
|
pub cache_dir: path::PathBuf,
|
||||||
pub textures_cache: TexturesCache,
|
pub textures_cache: TexturesCache,
|
||||||
pub cache_type: MediaCacheType,
|
pub cache_type: MediaCacheType,
|
||||||
|
pub cache_size: Arc<Mutex<Option<u64>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
|
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
|
||||||
@@ -231,10 +234,29 @@ pub enum MediaCacheType {
|
|||||||
impl MediaCache {
|
impl MediaCache {
|
||||||
pub fn new(parent_dir: &Path, cache_type: MediaCacheType) -> Self {
|
pub fn new(parent_dir: &Path, cache_type: MediaCacheType) -> Self {
|
||||||
let cache_dir = parent_dir.join(Self::rel_dir(cache_type));
|
let cache_dir = parent_dir.join(Self::rel_dir(cache_type));
|
||||||
|
|
||||||
|
let cache_dir_clone = cache_dir.clone();
|
||||||
|
let cache_size = Arc::new(Mutex::new(None));
|
||||||
|
let cache_size_clone = Arc::clone(&cache_size);
|
||||||
|
|
||||||
|
thread::spawn(move || {
|
||||||
|
let mut last_checked = Instant::now() - Duration::from_secs(999);
|
||||||
|
loop {
|
||||||
|
// check cache folder size every 60 s
|
||||||
|
if last_checked.elapsed() >= Duration::from_secs(60) {
|
||||||
|
let size = compute_folder_size(&cache_dir_clone);
|
||||||
|
*cache_size_clone.lock().unwrap() = Some(size);
|
||||||
|
last_checked = Instant::now();
|
||||||
|
}
|
||||||
|
thread::sleep(Duration::from_secs(5));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
cache_dir,
|
cache_dir,
|
||||||
textures_cache: TexturesCache::default(),
|
textures_cache: TexturesCache::default(),
|
||||||
cache_type,
|
cache_type,
|
||||||
|
cache_size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,8 +353,14 @@ impl MediaCache {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clear(&mut self) {
|
||||||
|
self.textures_cache.cache.clear();
|
||||||
|
*self.cache_size.try_lock().unwrap() = Some(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn color_image_to_rgba(color_image: ColorImage) -> image::RgbaImage {
|
fn color_image_to_rgba(color_image: ColorImage) -> image::RgbaImage {
|
||||||
@@ -349,7 +377,28 @@ fn color_image_to_rgba(color_image: ColorImage) -> image::RgbaImage {
|
|||||||
.expect("Failed to create RgbaImage from ColorImage")
|
.expect("Failed to create RgbaImage from ColorImage")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compute_folder_size<P: AsRef<Path>>(path: P) -> u64 {
|
||||||
|
fn walk(path: &Path) -> u64 {
|
||||||
|
let mut size = 0;
|
||||||
|
if let Ok(entries) = fs::read_dir(path) {
|
||||||
|
for entry in entries.flatten() {
|
||||||
|
let path = entry.path();
|
||||||
|
if let Ok(metadata) = entry.metadata() {
|
||||||
|
if metadata.is_file() {
|
||||||
|
size += metadata.len();
|
||||||
|
} else if metadata.is_dir() {
|
||||||
|
size += walk(&path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size
|
||||||
|
}
|
||||||
|
walk(path.as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Images {
|
pub struct Images {
|
||||||
|
pub base_path: path::PathBuf,
|
||||||
pub static_imgs: MediaCache,
|
pub static_imgs: MediaCache,
|
||||||
pub gifs: MediaCache,
|
pub gifs: MediaCache,
|
||||||
pub urls: UrlMimes,
|
pub urls: UrlMimes,
|
||||||
@@ -360,6 +409,7 @@ impl Images {
|
|||||||
/// path to directory to place [`MediaCache`]s
|
/// path to directory to place [`MediaCache`]s
|
||||||
pub fn new(path: path::PathBuf) -> Self {
|
pub fn new(path: path::PathBuf) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
base_path: path.clone(),
|
||||||
static_imgs: MediaCache::new(&path, MediaCacheType::Image),
|
static_imgs: MediaCache::new(&path, MediaCacheType::Image),
|
||||||
gifs: MediaCache::new(&path, MediaCacheType::Gif),
|
gifs: MediaCache::new(&path, MediaCacheType::Gif),
|
||||||
urls: UrlMimes::new(UrlCache::new(path.join(UrlCache::rel_dir()))),
|
urls: UrlMimes::new(UrlCache::new(path.join(UrlCache::rel_dir()))),
|
||||||
@@ -385,6 +435,26 @@ impl Images {
|
|||||||
MediaCacheType::Gif => &mut self.gifs,
|
MediaCacheType::Gif => &mut self.gifs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear_folder_contents(&mut self) -> io::Result<()> {
|
||||||
|
for entry in fs::read_dir(self.base_path.clone())? {
|
||||||
|
let entry = entry?;
|
||||||
|
let path = entry.path();
|
||||||
|
|
||||||
|
if path.is_dir() {
|
||||||
|
fs::remove_dir_all(path)?;
|
||||||
|
} else {
|
||||||
|
fs::remove_file(path)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.urls.cache.clear();
|
||||||
|
self.static_imgs.clear();
|
||||||
|
self.gifs.clear();
|
||||||
|
self.gif_states.clear();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type GifStateMap = HashMap<String, GifState>;
|
pub type GifStateMap = HashMap<String, GifState>;
|
||||||
|
|||||||
@@ -68,6 +68,17 @@ impl UrlCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
if self.from_disk_promise.is_none() {
|
||||||
|
let cache = self.cache.clone();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
if let Ok(mut locked_cache) = cache.write() {
|
||||||
|
locked_cache.clear();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_cache(cur_cache: Arc<RwLock<UrlsToMime>>, from_disk: UrlsToMime) {
|
fn merge_cache(cur_cache: Arc<RwLock<UrlsToMime>>, from_disk: UrlsToMime) {
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ impl ChromePanelAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Self::Settings => {
|
Self::Settings => {
|
||||||
Self::columns_navigate(ctx, chrome, notedeck_columns::Route::Relays);
|
Self::columns_navigate(ctx, chrome, notedeck_columns::Route::Settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::Wallet => {
|
Self::Wallet => {
|
||||||
@@ -707,7 +707,41 @@ fn pfp_button(ctx: &mut AppContext, ui: &mut egui::Ui) -> egui::Response {
|
|||||||
|
|
||||||
ui.put(helper.get_animation_rect(), &mut widget);
|
ui.put(helper.get_animation_rect(), &mut widget);
|
||||||
|
|
||||||
helper.take_animation_response()
|
let pfp_resp = helper.take_animation_response();
|
||||||
|
|
||||||
|
// let selected = ctx.accounts.cache.selected();
|
||||||
|
|
||||||
|
// pfp_resp.context_menu(|ui| {
|
||||||
|
// for (pk, account) in &ctx.accounts.cache {
|
||||||
|
// let profile = ctx.ndb.get_profile_by_pubkey(&txn, pk).ok();
|
||||||
|
// let is_selected = *pk == selected.key.pubkey;
|
||||||
|
// let has_nsec = account.key.secret_key.is_some();
|
||||||
|
|
||||||
|
// let profile_peview_view = {
|
||||||
|
// let max_size = egui::vec2(ui.available_width(), 77.0);
|
||||||
|
// let resp = ui.allocate_response(max_size, egui::Sense::click());
|
||||||
|
// ui.allocate_new_ui(UiBuilder::new().max_rect(resp.rect), |ui| {
|
||||||
|
// ui.add(
|
||||||
|
// &mut ProfilePic::new(ctx.img_cache, get_profile_url(profile.as_ref()))
|
||||||
|
// .size(24.0),
|
||||||
|
// )
|
||||||
|
// })
|
||||||
|
// };
|
||||||
|
|
||||||
|
// // if let Some(op) = profile_peview_view {
|
||||||
|
// // return_op = Some(match op {
|
||||||
|
// // ProfilePreviewAction::SwitchTo => AccountsViewResponse::SelectAccount(*pk),
|
||||||
|
// // ProfilePreviewAction::RemoveAccount => AccountsViewResponse::RemoveAccount(*pk),
|
||||||
|
// // });
|
||||||
|
// // }
|
||||||
|
// }
|
||||||
|
// // if ui.menu_image_button(image, add_contents).clicked() {
|
||||||
|
// // // ui.ctx().copy_text(url.to_owned());
|
||||||
|
// // ui.close_menu();
|
||||||
|
// // }
|
||||||
|
// });
|
||||||
|
|
||||||
|
pfp_resp
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The section of the chrome sidebar that starts at the
|
/// The section of the chrome sidebar that starts at the
|
||||||
@@ -720,6 +754,7 @@ fn bottomup_sidebar(
|
|||||||
ui.add_space(8.0);
|
ui.add_space(8.0);
|
||||||
|
|
||||||
let pfp_resp = pfp_button(ctx, ui).on_hover_cursor(egui::CursorIcon::PointingHand);
|
let pfp_resp = pfp_button(ctx, ui).on_hover_cursor(egui::CursorIcon::PointingHand);
|
||||||
|
|
||||||
let settings_resp = settings_button(ui).on_hover_cursor(egui::CursorIcon::PointingHand);
|
let settings_resp = settings_button(ui).on_hover_cursor(egui::CursorIcon::PointingHand);
|
||||||
|
|
||||||
let theme_action = match ui.ctx().theme() {
|
let theme_action = match ui.ctx().theme() {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ pub fn setup_chrome(ctx: &egui::Context, args: ¬edeck::Args, theme: ThemePref
|
|||||||
});
|
});
|
||||||
ctx.set_visuals_of(egui::Theme::Dark, theme::dark_mode(is_oled));
|
ctx.set_visuals_of(egui::Theme::Dark, theme::dark_mode(is_oled));
|
||||||
ctx.set_visuals_of(egui::Theme::Light, theme::light_mode());
|
ctx.set_visuals_of(egui::Theme::Light, theme::light_mode());
|
||||||
|
|
||||||
setup_cc(ctx, is_mobile);
|
setup_cc(ctx, is_mobile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,6 +39,7 @@ pub fn setup_cc(ctx: &egui::Context, is_mobile: bool) {
|
|||||||
if notedeck::ui::is_compiled_as_mobile() {
|
if notedeck::ui::is_compiled_as_mobile() {
|
||||||
ctx.set_pixels_per_point(ctx.pixels_per_point() + 0.2);
|
ctx.set_pixels_per_point(ctx.pixels_per_point() + 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
//ctx.set_pixels_per_point(1.0);
|
//ctx.set_pixels_per_point(1.0);
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ description = "A tweetdeck-style notedeck app"
|
|||||||
crate-type = ["lib", "cdylib"]
|
crate-type = ["lib", "cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
opener = { workspace = true }
|
||||||
rmpv = { workspace = true }
|
rmpv = { workspace = true }
|
||||||
bech32 = { workspace = true }
|
bech32 = { workspace = true }
|
||||||
notedeck = { workspace = true }
|
notedeck = { workspace = true }
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ pub enum DamusState {
|
|||||||
/// We derive Deserialize/Serialize so we can persist app state on shutdown.
|
/// We derive Deserialize/Serialize so we can persist app state on shutdown.
|
||||||
pub struct Damus {
|
pub struct Damus {
|
||||||
state: DamusState,
|
state: DamusState,
|
||||||
|
|
||||||
pub decks_cache: DecksCache,
|
pub decks_cache: DecksCache,
|
||||||
pub view_state: ViewState,
|
pub view_state: ViewState,
|
||||||
pub drafts: Drafts,
|
pub drafts: Drafts,
|
||||||
@@ -393,13 +394,13 @@ fn determine_key_storage_type() -> KeyStorageType {
|
|||||||
|
|
||||||
impl Damus {
|
impl Damus {
|
||||||
/// Called once before the first frame.
|
/// Called once before the first frame.
|
||||||
pub fn new(ctx: &mut AppContext<'_>, args: &[String]) -> Self {
|
pub fn new(app_context: &mut AppContext<'_>, args: &[String]) -> Self {
|
||||||
// arg parsing
|
// arg parsing
|
||||||
|
|
||||||
let (parsed_args, unrecognized_args) =
|
let (parsed_args, unrecognized_args) =
|
||||||
ColumnsArgs::parse(args, Some(ctx.accounts.selected_account_pubkey()));
|
ColumnsArgs::parse(args, Some(app_context.accounts.selected_account_pubkey()));
|
||||||
|
|
||||||
let account = ctx.accounts.selected_account_pubkey_bytes();
|
let account = app_context.accounts.selected_account_pubkey_bytes();
|
||||||
|
|
||||||
let mut timeline_cache = TimelineCache::default();
|
let mut timeline_cache = TimelineCache::default();
|
||||||
let mut options = AppOptions::default();
|
let mut options = AppOptions::default();
|
||||||
@@ -409,31 +410,34 @@ impl Damus {
|
|||||||
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");
|
||||||
let mut columns: Columns = Columns::new();
|
let mut columns: Columns = Columns::new();
|
||||||
let txn = Transaction::new(ctx.ndb).unwrap();
|
let txn = Transaction::new(app_context.ndb).unwrap();
|
||||||
for col in &parsed_args.columns {
|
for col in &parsed_args.columns {
|
||||||
let timeline_kind = col.clone().into_timeline_kind();
|
let timeline_kind = col.clone().into_timeline_kind();
|
||||||
if let Some(add_result) = columns.add_new_timeline_column(
|
if let Some(add_result) = columns.add_new_timeline_column(
|
||||||
&mut timeline_cache,
|
&mut timeline_cache,
|
||||||
&txn,
|
&txn,
|
||||||
ctx.ndb,
|
app_context.ndb,
|
||||||
ctx.note_cache,
|
app_context.note_cache,
|
||||||
ctx.pool,
|
app_context.pool,
|
||||||
&timeline_kind,
|
&timeline_kind,
|
||||||
) {
|
) {
|
||||||
add_result.process(
|
add_result.process(
|
||||||
ctx.ndb,
|
app_context.ndb,
|
||||||
ctx.note_cache,
|
app_context.note_cache,
|
||||||
&txn,
|
&txn,
|
||||||
&mut timeline_cache,
|
&mut timeline_cache,
|
||||||
ctx.unknown_ids,
|
app_context.unknown_ids,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
columns_to_decks_cache(ctx.i18n, columns, account)
|
columns_to_decks_cache(app_context.i18n, columns, account)
|
||||||
} else if let Some(decks_cache) =
|
} else if let Some(decks_cache) = crate::storage::load_decks_cache(
|
||||||
crate::storage::load_decks_cache(ctx.path, ctx.ndb, &mut timeline_cache, ctx.i18n)
|
app_context.path,
|
||||||
{
|
app_context.ndb,
|
||||||
|
&mut timeline_cache,
|
||||||
|
app_context.i18n,
|
||||||
|
) {
|
||||||
info!(
|
info!(
|
||||||
"DecksCache: loading from disk {}",
|
"DecksCache: loading from disk {}",
|
||||||
crate::storage::DECKS_CACHE_FILE
|
crate::storage::DECKS_CACHE_FILE
|
||||||
@@ -441,13 +445,13 @@ impl Damus {
|
|||||||
decks_cache
|
decks_cache
|
||||||
} else {
|
} else {
|
||||||
info!("DecksCache: creating new with demo configuration");
|
info!("DecksCache: creating new with demo configuration");
|
||||||
DecksCache::new_with_demo_config(&mut timeline_cache, ctx)
|
DecksCache::new_with_demo_config(&mut timeline_cache, app_context)
|
||||||
//for (pk, _) in &ctx.accounts.cache {
|
//for (pk, _) in &app_context.accounts.cache {
|
||||||
// cache.add_deck_default(*pk);
|
// cache.add_deck_default(*pk);
|
||||||
//}
|
//}
|
||||||
};
|
};
|
||||||
|
|
||||||
let support = Support::new(ctx.path);
|
let support = Support::new(app_context.path);
|
||||||
let mut note_options = NoteOptions::default();
|
let mut note_options = NoteOptions::default();
|
||||||
note_options.set(
|
note_options.set(
|
||||||
NoteOptions::Textmode,
|
NoteOptions::Textmode,
|
||||||
@@ -462,10 +466,14 @@ impl Damus {
|
|||||||
parsed_args.is_flag_set(ColumnsFlag::NoMedia),
|
parsed_args.is_flag_set(ColumnsFlag::NoMedia),
|
||||||
);
|
);
|
||||||
note_options.set(
|
note_options.set(
|
||||||
NoteOptions::ShowNoteClient,
|
NoteOptions::ShowNoteClientTop,
|
||||||
parsed_args.is_flag_set(ColumnsFlag::ShowNoteClient),
|
parsed_args.is_flag_set(ColumnsFlag::ShowNoteClientTop),
|
||||||
);
|
);
|
||||||
options.set(AppOptions::Debug, ctx.args.debug);
|
note_options.set(
|
||||||
|
NoteOptions::ShowNoteClientBottom,
|
||||||
|
parsed_args.is_flag_set(ColumnsFlag::ShowNoteClientBottom),
|
||||||
|
);
|
||||||
|
options.set(AppOptions::Debug, app_context.args.debug);
|
||||||
options.set(
|
options.set(
|
||||||
AppOptions::SinceOptimize,
|
AppOptions::SinceOptimize,
|
||||||
parsed_args.is_flag_set(ColumnsFlag::SinceOptimize),
|
parsed_args.is_flag_set(ColumnsFlag::SinceOptimize),
|
||||||
@@ -662,6 +670,7 @@ fn should_show_compose_button(decks: &DecksCache, accounts: &Accounts) -> bool {
|
|||||||
Route::Reply(_) => false,
|
Route::Reply(_) => false,
|
||||||
Route::Quote(_) => false,
|
Route::Quote(_) => false,
|
||||||
Route::Relays => false,
|
Route::Relays => false,
|
||||||
|
Route::Settings => false,
|
||||||
Route::ComposeNote => false,
|
Route::ComposeNote => false,
|
||||||
Route::AddColumn(_) => false,
|
Route::AddColumn(_) => false,
|
||||||
Route::EditProfile(_) => false,
|
Route::EditProfile(_) => false,
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ pub enum ColumnsFlag {
|
|||||||
Textmode,
|
Textmode,
|
||||||
Scramble,
|
Scramble,
|
||||||
NoMedia,
|
NoMedia,
|
||||||
ShowNoteClient,
|
ShowNoteClientTop,
|
||||||
|
ShowNoteClientBottom,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ColumnsArgs {
|
pub struct ColumnsArgs {
|
||||||
@@ -53,8 +54,10 @@ impl ColumnsArgs {
|
|||||||
res.clear_flag(ColumnsFlag::SinceOptimize);
|
res.clear_flag(ColumnsFlag::SinceOptimize);
|
||||||
} else if arg == "--scramble" {
|
} else if arg == "--scramble" {
|
||||||
res.set_flag(ColumnsFlag::Scramble);
|
res.set_flag(ColumnsFlag::Scramble);
|
||||||
} else if arg == "--show-note-client" {
|
} else if arg == "--show-note-client=top" {
|
||||||
res.set_flag(ColumnsFlag::ShowNoteClient);
|
res.set_flag(ColumnsFlag::ShowNoteClientTop);
|
||||||
|
} else if arg == "--show-note-client=bottom" {
|
||||||
|
res.set_flag(ColumnsFlag::ShowNoteClientBottom);
|
||||||
} else if arg == "--no-media" {
|
} else if arg == "--no-media" {
|
||||||
res.set_flag(ColumnsFlag::NoMedia);
|
res.set_flag(ColumnsFlag::NoMedia);
|
||||||
} else if arg == "--filter" {
|
} else if arg == "--filter" {
|
||||||
|
|||||||
@@ -20,9 +20,10 @@ use crate::{
|
|||||||
note::{custom_zap::CustomZapView, NewPostAction, PostAction, PostType},
|
note::{custom_zap::CustomZapView, NewPostAction, PostAction, PostType},
|
||||||
profile::EditProfileView,
|
profile::EditProfileView,
|
||||||
search::{FocusState, SearchView},
|
search::{FocusState, SearchView},
|
||||||
|
settings::{SettingsAction, ShowNoteClientOptions},
|
||||||
support::SupportView,
|
support::SupportView,
|
||||||
wallet::{get_default_zap_state, WalletAction, WalletState, WalletView},
|
wallet::{get_default_zap_state, WalletAction, WalletState, WalletView},
|
||||||
RelayView,
|
RelayView, SettingsView,
|
||||||
},
|
},
|
||||||
Damus,
|
Damus,
|
||||||
};
|
};
|
||||||
@@ -34,6 +35,7 @@ use notedeck::{
|
|||||||
get_current_default_msats, get_current_wallet, tr, ui::is_narrow, Accounts, AppContext,
|
get_current_default_msats, get_current_wallet, tr, ui::is_narrow, Accounts, AppContext,
|
||||||
NoteAction, NoteContext, RelayAction,
|
NoteAction, NoteContext, RelayAction,
|
||||||
};
|
};
|
||||||
|
use notedeck_ui::NoteOptions;
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
/// The result of processing a nav response
|
/// The result of processing a nav response
|
||||||
@@ -60,6 +62,7 @@ pub enum RenderNavAction {
|
|||||||
SwitchingAction(SwitchingAction),
|
SwitchingAction(SwitchingAction),
|
||||||
WalletAction(WalletAction),
|
WalletAction(WalletAction),
|
||||||
RelayAction(RelayAction),
|
RelayAction(RelayAction),
|
||||||
|
SettingsAction(SettingsAction),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum SwitchingAction {
|
pub enum SwitchingAction {
|
||||||
@@ -480,6 +483,10 @@ fn process_render_nav_action(
|
|||||||
.process_relay_action(ui.ctx(), ctx.pool, action);
|
.process_relay_action(ui.ctx(), ctx.pool, action);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
RenderNavAction::SettingsAction(action) => {
|
||||||
|
action.process(app, ctx.theme, ctx.i18n, ctx.img_cache, ui.ctx());
|
||||||
|
None
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(action) = router_action {
|
if let Some(action) = router_action {
|
||||||
@@ -497,7 +504,7 @@ fn process_render_nav_action(
|
|||||||
fn render_nav_body(
|
fn render_nav_body(
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
app: &mut Damus,
|
app: &mut Damus,
|
||||||
ctx: &mut AppContext<'_>,
|
ctx: &mut AppContext,
|
||||||
top: &Route,
|
top: &Route,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
col: usize,
|
col: usize,
|
||||||
@@ -573,6 +580,36 @@ fn render_nav_body(
|
|||||||
Route::Relays => RelayView::new(ctx.pool, &mut app.view_state.id_string_map, ctx.i18n)
|
Route::Relays => RelayView::new(ctx.pool, &mut app.view_state.id_string_map, ctx.i18n)
|
||||||
.ui(ui)
|
.ui(ui)
|
||||||
.map(RenderNavAction::RelayAction),
|
.map(RenderNavAction::RelayAction),
|
||||||
|
|
||||||
|
Route::Settings => {
|
||||||
|
let mut show_note_client = if app.note_options.contains(NoteOptions::ShowNoteClientTop)
|
||||||
|
{
|
||||||
|
ShowNoteClientOptions::Top
|
||||||
|
} else if app.note_options.contains(NoteOptions::ShowNoteClientBottom) {
|
||||||
|
ShowNoteClientOptions::Bottom
|
||||||
|
} else {
|
||||||
|
ShowNoteClientOptions::Hide
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut theme: String = (if ui.visuals().dark_mode {
|
||||||
|
"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)
|
||||||
|
.map(RenderNavAction::SettingsAction)
|
||||||
|
}
|
||||||
Route::Reply(id) => {
|
Route::Reply(id) => {
|
||||||
let txn = if let Ok(txn) = Transaction::new(ctx.ndb) {
|
let txn = if let Ok(txn) = Transaction::new(ctx.ndb) {
|
||||||
txn
|
txn
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ pub enum Route {
|
|||||||
Reply(NoteId),
|
Reply(NoteId),
|
||||||
Quote(NoteId),
|
Quote(NoteId),
|
||||||
Relays,
|
Relays,
|
||||||
|
Settings,
|
||||||
ComposeNote,
|
ComposeNote,
|
||||||
AddColumn(AddColumnRoute),
|
AddColumn(AddColumnRoute),
|
||||||
EditProfile(Pubkey),
|
EditProfile(Pubkey),
|
||||||
@@ -47,6 +48,10 @@ impl Route {
|
|||||||
Route::Relays
|
Route::Relays
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn settings() -> Self {
|
||||||
|
Route::Settings
|
||||||
|
}
|
||||||
|
|
||||||
pub fn thread(thread_selection: ThreadSelection) -> Self {
|
pub fn thread(thread_selection: ThreadSelection) -> Self {
|
||||||
Route::Thread(thread_selection)
|
Route::Thread(thread_selection)
|
||||||
}
|
}
|
||||||
@@ -110,6 +115,9 @@ impl Route {
|
|||||||
Route::Relays => {
|
Route::Relays => {
|
||||||
writer.write_token("relay");
|
writer.write_token("relay");
|
||||||
}
|
}
|
||||||
|
Route::Settings => {
|
||||||
|
writer.write_token("settings");
|
||||||
|
}
|
||||||
Route::ComposeNote => {
|
Route::ComposeNote => {
|
||||||
writer.write_token("compose");
|
writer.write_token("compose");
|
||||||
}
|
}
|
||||||
@@ -169,6 +177,12 @@ impl Route {
|
|||||||
Ok(Route::Relays)
|
Ok(Route::Relays)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|p| {
|
||||||
|
p.parse_all(|p| {
|
||||||
|
p.parse_token("settings")?;
|
||||||
|
Ok(Route::Settings)
|
||||||
|
})
|
||||||
|
},
|
||||||
|p| {
|
|p| {
|
||||||
p.parse_all(|p| {
|
p.parse_all(|p| {
|
||||||
p.parse_token("quote")?;
|
p.parse_token("quote")?;
|
||||||
@@ -250,6 +264,9 @@ impl Route {
|
|||||||
Route::Relays => {
|
Route::Relays => {
|
||||||
ColumnTitle::formatted(tr!(i18n, "Relays", "Column title for relay management"))
|
ColumnTitle::formatted(tr!(i18n, "Relays", "Column title for relay management"))
|
||||||
}
|
}
|
||||||
|
Route::Settings => {
|
||||||
|
ColumnTitle::formatted(tr!(i18n, "Settings", "Column title for app settings"))
|
||||||
|
}
|
||||||
Route::Accounts(amr) => match amr {
|
Route::Accounts(amr) => match amr {
|
||||||
AccountsRoute::Accounts => ColumnTitle::formatted(tr!(
|
AccountsRoute::Accounts => ColumnTitle::formatted(tr!(
|
||||||
i18n,
|
i18n,
|
||||||
@@ -555,6 +572,7 @@ impl fmt::Display for Route {
|
|||||||
write!(f, "{}", tr!("Quote", "Display name for quote composition"))
|
write!(f, "{}", tr!("Quote", "Display name for quote composition"))
|
||||||
}
|
}
|
||||||
Route::Relays => write!(f, "{}", tr!("Relays", "Display name for relay management")),
|
Route::Relays => write!(f, "{}", tr!("Relays", "Display name for relay management")),
|
||||||
|
Route::Settings => write!(f, "{}", tr!("Settings", "Display name for settings management")),
|
||||||
Route::Accounts(amr) => match amr {
|
Route::Accounts(amr) => match amr {
|
||||||
AccountsRoute::Accounts => write!(
|
AccountsRoute::Accounts => write!(
|
||||||
f,
|
f,
|
||||||
|
|||||||
@@ -481,6 +481,7 @@ impl<'a> NavTitle<'a> {
|
|||||||
Route::AddColumn(_add_col_route) => None,
|
Route::AddColumn(_add_col_route) => None,
|
||||||
Route::Support => None,
|
Route::Support => None,
|
||||||
Route::Relays => None,
|
Route::Relays => None,
|
||||||
|
Route::Settings => None,
|
||||||
Route::NewDeck => None,
|
Route::NewDeck => None,
|
||||||
Route::EditDeck(_) => None,
|
Route::EditDeck(_) => None,
|
||||||
Route::EditProfile(pubkey) => Some(self.show_profile(ui, pubkey, pfp_size)),
|
Route::EditProfile(pubkey) => Some(self.show_profile(ui, pubkey, pfp_size)),
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ pub mod profile;
|
|||||||
pub mod relay;
|
pub mod relay;
|
||||||
pub mod search;
|
pub mod search;
|
||||||
pub mod search_results;
|
pub mod search_results;
|
||||||
|
pub mod settings;
|
||||||
pub mod side_panel;
|
pub mod side_panel;
|
||||||
pub mod support;
|
pub mod support;
|
||||||
pub mod thread;
|
pub mod thread;
|
||||||
@@ -24,6 +25,7 @@ pub use note::{PostReplyView, PostView};
|
|||||||
pub use preview::{Preview, PreviewApp, PreviewConfig};
|
pub use preview::{Preview, PreviewApp, PreviewConfig};
|
||||||
pub use profile::ProfileView;
|
pub use profile::ProfileView;
|
||||||
pub use relay::RelayView;
|
pub use relay::RelayView;
|
||||||
|
pub use settings::SettingsView;
|
||||||
pub use side_panel::{DesktopSidePanel, SidePanelAction};
|
pub use side_panel::{DesktopSidePanel, SidePanelAction};
|
||||||
pub use thread::ThreadView;
|
pub use thread::ThreadView;
|
||||||
pub use timeline::TimelineView;
|
pub use timeline::TimelineView;
|
||||||
|
|||||||
459
crates/notedeck_columns/src/ui/settings.rs
Normal file
459
crates/notedeck_columns/src/ui/settings.rs
Normal file
@@ -0,0 +1,459 @@
|
|||||||
|
use egui::{vec2, Button, Color32, ComboBox, Frame, Margin, RichText, ThemePreference};
|
||||||
|
use notedeck::{tr, Images, LanguageIdentifier, Localization, NotedeckTextStyle, ThemeHandler};
|
||||||
|
use notedeck_ui::NoteOptions;
|
||||||
|
use strum::Display;
|
||||||
|
|
||||||
|
use crate::{nav::RouterAction, Damus, Route};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Display)]
|
||||||
|
pub enum ShowNoteClientOptions {
|
||||||
|
Hide,
|
||||||
|
Top,
|
||||||
|
Bottom,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum SettingsAction {
|
||||||
|
SetZoom(f32),
|
||||||
|
SetTheme(ThemePreference),
|
||||||
|
SetShowNoteClient(ShowNoteClientOptions),
|
||||||
|
SetLocale(LanguageIdentifier),
|
||||||
|
OpenRelays,
|
||||||
|
OpenCacheFolder,
|
||||||
|
ClearCacheFolder,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SettingsAction {
|
||||||
|
pub fn process<'a>(
|
||||||
|
self,
|
||||||
|
app: &mut Damus,
|
||||||
|
theme_handler: &'a mut ThemeHandler,
|
||||||
|
i18n: &'a mut Localization,
|
||||||
|
img_cache: &mut Images,
|
||||||
|
ctx: &egui::Context,
|
||||||
|
) -> Option<RouterAction> {
|
||||||
|
let mut route_action: Option<RouterAction> = None;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
SettingsAction::OpenRelays => {
|
||||||
|
route_action = Some(RouterAction::route_to(Route::Relays))
|
||||||
|
}
|
||||||
|
SettingsAction::SetZoom(zoom_level) => {
|
||||||
|
ctx.set_zoom_factor(zoom_level);
|
||||||
|
}
|
||||||
|
SettingsAction::SetShowNoteClient(newvalue) => match newvalue {
|
||||||
|
ShowNoteClientOptions::Hide => {
|
||||||
|
app.note_options.set(NoteOptions::ShowNoteClientTop, false);
|
||||||
|
app.note_options
|
||||||
|
.set(NoteOptions::ShowNoteClientBottom, false);
|
||||||
|
}
|
||||||
|
ShowNoteClientOptions::Bottom => {
|
||||||
|
app.note_options.set(NoteOptions::ShowNoteClientTop, false);
|
||||||
|
app.note_options
|
||||||
|
.set(NoteOptions::ShowNoteClientBottom, true);
|
||||||
|
}
|
||||||
|
ShowNoteClientOptions::Top => {
|
||||||
|
app.note_options.set(NoteOptions::ShowNoteClientTop, true);
|
||||||
|
app.note_options
|
||||||
|
.set(NoteOptions::ShowNoteClientBottom, false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SettingsAction::SetTheme(theme) => {
|
||||||
|
ctx.options_mut(|o| {
|
||||||
|
o.theme_preference = theme;
|
||||||
|
});
|
||||||
|
theme_handler.save(theme);
|
||||||
|
}
|
||||||
|
SettingsAction::SetLocale(language) => {
|
||||||
|
_ = i18n.set_locale(language);
|
||||||
|
}
|
||||||
|
SettingsAction::OpenCacheFolder => {
|
||||||
|
use opener;
|
||||||
|
let _ = opener::open(img_cache.base_path.clone());
|
||||||
|
}
|
||||||
|
SettingsAction::ClearCacheFolder => {
|
||||||
|
let _ = img_cache.clear_folder_contents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
route_action
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SettingsView<'a> {
|
||||||
|
theme: &'a mut String,
|
||||||
|
selected_language: &'a mut String,
|
||||||
|
show_note_client: &'a mut ShowNoteClientOptions,
|
||||||
|
i18n: &'a mut Localization,
|
||||||
|
img_cache: &'a mut Images,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> SettingsView<'a> {
|
||||||
|
pub fn new(
|
||||||
|
img_cache: &'a mut Images,
|
||||||
|
selected_language: &'a mut String,
|
||||||
|
theme: &'a mut String,
|
||||||
|
show_note_client: &'a mut ShowNoteClientOptions,
|
||||||
|
i18n: &'a mut Localization,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
show_note_client,
|
||||||
|
theme,
|
||||||
|
img_cache,
|
||||||
|
selected_language,
|
||||||
|
i18n,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<SettingsAction> {
|
||||||
|
let id = ui.id();
|
||||||
|
let mut action = None;
|
||||||
|
|
||||||
|
Frame::default()
|
||||||
|
.inner_margin(Margin::symmetric(10, 10))
|
||||||
|
.show(ui, |ui| {
|
||||||
|
Frame::group(ui.style())
|
||||||
|
.fill(ui.style().visuals.widgets.open.bg_fill)
|
||||||
|
.inner_margin(10.0)
|
||||||
|
.show(ui, |ui| {
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
ui.label(
|
||||||
|
RichText::new(tr!(
|
||||||
|
self.i18n,
|
||||||
|
"Appearance",
|
||||||
|
"Label for appearance settings section"
|
||||||
|
))
|
||||||
|
.text_style(NotedeckTextStyle::Body.text_style()),
|
||||||
|
);
|
||||||
|
ui.separator();
|
||||||
|
ui.spacing_mut().item_spacing = vec2(10.0, 10.0);
|
||||||
|
|
||||||
|
let current_zoom = ui.ctx().zoom_factor();
|
||||||
|
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label(
|
||||||
|
RichText::new(tr!(
|
||||||
|
self.i18n,
|
||||||
|
"Zoom Level:",
|
||||||
|
"Label for zoom level, Appearance settings section"
|
||||||
|
))
|
||||||
|
.text_style(NotedeckTextStyle::Small.text_style()),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ui
|
||||||
|
.button(
|
||||||
|
RichText::new("-")
|
||||||
|
.text_style(NotedeckTextStyle::Small.text_style()),
|
||||||
|
)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
let new_zoom = (current_zoom - 0.1).max(0.1);
|
||||||
|
action = Some(SettingsAction::SetZoom(new_zoom));
|
||||||
|
};
|
||||||
|
|
||||||
|
ui.label(
|
||||||
|
RichText::new(format!("{:.0}%", current_zoom * 100.0))
|
||||||
|
.text_style(NotedeckTextStyle::Small.text_style()),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ui
|
||||||
|
.button(
|
||||||
|
RichText::new("+")
|
||||||
|
.text_style(NotedeckTextStyle::Small.text_style()),
|
||||||
|
)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
let new_zoom = (current_zoom + 0.1).min(10.0);
|
||||||
|
action = Some(SettingsAction::SetZoom(new_zoom));
|
||||||
|
};
|
||||||
|
|
||||||
|
if ui
|
||||||
|
.button(
|
||||||
|
RichText::new(tr!(
|
||||||
|
self.i18n,
|
||||||
|
"Reset",
|
||||||
|
"Label for reset zoom level, Appearance settings section"
|
||||||
|
))
|
||||||
|
.text_style(NotedeckTextStyle::Small.text_style()),
|
||||||
|
)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
action = Some(SettingsAction::SetZoom(1.0));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label(
|
||||||
|
RichText::new(tr!(
|
||||||
|
self.i18n,
|
||||||
|
"Language:",
|
||||||
|
"Label for language, Appearance settings section"
|
||||||
|
))
|
||||||
|
.text_style(NotedeckTextStyle::Small.text_style()),
|
||||||
|
);
|
||||||
|
ComboBox::from_label("")
|
||||||
|
.selected_text(self.selected_language.to_owned())
|
||||||
|
.show_ui(ui, |ui| {
|
||||||
|
for lang in self.i18n.get_available_locales() {
|
||||||
|
if ui
|
||||||
|
.selectable_value(
|
||||||
|
self.selected_language,
|
||||||
|
lang.to_string(),
|
||||||
|
lang.to_string(),
|
||||||
|
)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
action =
|
||||||
|
Some(SettingsAction::SetLocale(lang.to_owned()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label(
|
||||||
|
RichText::new(tr!(
|
||||||
|
self.i18n,
|
||||||
|
"Theme:",
|
||||||
|
"Label for theme, Appearance settings section"
|
||||||
|
))
|
||||||
|
.text_style(NotedeckTextStyle::Small.text_style()),
|
||||||
|
);
|
||||||
|
if ui
|
||||||
|
.selectable_value(
|
||||||
|
self.theme,
|
||||||
|
"Light".into(),
|
||||||
|
RichText::new(tr!(
|
||||||
|
self.i18n,
|
||||||
|
"Light",
|
||||||
|
"Label for Theme Light, Appearance settings section"
|
||||||
|
))
|
||||||
|
.text_style(NotedeckTextStyle::Small.text_style()),
|
||||||
|
)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
action = Some(SettingsAction::SetTheme(ThemePreference::Light));
|
||||||
|
}
|
||||||
|
if ui
|
||||||
|
.selectable_value(
|
||||||
|
self.theme,
|
||||||
|
"Dark".into(),
|
||||||
|
RichText::new(tr!(
|
||||||
|
self.i18n,
|
||||||
|
"Dark",
|
||||||
|
"Label for Theme Dark, Appearance settings section"
|
||||||
|
))
|
||||||
|
.text_style(NotedeckTextStyle::Small.text_style()),
|
||||||
|
)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
action = Some(SettingsAction::SetTheme(ThemePreference::Dark));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.add_space(5.0);
|
||||||
|
|
||||||
|
Frame::group(ui.style())
|
||||||
|
.fill(ui.style().visuals.widgets.open.bg_fill)
|
||||||
|
.inner_margin(10.0)
|
||||||
|
.show(ui, |ui| {
|
||||||
|
ui.label(
|
||||||
|
RichText::new(tr!(
|
||||||
|
self.i18n,
|
||||||
|
"Storage",
|
||||||
|
"Label for storage settings section"
|
||||||
|
))
|
||||||
|
.text_style(NotedeckTextStyle::Body.text_style()),
|
||||||
|
);
|
||||||
|
ui.separator();
|
||||||
|
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
ui.spacing_mut().item_spacing = vec2(10.0, 10.0);
|
||||||
|
|
||||||
|
ui.horizontal_wrapped(|ui| {
|
||||||
|
let static_imgs_size = self
|
||||||
|
.img_cache
|
||||||
|
.static_imgs
|
||||||
|
.cache_size
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.clone();
|
||||||
|
|
||||||
|
let gifs_size = self.img_cache.gifs.cache_size.lock().unwrap().clone();
|
||||||
|
|
||||||
|
ui.label(
|
||||||
|
RichText::new(format!("{} {}",
|
||||||
|
tr!(
|
||||||
|
self.i18n,
|
||||||
|
"Image cache size:",
|
||||||
|
"Label for Image cache size, Storage settings section"
|
||||||
|
),
|
||||||
|
format_size(
|
||||||
|
[static_imgs_size, gifs_size]
|
||||||
|
.iter()
|
||||||
|
.fold(0_u64, |acc, cur| acc
|
||||||
|
+ cur.unwrap_or_default())
|
||||||
|
)
|
||||||
|
))
|
||||||
|
.text_style(NotedeckTextStyle::Small.text_style()),
|
||||||
|
);
|
||||||
|
|
||||||
|
ui.end_row();
|
||||||
|
|
||||||
|
if !notedeck::ui::is_compiled_as_mobile() {
|
||||||
|
if ui
|
||||||
|
.button(
|
||||||
|
RichText::new(tr!(
|
||||||
|
self.i18n,
|
||||||
|
"View folder:",
|
||||||
|
"Label for view folder button, Storage settings section"
|
||||||
|
))
|
||||||
|
.text_style(NotedeckTextStyle::Small.text_style()),
|
||||||
|
)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
action = Some(SettingsAction::OpenCacheFolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let clearcache_resp = ui.button(
|
||||||
|
RichText::new(tr!(
|
||||||
|
self.i18n,
|
||||||
|
"Clear cache",
|
||||||
|
"Label for clear cache button, Storage settings section"
|
||||||
|
))
|
||||||
|
.text_style(NotedeckTextStyle::Small.text_style())
|
||||||
|
.color(Color32::LIGHT_RED),
|
||||||
|
);
|
||||||
|
|
||||||
|
let id_clearcache = id.with("clear_cache");
|
||||||
|
if clearcache_resp.clicked() {
|
||||||
|
ui.data_mut(|d| d.insert_temp(id_clearcache, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ui.data_mut(|d| *d.get_temp_mut_or_default(id_clearcache)) {
|
||||||
|
let mut confirm_pressed = false;
|
||||||
|
clearcache_resp.show_tooltip_ui(|ui| {
|
||||||
|
let confirm_resp = ui.button(tr!(
|
||||||
|
self.i18n,
|
||||||
|
"Confirm",
|
||||||
|
"Label for confirm clear cache, Storage settings section"
|
||||||
|
));
|
||||||
|
if confirm_resp.clicked() {
|
||||||
|
confirm_pressed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if confirm_resp.clicked() || ui.button(tr!(
|
||||||
|
self.i18n,
|
||||||
|
"Cancel",
|
||||||
|
"Label for cancel clear cache, Storage settings section"
|
||||||
|
)).clicked() {
|
||||||
|
ui.data_mut(|d| d.insert_temp(id_clearcache, false));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if confirm_pressed {
|
||||||
|
action = Some(SettingsAction::ClearCacheFolder);
|
||||||
|
} else if !confirm_pressed
|
||||||
|
&& clearcache_resp.clicked_elsewhere()
|
||||||
|
{
|
||||||
|
ui.data_mut(|d| d.insert_temp(id_clearcache, false));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.add_space(5.0);
|
||||||
|
|
||||||
|
Frame::group(ui.style())
|
||||||
|
.fill(ui.style().visuals.widgets.open.bg_fill)
|
||||||
|
.inner_margin(10.0)
|
||||||
|
.show(ui, |ui| {
|
||||||
|
ui.label(
|
||||||
|
RichText::new(tr!(
|
||||||
|
self.i18n,
|
||||||
|
"Others",
|
||||||
|
"Label for others settings section"
|
||||||
|
))
|
||||||
|
.text_style(NotedeckTextStyle::Body.text_style()),
|
||||||
|
);
|
||||||
|
ui.separator();
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
ui.spacing_mut().item_spacing = vec2(10.0, 10.0);
|
||||||
|
|
||||||
|
ui.horizontal_wrapped(|ui| {
|
||||||
|
ui.label(
|
||||||
|
RichText::new(
|
||||||
|
tr!(
|
||||||
|
self.i18n,
|
||||||
|
"Show source client",
|
||||||
|
"Label for Show source client, others settings section"
|
||||||
|
))
|
||||||
|
.text_style(NotedeckTextStyle::Small.text_style()),
|
||||||
|
);
|
||||||
|
|
||||||
|
for option in [
|
||||||
|
ShowNoteClientOptions::Hide,
|
||||||
|
ShowNoteClientOptions::Top,
|
||||||
|
ShowNoteClientOptions::Bottom,
|
||||||
|
] {
|
||||||
|
let label = option.clone().to_string();
|
||||||
|
|
||||||
|
if ui
|
||||||
|
.selectable_value(
|
||||||
|
self.show_note_client,
|
||||||
|
option,
|
||||||
|
RichText::new(label)
|
||||||
|
.text_style(NotedeckTextStyle::Small.text_style()),
|
||||||
|
)
|
||||||
|
.changed()
|
||||||
|
{
|
||||||
|
action = Some(SettingsAction::SetShowNoteClient(option));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.add_space(10.0);
|
||||||
|
|
||||||
|
if ui
|
||||||
|
.add_sized(
|
||||||
|
[ui.available_width(), 30.0],
|
||||||
|
Button::new(
|
||||||
|
RichText::new(tr!(
|
||||||
|
self.i18n,
|
||||||
|
"Configure relays",
|
||||||
|
"Label for configure relays, settings section"
|
||||||
|
))
|
||||||
|
.text_style(NotedeckTextStyle::Small.text_style()),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
action = Some(SettingsAction::OpenRelays);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
action
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_size(size_bytes: u64) -> String {
|
||||||
|
const KB: f64 = 1024.0;
|
||||||
|
const MB: f64 = KB * 1024.0;
|
||||||
|
const GB: f64 = MB * 1024.0;
|
||||||
|
|
||||||
|
let size = size_bytes as f64;
|
||||||
|
|
||||||
|
if size < KB {
|
||||||
|
format!("{:.0} Bytes", size)
|
||||||
|
} else if size < MB {
|
||||||
|
format!("{:.1} KB", size / KB)
|
||||||
|
} else if size < GB {
|
||||||
|
format!("{:.1} MB", size / MB)
|
||||||
|
} else {
|
||||||
|
format!("{:.2} GB", size / GB)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -46,6 +46,9 @@ impl<'a, 'd> NoteContents<'a, 'd> {
|
|||||||
|
|
||||||
impl egui::Widget for &mut NoteContents<'_, '_> {
|
impl egui::Widget for &mut NoteContents<'_, '_> {
|
||||||
fn ui(self, ui: &mut egui::Ui) -> egui::Response {
|
fn ui(self, ui: &mut egui::Ui) -> egui::Response {
|
||||||
|
if self.options.contains(NoteOptions::ShowNoteClientTop) {
|
||||||
|
render_client(ui, self.note_context.note_cache, self.note);
|
||||||
|
}
|
||||||
let result = render_note_contents(
|
let result = render_note_contents(
|
||||||
ui,
|
ui,
|
||||||
self.note_context,
|
self.note_context,
|
||||||
@@ -54,7 +57,7 @@ impl egui::Widget for &mut NoteContents<'_, '_> {
|
|||||||
self.options,
|
self.options,
|
||||||
self.jobs,
|
self.jobs,
|
||||||
);
|
);
|
||||||
if self.options.contains(NoteOptions::ShowNoteClient) {
|
if self.options.contains(NoteOptions::ShowNoteClientBottom) {
|
||||||
render_client(ui, self.note_context.note_cache, self.note);
|
render_client(ui, self.note_context.note_cache, self.note);
|
||||||
}
|
}
|
||||||
self.action = result.action;
|
self.action = result.action;
|
||||||
|
|||||||
@@ -235,11 +235,24 @@ fn get_selected_index(ui: &egui::Ui, selection_id: egui::Id) -> usize {
|
|||||||
/// Checks to see if we have any left/right key presses and updates the carousel index
|
/// Checks to see if we have any left/right key presses and updates the carousel index
|
||||||
fn update_selected_image_index(ui: &mut egui::Ui, carousel_id: egui::Id, num_urls: i32) -> usize {
|
fn update_selected_image_index(ui: &mut egui::Ui, carousel_id: egui::Id, num_urls: i32) -> usize {
|
||||||
if num_urls > 1 {
|
if num_urls > 1 {
|
||||||
if ui.input(|i| i.key_pressed(egui::Key::ArrowRight) || i.key_pressed(egui::Key::L)) {
|
let (next_image, prev_image) = ui.data(|data| {
|
||||||
|
(
|
||||||
|
data.get_temp(carousel_id.with("next_image"))
|
||||||
|
.unwrap_or_default(),
|
||||||
|
data.get_temp(carousel_id.with("prev_image"))
|
||||||
|
.unwrap_or_default(),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
if next_image
|
||||||
|
|| ui.input(|i| i.key_pressed(egui::Key::ArrowRight) || i.key_pressed(egui::Key::L))
|
||||||
|
{
|
||||||
let ind = select_next_media(ui, carousel_id, num_urls, 1);
|
let ind = select_next_media(ui, carousel_id, num_urls, 1);
|
||||||
tracing::debug!("carousel selecting right {}/{}", ind + 1, num_urls);
|
tracing::debug!("carousel selecting right {}/{}", ind + 1, num_urls);
|
||||||
ind
|
ind
|
||||||
} else if ui.input(|i| i.key_pressed(egui::Key::ArrowLeft) || i.key_pressed(egui::Key::H)) {
|
} else if prev_image
|
||||||
|
|| ui.input(|i| i.key_pressed(egui::Key::ArrowLeft) || i.key_pressed(egui::Key::H))
|
||||||
|
{
|
||||||
let ind = select_next_media(ui, carousel_id, num_urls, -1);
|
let ind = select_next_media(ui, carousel_id, num_urls, -1);
|
||||||
tracing::debug!("carousel selecting left {}/{}", ind + 1, num_urls);
|
tracing::debug!("carousel selecting left {}/{}", ind + 1, num_urls);
|
||||||
ind
|
ind
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ bitflags! {
|
|||||||
/// will end with a ... and a "Show more" button.
|
/// will end with a ... and a "Show more" button.
|
||||||
const Truncate = 1 << 11;
|
const Truncate = 1 << 11;
|
||||||
/// Show note's client in the note header
|
/// Show note's client in the note header
|
||||||
const ShowNoteClient = 1 << 12;
|
const ShowNoteClientTop = 1 << 12;
|
||||||
|
const ShowNoteClientBottom = 1 << 13;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ pub fn display_name_widget<'a>(
|
|||||||
|
|
||||||
let nip05_resp = name.nip05.map(|nip05| {
|
let nip05_resp = name.nip05.map(|nip05| {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
|
ui.spacing_mut().item_spacing.x = 2.0;
|
||||||
|
|
||||||
ui.add(app_images::verified_image());
|
ui.add(app_images::verified_image());
|
||||||
|
|
||||||
ui.label(RichText::new(nip05).size(16.0).color(crate::colors::TEAL))
|
ui.label(RichText::new(nip05).size(16.0).color(crate::colors::TEAL))
|
||||||
|
|||||||
Reference in New Issue
Block a user