mirror of
https://github.com/aljazceru/notedeck.git
synced 2025-12-21 10:14:19 +01:00
feat(mobile): improve layout and behavior on narrow screens
This commit is contained in:
committed by
William Casarin
parent
f25735f89e
commit
ec25413433
@@ -2,7 +2,7 @@
|
|||||||
//#[cfg(target_arch = "wasm32")]
|
//#[cfg(target_arch = "wasm32")]
|
||||||
//use wasm_bindgen::prelude::*;
|
//use wasm_bindgen::prelude::*;
|
||||||
use crate::app::NotedeckApp;
|
use crate::app::NotedeckApp;
|
||||||
use egui::{vec2, Button, Label, Layout, Rect, RichText, ThemePreference, Widget};
|
use egui::{vec2, Button, Color32, Label, Layout, Rect, RichText, ThemePreference, Widget};
|
||||||
use egui_extras::{Size, StripBuilder};
|
use egui_extras::{Size, StripBuilder};
|
||||||
use nostrdb::{ProfileRecord, Transaction};
|
use nostrdb::{ProfileRecord, Transaction};
|
||||||
use notedeck::{App, AppAction, AppContext, NotedeckTextStyle, UserAccount, WalletType};
|
use notedeck::{App, AppAction, AppContext, NotedeckTextStyle, UserAccount, WalletType};
|
||||||
@@ -207,8 +207,8 @@ impl Chrome {
|
|||||||
.size(Size::exact(amt_open)) // collapsible sidebar
|
.size(Size::exact(amt_open)) // collapsible sidebar
|
||||||
.size(Size::remainder()) // the main app contents
|
.size(Size::remainder()) // the main app contents
|
||||||
.clip(true)
|
.clip(true)
|
||||||
.horizontal(|mut strip| {
|
.horizontal(|mut hstrip| {
|
||||||
strip.cell(|ui| {
|
hstrip.cell(|ui| {
|
||||||
let rect = ui.available_rect_before_wrap();
|
let rect = ui.available_rect_before_wrap();
|
||||||
if !ui.visuals().dark_mode {
|
if !ui.visuals().dark_mode {
|
||||||
let rect = ui.available_rect_before_wrap();
|
let rect = ui.available_rect_before_wrap();
|
||||||
@@ -216,20 +216,28 @@ impl Chrome {
|
|||||||
rect,
|
rect,
|
||||||
0,
|
0,
|
||||||
notedeck_ui::colors::ALMOST_WHITE,
|
notedeck_ui::colors::ALMOST_WHITE,
|
||||||
egui::Stroke::new(0.0, egui::Color32::TRANSPARENT),
|
egui::Stroke::new(0.0, Color32::TRANSPARENT),
|
||||||
egui::StrokeKind::Inside,
|
egui::StrokeKind::Inside,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.with_layout(Layout::top_down(egui::Align::Center), |ui| {
|
StripBuilder::new(ui)
|
||||||
|
.size(Size::remainder())
|
||||||
|
.size(Size::remainder())
|
||||||
|
.vertical(|mut vstrip| {
|
||||||
|
vstrip.cell(|ui| {
|
||||||
|
_ = ui.vertical_centered(|ui| {
|
||||||
self.topdown_sidebar(ui);
|
self.topdown_sidebar(ui);
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
vstrip.cell(|ui| {
|
||||||
ui.with_layout(Layout::bottom_up(egui::Align::Center), |ui| {
|
ui.with_layout(Layout::bottom_up(egui::Align::Center), |ui| {
|
||||||
if let Some(action) = bottomup_sidebar(self, app_ctx, ui) {
|
if let Some(action) = bottomup_sidebar(self, app_ctx, ui) {
|
||||||
got_action = Some(action);
|
got_action = Some(action);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// vertical sidebar line
|
// vertical sidebar line
|
||||||
ui.painter().vline(
|
ui.painter().vline(
|
||||||
@@ -239,7 +247,7 @@ impl Chrome {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
strip.cell(|ui| {
|
hstrip.cell(|ui| {
|
||||||
/*
|
/*
|
||||||
let rect = ui.available_rect_before_wrap();
|
let rect = ui.available_rect_before_wrap();
|
||||||
ui.painter().rect(
|
ui.painter().rect(
|
||||||
@@ -286,7 +294,6 @@ impl Chrome {
|
|||||||
.vertical(|mut strip| {
|
.vertical(|mut strip| {
|
||||||
strip.strip(|builder| {
|
strip.strip(|builder| {
|
||||||
// the chrome panel is nested above the toolbar
|
// the chrome panel is nested above the toolbar
|
||||||
|
|
||||||
got_action = self.panel(ctx, builder, amt_open);
|
got_action = self.panel(ctx, builder, amt_open);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -303,6 +310,23 @@ impl Chrome {
|
|||||||
fn toolbar(&mut self, ui: &mut egui::Ui) -> Option<ToolbarAction> {
|
fn toolbar(&mut self, ui: &mut egui::Ui) -> Option<ToolbarAction> {
|
||||||
use egui_tabs::{TabColor, Tabs};
|
use egui_tabs::{TabColor, Tabs};
|
||||||
|
|
||||||
|
let rect = ui.available_rect_before_wrap();
|
||||||
|
ui.painter().hline(
|
||||||
|
rect.x_range(),
|
||||||
|
rect.top(),
|
||||||
|
ui.visuals().widgets.noninteractive.bg_stroke,
|
||||||
|
);
|
||||||
|
|
||||||
|
if !ui.visuals().dark_mode {
|
||||||
|
ui.painter().rect(
|
||||||
|
rect,
|
||||||
|
0,
|
||||||
|
notedeck_ui::colors::ALMOST_WHITE,
|
||||||
|
egui::Stroke::new(0.0, Color32::TRANSPARENT),
|
||||||
|
egui::StrokeKind::Inside,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let rs = Tabs::new(3)
|
let rs = Tabs::new(3)
|
||||||
.selected(self.tab_selected)
|
.selected(self.tab_selected)
|
||||||
.hover_bg(TabColor::none())
|
.hover_bg(TabColor::none())
|
||||||
@@ -496,8 +520,8 @@ fn notifications_button(ui: &mut egui::Ui) -> egui::Response {
|
|||||||
expanding_button(
|
expanding_button(
|
||||||
"notifications-button",
|
"notifications-button",
|
||||||
24.0,
|
24.0,
|
||||||
app_images::notifications_button_image(),
|
app_images::notifications_light_image(),
|
||||||
app_images::notifications_button_image(),
|
app_images::notifications_dark_image(),
|
||||||
ui,
|
ui,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -506,8 +530,8 @@ fn home_button(ui: &mut egui::Ui) -> egui::Response {
|
|||||||
expanding_button(
|
expanding_button(
|
||||||
"home-button",
|
"home-button",
|
||||||
24.0,
|
24.0,
|
||||||
app_images::home_button_image(),
|
app_images::home_light_image(),
|
||||||
app_images::home_button_image(),
|
app_images::home_dark_image(),
|
||||||
ui,
|
ui,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ use crate::{
|
|||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
use notedeck::{Accounts, AppAction, AppContext, DataPath, DataPathType, FilterState, UnknownIds};
|
use notedeck::{
|
||||||
|
ui::is_narrow, Accounts, AppAction, AppContext, DataPath, DataPathType, FilterState, UnknownIds,
|
||||||
|
};
|
||||||
use notedeck_ui::{jobs::JobsCache, NoteOptions};
|
use notedeck_ui::{jobs::JobsCache, NoteOptions};
|
||||||
|
|
||||||
use enostr::{ClientMessage, PoolRelay, Pubkey, RelayEvent, RelayMessage, RelayPool};
|
use enostr::{ClientMessage, PoolRelay, Pubkey, RelayEvent, RelayMessage, RelayPool};
|
||||||
@@ -561,14 +563,22 @@ fn render_damus_mobile(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rect.min.x = rect.max.x - 100.0;
|
rect.min.x = rect.max.x - if is_narrow(ui.ctx()) { 60.0 } else { 100.0 };
|
||||||
rect.min.y = rect.max.y - 100.0;
|
rect.min.y = rect.max.y - 100.0;
|
||||||
|
|
||||||
let interactive = true;
|
let is_interactive = app_ctx
|
||||||
|
.accounts
|
||||||
|
.get_selected_account()
|
||||||
|
.key
|
||||||
|
.secret_key
|
||||||
|
.is_some();
|
||||||
let darkmode = ui.ctx().style().visuals.dark_mode;
|
let darkmode = ui.ctx().style().visuals.dark_mode;
|
||||||
|
|
||||||
if ui
|
if ui
|
||||||
.put(rect, ui::post::compose_note_button(interactive, darkmode))
|
.put(
|
||||||
|
rect,
|
||||||
|
ui::post::compose_note_button(is_interactive, darkmode),
|
||||||
|
)
|
||||||
.clicked()
|
.clicked()
|
||||||
&& !app.columns(app_ctx.accounts).columns().is_empty()
|
&& !app.columns(app_ctx.accounts).columns().is_empty()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ impl<'a> AddColumnView<'a> {
|
|||||||
ScrollArea::vertical()
|
ScrollArea::vertical()
|
||||||
.show(ui, |ui| {
|
.show(ui, |ui| {
|
||||||
let mut selected_option: Option<AddColumnResponse> = None;
|
let mut selected_option: Option<AddColumnResponse> = None;
|
||||||
for column_option_data in self.get_base_options() {
|
for column_option_data in self.get_base_options(ui) {
|
||||||
let option = column_option_data.option.clone();
|
let option = column_option_data.option.clone();
|
||||||
if self.column_option_ui(ui, column_option_data).clicked() {
|
if self.column_option_ui(ui, column_option_data).clicked() {
|
||||||
selected_option = Some(option.take_as_response(self.cur_account));
|
selected_option = Some(option.take_as_response(self.cur_account));
|
||||||
@@ -203,7 +203,7 @@ impl<'a> AddColumnView<'a> {
|
|||||||
|
|
||||||
fn notifications_ui(&mut self, ui: &mut Ui) -> Option<AddColumnResponse> {
|
fn notifications_ui(&mut self, ui: &mut Ui) -> Option<AddColumnResponse> {
|
||||||
let mut selected_option: Option<AddColumnResponse> = None;
|
let mut selected_option: Option<AddColumnResponse> = None;
|
||||||
for column_option_data in self.get_notifications_options() {
|
for column_option_data in self.get_notifications_options(ui) {
|
||||||
let option = column_option_data.option.clone();
|
let option = column_option_data.option.clone();
|
||||||
if self.column_option_ui(ui, column_option_data).clicked() {
|
if self.column_option_ui(ui, column_option_data).clicked() {
|
||||||
selected_option = Some(option.take_as_response(self.cur_account));
|
selected_option = Some(option.take_as_response(self.cur_account));
|
||||||
@@ -441,7 +441,7 @@ impl<'a> AddColumnView<'a> {
|
|||||||
helper.take_animation_response()
|
helper.take_animation_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_base_options(&self) -> Vec<ColumnOptionData> {
|
fn get_base_options(&self, ui: &mut Ui) -> Vec<ColumnOptionData> {
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
vec.push(ColumnOptionData {
|
vec.push(ColumnOptionData {
|
||||||
title: "Universe",
|
title: "Universe",
|
||||||
@@ -465,7 +465,7 @@ impl<'a> AddColumnView<'a> {
|
|||||||
vec.push(ColumnOptionData {
|
vec.push(ColumnOptionData {
|
||||||
title: "Notifications",
|
title: "Notifications",
|
||||||
description: "Stay up to date with notifications and mentions",
|
description: "Stay up to date with notifications and mentions",
|
||||||
icon: app_images::notifications_image(),
|
icon: app_images::notifications_image(ui.visuals().dark_mode),
|
||||||
option: AddColumnOption::UndecidedNotification,
|
option: AddColumnOption::UndecidedNotification,
|
||||||
});
|
});
|
||||||
vec.push(ColumnOptionData {
|
vec.push(ColumnOptionData {
|
||||||
@@ -490,7 +490,7 @@ impl<'a> AddColumnView<'a> {
|
|||||||
vec
|
vec
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_notifications_options(&self) -> Vec<ColumnOptionData> {
|
fn get_notifications_options(&self, ui: &mut Ui) -> Vec<ColumnOptionData> {
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
|
|
||||||
let source = if self.cur_account.key.secret_key.is_some() {
|
let source = if self.cur_account.key.secret_key.is_some() {
|
||||||
@@ -502,14 +502,14 @@ impl<'a> AddColumnView<'a> {
|
|||||||
vec.push(ColumnOptionData {
|
vec.push(ColumnOptionData {
|
||||||
title: "Your Notifications",
|
title: "Your Notifications",
|
||||||
description: "Stay up to date with your notifications and mentions",
|
description: "Stay up to date with your notifications and mentions",
|
||||||
icon: app_images::notifications_image(),
|
icon: app_images::notifications_image(ui.visuals().dark_mode),
|
||||||
option: AddColumnOption::Notification(source),
|
option: AddColumnOption::Notification(source),
|
||||||
});
|
});
|
||||||
|
|
||||||
vec.push(ColumnOptionData {
|
vec.push(ColumnOptionData {
|
||||||
title: "Someone else's Notifications",
|
title: "Someone else's Notifications",
|
||||||
description: "Stay up to date with someone else's notifications and mentions",
|
description: "Stay up to date with someone else's notifications and mentions",
|
||||||
icon: app_images::notifications_image(),
|
icon: app_images::notifications_image(ui.visuals().dark_mode),
|
||||||
option: AddColumnOption::ExternalNotification,
|
option: AddColumnOption::ExternalNotification,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use egui::{vec2, Direction, Layout, Pos2, Stroke};
|
|||||||
use egui_tabs::TabColor;
|
use egui_tabs::TabColor;
|
||||||
use enostr::KeypairUnowned;
|
use enostr::KeypairUnowned;
|
||||||
use nostrdb::Transaction;
|
use nostrdb::Transaction;
|
||||||
|
use notedeck::ui::is_narrow;
|
||||||
use notedeck_ui::jobs::JobsCache;
|
use notedeck_ui::jobs::JobsCache;
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
use tracing::{error, warn};
|
use tracing::{error, warn};
|
||||||
@@ -114,7 +115,9 @@ fn timeline_ui(
|
|||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
|
|
||||||
let goto_top_resp = if show_top_button {
|
let goto_top_resp = if show_top_button {
|
||||||
let top_button_pos = ui.available_rect_before_wrap().right_top() - vec2(48.0, -24.0);
|
let top_button_pos_x = if is_narrow(ui.ctx()) { 28.0 } else { 48.0 };
|
||||||
|
let top_button_pos =
|
||||||
|
ui.available_rect_before_wrap().right_top() - vec2(top_button_pos_x, -24.0);
|
||||||
egui::Area::new(ui.id().with("foreground_area"))
|
egui::Area::new(ui.id().with("foreground_area"))
|
||||||
.order(egui::Order::Middle)
|
.order(egui::Order::Middle)
|
||||||
.fixed_pos(top_button_pos)
|
.fixed_pos(top_button_pos)
|
||||||
|
|||||||
@@ -113,10 +113,14 @@ pub fn help_light_image() -> Image<'static> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn home_button_image() -> Image<'static> {
|
pub fn home_dark_image() -> Image<'static> {
|
||||||
Image::new(include_image!("../../../assets/icons/home-toolbar.png"))
|
Image::new(include_image!("../../../assets/icons/home-toolbar.png"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn home_light_image() -> Image<'static> {
|
||||||
|
home_dark_image().tint(Color32::BLACK)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn home_image() -> Image<'static> {
|
pub fn home_image() -> Image<'static> {
|
||||||
Image::new(include_image!(
|
Image::new(include_image!(
|
||||||
"../../../assets/icons/home_icon_dark_4x.png"
|
"../../../assets/icons/home_icon_dark_4x.png"
|
||||||
@@ -141,16 +145,22 @@ pub fn new_deck_image() -> Image<'static> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn notifications_button_image() -> Image<'static> {
|
pub fn notifications_image(dark_mode: bool) -> Image<'static> {
|
||||||
|
if dark_mode {
|
||||||
|
crate::app_images::notifications_dark_image()
|
||||||
|
} else {
|
||||||
|
crate::app_images::notifications_light_image()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn notifications_dark_image() -> Image<'static> {
|
||||||
Image::new(include_image!(
|
Image::new(include_image!(
|
||||||
"../../../assets/icons/notifications_dark_4x.png"
|
"../../../assets/icons/notifications_dark_4x.png"
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn notifications_image() -> Image<'static> {
|
pub fn notifications_light_image() -> Image<'static> {
|
||||||
Image::new(include_image!(
|
notifications_dark_image().tint(Color32::BLACK)
|
||||||
"../../../assets/icons/notifications_icon_dark_4x.png"
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
pub fn repost_dark_image() -> Image<'static> {
|
pub fn repost_dark_image() -> Image<'static> {
|
||||||
Image::new(include_image!("../../../assets/icons/repost.svg"))
|
Image::new(include_image!("../../../assets/icons/repost.svg"))
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ pub use contents::{render_note_contents, render_note_preview, NoteContents};
|
|||||||
pub use context::NoteContextButton;
|
pub use context::NoteContextButton;
|
||||||
use notedeck::note::MediaAction;
|
use notedeck::note::MediaAction;
|
||||||
use notedeck::note::ZapTargetAmount;
|
use notedeck::note::ZapTargetAmount;
|
||||||
|
use notedeck::ui::is_narrow;
|
||||||
use notedeck::Images;
|
use notedeck::Images;
|
||||||
pub use options::NoteOptions;
|
pub use options::NoteOptions;
|
||||||
pub use reply_description::reply_desc;
|
pub use reply_description::reply_desc;
|
||||||
@@ -253,6 +254,10 @@ impl<'a, 'd> NoteView<'a, 'd> {
|
|||||||
ui.spacing_mut().item_spacing.x = 4.0;
|
ui.spacing_mut().item_spacing.x = 4.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if is_narrow(ui.ctx()) {
|
||||||
|
ui.spacing_mut().item_spacing.x = 1.0
|
||||||
|
}
|
||||||
|
|
||||||
let pfp_size = self.options().pfp_size();
|
let pfp_size = self.options().pfp_size();
|
||||||
|
|
||||||
match profile
|
match profile
|
||||||
@@ -363,7 +368,7 @@ impl<'a, 'd> NoteView<'a, 'd> {
|
|||||||
|
|
||||||
let horiz_resp = ui
|
let horiz_resp = ui
|
||||||
.horizontal(|ui| {
|
.horizontal(|ui| {
|
||||||
ui.spacing_mut().item_spacing.x = 2.0;
|
ui.spacing_mut().item_spacing.x = if is_narrow(ui.ctx()) { 1.0 } else { 2.0 };
|
||||||
ui.add(Username::new(profile.as_ref().ok(), note.pubkey()).abbreviated(20));
|
ui.add(Username::new(profile.as_ref().ok(), note.pubkey()).abbreviated(20));
|
||||||
|
|
||||||
let cached_note = note_cache.cached_note_or_insert_mut(note_key, note);
|
let cached_note = note_cache.cached_note_or_insert_mut(note_key, note);
|
||||||
@@ -507,7 +512,7 @@ impl<'a, 'd> NoteView<'a, 'd> {
|
|||||||
self.show_unread_indicator,
|
self.show_unread_indicator,
|
||||||
);
|
);
|
||||||
ui.horizontal(|ui| 's: {
|
ui.horizontal(|ui| 's: {
|
||||||
ui.spacing_mut().item_spacing.x = 2.0;
|
ui.spacing_mut().item_spacing.x = if is_narrow(ui.ctx()) { 1.0 } else { 2.0 };
|
||||||
|
|
||||||
let note_reply = self
|
let note_reply = self
|
||||||
.note_context
|
.note_context
|
||||||
|
|||||||
Reference in New Issue
Block a user