mirror of
https://github.com/damus-io/notedeck.git
synced 2024-10-18 11:13:23 +00:00
Merge side panel update #327
A few merge conflicts resolved, and changes the image to svg kernelkind (7): initial compose note view change side panel width to 64.0 Add AnimationHelper update sidebar to match new design remove app from sidebar remove profile_preview_controller add logo to side panel Closes: https://github.com/damus-io/notedeck/pull/327
This commit is contained in:
commit
7fe3d5e99f
334
assets/damus_rounded.svg
Normal file
334
assets/damus_rounded.svg
Normal file
@ -0,0 +1,334 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="256mm"
|
||||||
|
height="256mm"
|
||||||
|
viewBox="0 0 256 256"
|
||||||
|
version="1.1"
|
||||||
|
id="svg5"
|
||||||
|
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
|
||||||
|
sodipodi:docname="damus_rounded.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview7"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:blackoutopacity="0.0"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="0.5946522"
|
||||||
|
inkscape:cx="405.27892"
|
||||||
|
inkscape:cy="543.17465"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1080"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:deskcolor="#d1d1d1" />
|
||||||
|
<defs
|
||||||
|
id="defs2">
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="fillet_chamfer"
|
||||||
|
id="path-effect9"
|
||||||
|
is_visible="true"
|
||||||
|
lpeversion="1"
|
||||||
|
nodesatellites_param="F,0,0,1,0,80,0,1 @ F,0,1,1,0,80,0,1 @ F,0,0,1,0,80,0,1 @ F,0,0,1,0,80,0,1"
|
||||||
|
radius="0"
|
||||||
|
unit="px"
|
||||||
|
method="auto"
|
||||||
|
mode="F"
|
||||||
|
chamfer_steps="1"
|
||||||
|
flexible="false"
|
||||||
|
use_knot_distance="true"
|
||||||
|
apply_no_radius="true"
|
||||||
|
apply_with_radius="true"
|
||||||
|
only_selected="false"
|
||||||
|
hide_knots="false" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="fillet_chamfer"
|
||||||
|
id="path-effect8"
|
||||||
|
is_visible="true"
|
||||||
|
lpeversion="1"
|
||||||
|
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||||
|
radius="0"
|
||||||
|
unit="px"
|
||||||
|
method="auto"
|
||||||
|
mode="F"
|
||||||
|
chamfer_steps="1"
|
||||||
|
flexible="false"
|
||||||
|
use_knot_distance="true"
|
||||||
|
apply_no_radius="true"
|
||||||
|
apply_with_radius="true"
|
||||||
|
only_selected="false"
|
||||||
|
hide_knots="false" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="fillet_chamfer"
|
||||||
|
id="path-effect7"
|
||||||
|
is_visible="true"
|
||||||
|
lpeversion="1"
|
||||||
|
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||||
|
radius="0"
|
||||||
|
unit="px"
|
||||||
|
method="auto"
|
||||||
|
mode="F"
|
||||||
|
chamfer_steps="1"
|
||||||
|
flexible="false"
|
||||||
|
use_knot_distance="true"
|
||||||
|
apply_no_radius="true"
|
||||||
|
apply_with_radius="true"
|
||||||
|
only_selected="false"
|
||||||
|
hide_knots="false" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="fillet_chamfer"
|
||||||
|
id="path-effect6"
|
||||||
|
is_visible="true"
|
||||||
|
lpeversion="1"
|
||||||
|
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||||
|
radius="0"
|
||||||
|
unit="px"
|
||||||
|
method="auto"
|
||||||
|
mode="F"
|
||||||
|
chamfer_steps="1"
|
||||||
|
flexible="false"
|
||||||
|
use_knot_distance="true"
|
||||||
|
apply_no_radius="true"
|
||||||
|
apply_with_radius="true"
|
||||||
|
only_selected="false"
|
||||||
|
hide_knots="false" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="fillet_chamfer"
|
||||||
|
id="path-effect5"
|
||||||
|
is_visible="true"
|
||||||
|
lpeversion="1"
|
||||||
|
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||||
|
radius="0"
|
||||||
|
unit="px"
|
||||||
|
method="auto"
|
||||||
|
mode="F"
|
||||||
|
chamfer_steps="1"
|
||||||
|
flexible="false"
|
||||||
|
use_knot_distance="true"
|
||||||
|
apply_no_radius="true"
|
||||||
|
apply_with_radius="true"
|
||||||
|
only_selected="false"
|
||||||
|
hide_knots="false" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="fillet_chamfer"
|
||||||
|
id="path-effect4"
|
||||||
|
is_visible="true"
|
||||||
|
lpeversion="1"
|
||||||
|
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||||
|
radius="0"
|
||||||
|
unit="px"
|
||||||
|
method="auto"
|
||||||
|
mode="F"
|
||||||
|
chamfer_steps="1"
|
||||||
|
flexible="false"
|
||||||
|
use_knot_distance="true"
|
||||||
|
apply_no_radius="true"
|
||||||
|
apply_with_radius="true"
|
||||||
|
only_selected="false"
|
||||||
|
hide_knots="false" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="fillet_chamfer"
|
||||||
|
id="path-effect3"
|
||||||
|
is_visible="true"
|
||||||
|
lpeversion="1"
|
||||||
|
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||||
|
radius="0"
|
||||||
|
unit="px"
|
||||||
|
method="auto"
|
||||||
|
mode="F"
|
||||||
|
chamfer_steps="1"
|
||||||
|
flexible="false"
|
||||||
|
use_knot_distance="true"
|
||||||
|
apply_no_radius="true"
|
||||||
|
apply_with_radius="true"
|
||||||
|
only_selected="false"
|
||||||
|
hide_knots="false" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="fillet_chamfer"
|
||||||
|
id="path-effect2"
|
||||||
|
is_visible="true"
|
||||||
|
lpeversion="1"
|
||||||
|
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||||
|
radius="0"
|
||||||
|
unit="px"
|
||||||
|
method="auto"
|
||||||
|
mode="F"
|
||||||
|
chamfer_steps="1"
|
||||||
|
flexible="false"
|
||||||
|
use_knot_distance="true"
|
||||||
|
apply_no_radius="true"
|
||||||
|
apply_with_radius="true"
|
||||||
|
only_selected="false"
|
||||||
|
hide_knots="false" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="fillet_chamfer"
|
||||||
|
id="path-effect1"
|
||||||
|
is_visible="true"
|
||||||
|
lpeversion="1"
|
||||||
|
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||||
|
radius="0"
|
||||||
|
unit="px"
|
||||||
|
method="auto"
|
||||||
|
mode="F"
|
||||||
|
chamfer_steps="1"
|
||||||
|
flexible="false"
|
||||||
|
use_knot_distance="true"
|
||||||
|
apply_no_radius="true"
|
||||||
|
apply_with_radius="true"
|
||||||
|
only_selected="false"
|
||||||
|
hide_knots="false" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient39361">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#0de8ff;stop-opacity:0.78082192;"
|
||||||
|
offset="0"
|
||||||
|
id="stop39357" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#d600fc;stop-opacity:0.95433789;"
|
||||||
|
offset="1"
|
||||||
|
id="stop39359" />
|
||||||
|
</linearGradient>
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="bspline"
|
||||||
|
id="path-effect255"
|
||||||
|
is_visible="true"
|
||||||
|
lpeversion="1"
|
||||||
|
weight="33.333333"
|
||||||
|
steps="2"
|
||||||
|
helper_size="0"
|
||||||
|
apply_no_weight="true"
|
||||||
|
apply_with_weight="true"
|
||||||
|
only_selected="false" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient2119">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#1c55ff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop2115" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#7f35ab;stop-opacity:1;"
|
||||||
|
offset="0.5"
|
||||||
|
id="stop2123" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ff0bd6;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop2117" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2119"
|
||||||
|
id="linearGradient2121"
|
||||||
|
x1="10.067794"
|
||||||
|
y1="248.81357"
|
||||||
|
x2="246.56145"
|
||||||
|
y2="7.1864405"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient39361"
|
||||||
|
id="linearGradient39367"
|
||||||
|
x1="62.104473"
|
||||||
|
y1="128.78963"
|
||||||
|
x2="208.25758"
|
||||||
|
y2="128.78963"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
</defs>
|
||||||
|
<g
|
||||||
|
inkscape:label="Background"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
sodipodi:insensitive="true">
|
||||||
|
<path
|
||||||
|
id="rect61"
|
||||||
|
style="fill:url(#linearGradient2121);stroke-width:0.264583;opacity:1"
|
||||||
|
inkscape:label="Gradient"
|
||||||
|
d="m 80,-1.0775033e-7 h 96 A 80,80 45 0 1 256,80 v 96 a 80,80 135 0 1 -80,80 H 80 A 80,80 45 0 1 -5.3875166e-8,176 V 80 A 80,80 135 0 1 80,-1.0775033e-7 Z"
|
||||||
|
inkscape:path-effect="#path-effect9"
|
||||||
|
inkscape:original-d="M -5.3875166e-8,-1.0775033e-7 H 256 V 256 H -5.3875166e-8 Z" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g407"
|
||||||
|
inkscape:label="Logo">
|
||||||
|
<g
|
||||||
|
id="layer2"
|
||||||
|
inkscape:label="LogoStroke"
|
||||||
|
style="display:inline">
|
||||||
|
<path
|
||||||
|
style="fill:url(#linearGradient39367);fill-opacity:1;stroke:#ffffff;stroke-width:10;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 101.1429,213.87373 C 67.104473,239.1681 67.104473,42.67112 67.104473,42.67112 135.18122,57.58146 203.25844,72.491904 203.25758,105.24181 c -8.6e-4,32.74991 -68.07625,83.33755 -102.11468,108.63192 z"
|
||||||
|
id="path253" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer3"
|
||||||
|
inkscape:label="Poly">
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:0.325424;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 67.32839,76.766948 112.00424,99.41949 100.04873,52.226693 Z"
|
||||||
|
id="path4648" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:0.274576;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 111.45696,98.998695 107.00758,142.60261 70.077729,105.67276 Z"
|
||||||
|
id="path9299" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:0.379661;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 111.01202,99.221164 29.14343,-37.15232 25.80641,39.377006 z"
|
||||||
|
id="path9301" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:0.447458;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 111.45696,99.443631 57.17452,55.172309 -2.89209,-53.17009 z"
|
||||||
|
id="path9368" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:0.20678;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 106.78511,142.38015 62.06884,12.68073 -57.17452,-55.617249 z"
|
||||||
|
id="path9370" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:0.244068;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 106.78511,142.38015 -28.47603,32.9254 62.51378,7.56395 z"
|
||||||
|
id="path9372" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:0.216949;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 165.96186,101.44585 195.7727,125.02756 182.64703,78.754017 Z"
|
||||||
|
id="path9374" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer4"
|
||||||
|
inkscape:label="Vertices">
|
||||||
|
<circle
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path27764"
|
||||||
|
cx="106.86934"
|
||||||
|
cy="142.38014"
|
||||||
|
r="2.0022209" />
|
||||||
|
<circle
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="circle28773"
|
||||||
|
cx="111.54119"
|
||||||
|
cy="99.221161"
|
||||||
|
r="2.0022209" />
|
||||||
|
<circle
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="circle29091"
|
||||||
|
cx="165.90784"
|
||||||
|
cy="101.36163"
|
||||||
|
r="2.0022209" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 11 KiB |
27
src/app.rs
27
src/app.rs
@ -903,7 +903,7 @@ fn render_damus_mobile(ctx: &egui::Context, app: &mut Damus) {
|
|||||||
|
|
||||||
main_panel(&ctx.style(), ui::is_narrow(ctx)).show(ctx, |ui| {
|
main_panel(&ctx.style(), ui::is_narrow(ctx)).show(ctx, |ui| {
|
||||||
if !app.columns.columns().is_empty() {
|
if !app.columns.columns().is_empty() {
|
||||||
nav::render_nav(false, 0, app, ui);
|
nav::render_nav(0, app, ui);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -951,13 +951,18 @@ fn render_damus_desktop(ctx: &egui::Context, app: &mut Damus) {
|
|||||||
|
|
||||||
fn timelines_view(ui: &mut egui::Ui, sizes: Size, app: &mut Damus, columns: usize) {
|
fn timelines_view(ui: &mut egui::Ui, sizes: Size, app: &mut Damus, columns: usize) {
|
||||||
StripBuilder::new(ui)
|
StripBuilder::new(ui)
|
||||||
.size(Size::exact(40.0))
|
.size(Size::exact(ui::side_panel::SIDE_PANEL_WIDTH))
|
||||||
.sizes(sizes, columns)
|
.sizes(sizes, columns)
|
||||||
.clip(true)
|
.clip(true)
|
||||||
.horizontal(|mut strip| {
|
.horizontal(|mut strip| {
|
||||||
strip.cell(|ui| {
|
strip.cell(|ui| {
|
||||||
let rect = ui.available_rect_before_wrap();
|
let rect = ui.available_rect_before_wrap();
|
||||||
let side_panel = DesktopSidePanel::new(app).show(ui);
|
let side_panel = DesktopSidePanel::new(
|
||||||
|
&app.ndb,
|
||||||
|
&mut app.img_cache,
|
||||||
|
app.accounts.get_selected_account(),
|
||||||
|
)
|
||||||
|
.show(ui);
|
||||||
|
|
||||||
let router = if let Some(router) = app
|
let router = if let Some(router) = app
|
||||||
.columns
|
.columns
|
||||||
@ -986,24 +991,10 @@ fn timelines_view(ui: &mut egui::Ui, sizes: Size, app: &mut Damus, columns: usiz
|
|||||||
});
|
});
|
||||||
|
|
||||||
let n_cols = app.columns.columns().len();
|
let n_cols = app.columns.columns().len();
|
||||||
let mut first = true;
|
|
||||||
for column_ind in 0..n_cols {
|
for column_ind in 0..n_cols {
|
||||||
strip.cell(|ui| {
|
strip.cell(|ui| {
|
||||||
let rect = ui.available_rect_before_wrap();
|
let rect = ui.available_rect_before_wrap();
|
||||||
let show_postbox = first
|
nav::render_nav(column_ind, app, ui);
|
||||||
&& app
|
|
||||||
.columns
|
|
||||||
.column(column_ind)
|
|
||||||
.router()
|
|
||||||
.routes()
|
|
||||||
.iter()
|
|
||||||
.find_map(|r| r.timeline_id())
|
|
||||||
.is_some();
|
|
||||||
if show_postbox {
|
|
||||||
first = false
|
|
||||||
}
|
|
||||||
|
|
||||||
nav::render_nav(show_postbox, column_ind, app, ui);
|
|
||||||
|
|
||||||
// vertical line
|
// vertical line
|
||||||
ui.painter().vline(
|
ui.painter().vline(
|
||||||
|
28
src/nav.rs
28
src/nav.rs
@ -4,13 +4,13 @@ use crate::{
|
|||||||
route::Route,
|
route::Route,
|
||||||
thread::thread_unsubscribe,
|
thread::thread_unsubscribe,
|
||||||
timeline::route::{render_timeline_route, TimelineRoute, TimelineRouteResponse},
|
timeline::route::{render_timeline_route, TimelineRoute, TimelineRouteResponse},
|
||||||
ui::{note::PostAction, RelayView, View},
|
ui::{self, note::PostAction, RelayView, View},
|
||||||
Damus,
|
Damus,
|
||||||
};
|
};
|
||||||
|
|
||||||
use egui_nav::{Nav, NavAction};
|
use egui_nav::{Nav, NavAction};
|
||||||
|
|
||||||
pub fn render_nav(show_postbox: bool, col: usize, app: &mut Damus, ui: &mut egui::Ui) {
|
pub fn render_nav(col: usize, app: &mut Damus, ui: &mut egui::Ui) {
|
||||||
// TODO(jb55): clean up this router_mut mess by using Router<R> in egui-nav directly
|
// TODO(jb55): clean up this router_mut mess by using Router<R> in egui-nav directly
|
||||||
let nav_response = Nav::new(app.columns().column(col).router().routes().clone())
|
let nav_response = Nav::new(app.columns().column(col).router().routes().clone())
|
||||||
.navigating(app.columns_mut().column_mut(col).router_mut().navigating)
|
.navigating(app.columns_mut().column_mut(col).router_mut().navigating)
|
||||||
@ -28,7 +28,6 @@ pub fn render_nav(show_postbox: bool, col: usize, app: &mut Damus, ui: &mut egui
|
|||||||
&mut app.accounts,
|
&mut app.accounts,
|
||||||
*tlr,
|
*tlr,
|
||||||
col,
|
col,
|
||||||
show_postbox,
|
|
||||||
app.textmode,
|
app.textmode,
|
||||||
ui,
|
ui,
|
||||||
),
|
),
|
||||||
@ -50,6 +49,29 @@ pub fn render_nav(show_postbox: bool, col: usize, app: &mut Damus, ui: &mut egui
|
|||||||
RelayView::new(manager).ui(ui);
|
RelayView::new(manager).ui(ui);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
Route::ComposeNote => {
|
||||||
|
let kp = app.accounts.selected_or_first_nsec()?;
|
||||||
|
let draft = app.drafts.compose_mut();
|
||||||
|
|
||||||
|
let txn = nostrdb::Transaction::new(&app.ndb).expect("txn");
|
||||||
|
let post_response = ui::PostView::new(
|
||||||
|
&app.ndb,
|
||||||
|
draft,
|
||||||
|
crate::draft::DraftSource::Compose,
|
||||||
|
&mut app.img_cache,
|
||||||
|
&mut app.note_cache,
|
||||||
|
kp,
|
||||||
|
)
|
||||||
|
.ui(&txn, ui);
|
||||||
|
|
||||||
|
if let Some(action) = post_response.action {
|
||||||
|
PostAction::execute(kp, &action, &mut app.pool, draft, |np, seckey| {
|
||||||
|
np.to_note(seckey)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(reply_response) = nav_response.inner {
|
if let Some(reply_response) = nav_response.inner {
|
||||||
|
@ -12,6 +12,7 @@ pub enum Route {
|
|||||||
Timeline(TimelineRoute),
|
Timeline(TimelineRoute),
|
||||||
Accounts(AccountsRoute),
|
Accounts(AccountsRoute),
|
||||||
Relays,
|
Relays,
|
||||||
|
ComposeNote,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Route {
|
impl Route {
|
||||||
@ -123,6 +124,7 @@ impl fmt::Display for Route {
|
|||||||
AccountsRoute::Accounts => write!(f, "Accounts"),
|
AccountsRoute::Accounts => write!(f, "Accounts"),
|
||||||
AccountsRoute::AddAccount => write!(f, "Add Account"),
|
AccountsRoute::AddAccount => write!(f, "Add Account"),
|
||||||
},
|
},
|
||||||
|
Route::ComposeNote => write!(f, "Compose Note"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,23 +48,11 @@ pub fn render_timeline_route(
|
|||||||
accounts: &mut AccountManager,
|
accounts: &mut AccountManager,
|
||||||
route: TimelineRoute,
|
route: TimelineRoute,
|
||||||
col: usize,
|
col: usize,
|
||||||
show_postbox: bool,
|
|
||||||
textmode: bool,
|
textmode: bool,
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
) -> Option<TimelineRouteResponse> {
|
) -> Option<TimelineRouteResponse> {
|
||||||
match route {
|
match route {
|
||||||
TimelineRoute::Timeline(timeline_id) => {
|
TimelineRoute::Timeline(timeline_id) => {
|
||||||
if show_postbox {
|
|
||||||
let kp = accounts.selected_or_first_nsec()?;
|
|
||||||
let draft = drafts.compose_mut();
|
|
||||||
let response =
|
|
||||||
ui::timeline::postbox_view(ndb, kp, draft, img_cache, note_cache, ui);
|
|
||||||
|
|
||||||
if let Some(action) = response.action {
|
|
||||||
PostAction::execute(kp, &action, pool, draft, |np, seckey| np.to_note(seckey));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(bar_action) =
|
if let Some(bar_action) =
|
||||||
ui::TimelineView::new(timeline_id, columns, ndb, note_cache, img_cache, textmode)
|
ui::TimelineView::new(timeline_id, columns, ndb, note_cache, img_cache, textmode)
|
||||||
.ui(ui)
|
.ui(ui)
|
||||||
|
@ -10,8 +10,6 @@ use egui::{Align, Button, Frame, Image, InnerResponse, Layout, RichText, ScrollA
|
|||||||
use nostrdb::{Ndb, Transaction};
|
use nostrdb::{Ndb, Transaction};
|
||||||
|
|
||||||
use super::profile::preview::SimpleProfilePreview;
|
use super::profile::preview::SimpleProfilePreview;
|
||||||
use super::profile::ProfilePreviewOp;
|
|
||||||
use super::profile_preview_controller::profile_preview_view;
|
|
||||||
|
|
||||||
pub struct AccountsView<'a> {
|
pub struct AccountsView<'a> {
|
||||||
ndb: &'a Ndb,
|
ndb: &'a Ndb,
|
||||||
@ -26,6 +24,12 @@ pub enum AccountsViewResponse {
|
|||||||
RouteToLogin,
|
RouteToLogin,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum ProfilePreviewOp {
|
||||||
|
RemoveAccount,
|
||||||
|
SwitchTo,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> AccountsView<'a> {
|
impl<'a> AccountsView<'a> {
|
||||||
pub fn new(ndb: &'a Ndb, accounts: &'a AccountManager, img_cache: &'a mut ImageCache) -> Self {
|
pub fn new(ndb: &'a Ndb, accounts: &'a AccountManager, img_cache: &'a mut ImageCache) -> Self {
|
||||||
AccountsView {
|
AccountsView {
|
||||||
@ -86,9 +90,13 @@ impl<'a> AccountsView<'a> {
|
|||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(op) =
|
let profile_peview_view = {
|
||||||
profile_preview_view(ui, profile.as_ref(), img_cache, is_selected)
|
let width = ui.available_width();
|
||||||
{
|
let preview = SimpleProfilePreview::new(profile.as_ref(), img_cache);
|
||||||
|
show_profile_card(ui, preview, width, is_selected)
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(op) = profile_peview_view {
|
||||||
return_op = Some(match op {
|
return_op = Some(match op {
|
||||||
ProfilePreviewOp::SwitchTo => AccountsViewResponse::SelectAccount(i),
|
ProfilePreviewOp::SwitchTo => AccountsViewResponse::SelectAccount(i),
|
||||||
ProfilePreviewOp::RemoveAccount => {
|
ProfilePreviewOp::RemoveAccount => {
|
||||||
@ -119,7 +127,7 @@ impl<'a> AccountsView<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show_profile_card(
|
fn show_profile_card(
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
preview: SimpleProfilePreview,
|
preview: SimpleProfilePreview,
|
||||||
width: f32,
|
width: f32,
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use egui::{Pos2, Rect, Response, Sense};
|
||||||
|
|
||||||
pub fn hover_expand(
|
pub fn hover_expand(
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
id: egui::Id,
|
id: egui::Id,
|
||||||
@ -25,3 +27,70 @@ pub fn hover_expand_small(ui: &mut egui::Ui, id: egui::Id) -> (egui::Rect, f32,
|
|||||||
|
|
||||||
hover_expand(ui, id, size, expand_size, anim_speed)
|
hover_expand(ui, id, size, expand_size, anim_speed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub static ICON_EXPANSION_MULTIPLE: f32 = 1.2;
|
||||||
|
pub static ANIM_SPEED: f32 = 0.05;
|
||||||
|
pub struct AnimationHelper {
|
||||||
|
rect: Rect,
|
||||||
|
center: Pos2,
|
||||||
|
response: Response,
|
||||||
|
animation_progress: f32,
|
||||||
|
expansion_multiple: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnimationHelper {
|
||||||
|
pub fn new(
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
animation_name: impl std::hash::Hash,
|
||||||
|
max_size: egui::Vec2,
|
||||||
|
) -> Self {
|
||||||
|
let id = ui.id().with(animation_name);
|
||||||
|
let (rect, response) = ui.allocate_exact_size(max_size, Sense::click());
|
||||||
|
|
||||||
|
let animation_progress =
|
||||||
|
ui.ctx()
|
||||||
|
.animate_bool_with_time(id, response.hovered(), ANIM_SPEED);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
rect,
|
||||||
|
center: rect.center(),
|
||||||
|
response,
|
||||||
|
animation_progress,
|
||||||
|
expansion_multiple: ICON_EXPANSION_MULTIPLE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scale_1d_pos(&self, min_object_size: f32) -> f32 {
|
||||||
|
let max_object_size = min_object_size * self.expansion_multiple;
|
||||||
|
|
||||||
|
if self.response.is_pointer_button_down_on() {
|
||||||
|
min_object_size
|
||||||
|
} else {
|
||||||
|
min_object_size + ((max_object_size - min_object_size) * self.animation_progress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scale_radius(&self, min_diameter: f32) -> f32 {
|
||||||
|
self.scale_1d_pos((min_diameter - 1.0) / 2.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_animation_rect(&self) -> egui::Rect {
|
||||||
|
self.rect
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn center(&self) -> Pos2 {
|
||||||
|
self.rect.center()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn take_animation_response(self) -> egui::Response {
|
||||||
|
self.response
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale a minimum position from center to the current animation position
|
||||||
|
pub fn scale_from_center(&self, x_min: f32, y_min: f32) -> Pos2 {
|
||||||
|
Pos2::new(
|
||||||
|
self.center.x + self.scale_1d_pos(x_min),
|
||||||
|
self.center.y + self.scale_1d_pos(y_min),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -15,7 +15,7 @@ pub use account_management::AccountsView;
|
|||||||
pub use mention::Mention;
|
pub use mention::Mention;
|
||||||
pub use note::{NoteResponse, NoteView, PostReplyView, PostView};
|
pub use note::{NoteResponse, NoteView, PostReplyView, PostView};
|
||||||
pub use preview::{Preview, PreviewApp, PreviewConfig};
|
pub use preview::{Preview, PreviewApp, PreviewConfig};
|
||||||
pub use profile::{profile_preview_controller, ProfilePic, ProfilePreview};
|
pub use profile::{ProfilePic, ProfilePreview};
|
||||||
pub use relay::RelayView;
|
pub use relay::RelayView;
|
||||||
pub use side_panel::{DesktopSidePanel, SidePanelAction};
|
pub use side_panel::{DesktopSidePanel, SidePanelAction};
|
||||||
pub use thread::ThreadView;
|
pub use thread::ThreadView;
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
pub mod picture;
|
pub mod picture;
|
||||||
pub mod preview;
|
pub mod preview;
|
||||||
pub mod profile_preview_controller;
|
|
||||||
|
|
||||||
pub use picture::ProfilePic;
|
pub use picture::ProfilePic;
|
||||||
pub use preview::ProfilePreview;
|
pub use preview::ProfilePreview;
|
||||||
pub use profile_preview_controller::ProfilePreviewOp;
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::app_style::NotedeckTextStyle;
|
use crate::app_style::NotedeckTextStyle;
|
||||||
use crate::imgcache::ImageCache;
|
use crate::imgcache::ImageCache;
|
||||||
use crate::ui::ProfilePic;
|
use crate::ui::ProfilePic;
|
||||||
|
use crate::user_account::UserAccount;
|
||||||
use crate::{colors, images, DisplayName};
|
use crate::{colors, images, DisplayName};
|
||||||
use egui::load::TexturePoll;
|
use egui::load::TexturePoll;
|
||||||
use egui::{Frame, RichText, Sense, Widget};
|
use egui::{Frame, RichText, Sense, Widget};
|
||||||
@ -167,6 +168,30 @@ pub fn get_profile_url<'a>(profile: Option<&'a ProfileRecord<'a>>) -> &'a str {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_profile_url_owned(profile: Option<ProfileRecord<'_>>) -> &str {
|
||||||
|
if let Some(url) = profile.and_then(|pr| pr.record().profile().and_then(|p| p.picture())) {
|
||||||
|
url
|
||||||
|
} else {
|
||||||
|
ProfilePic::no_pfp_url()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_account_url<'a>(
|
||||||
|
txn: &'a nostrdb::Transaction,
|
||||||
|
ndb: &nostrdb::Ndb,
|
||||||
|
account: Option<&UserAccount>,
|
||||||
|
) -> &'a str {
|
||||||
|
if let Some(selected_account) = account {
|
||||||
|
if let Ok(profile) = ndb.get_profile_by_pubkey(txn, selected_account.pubkey.bytes()) {
|
||||||
|
get_profile_url_owned(Some(profile))
|
||||||
|
} else {
|
||||||
|
get_profile_url_owned(None)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
get_profile_url(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn display_name_widget(
|
fn display_name_widget(
|
||||||
display_name: DisplayName<'_>,
|
display_name: DisplayName<'_>,
|
||||||
add_placeholder_space: bool,
|
add_placeholder_space: bool,
|
||||||
|
@ -1,126 +0,0 @@
|
|||||||
use egui::Ui;
|
|
||||||
use nostrdb::{Ndb, ProfileRecord, Transaction};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
imgcache::ImageCache, ui::account_management::show_profile_card, Damus, DisplayName, Result,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
|
||||||
preview::{get_display_name, get_profile_url, SimpleProfilePreview},
|
|
||||||
ProfilePic,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum ProfilePreviewOp {
|
|
||||||
RemoveAccount,
|
|
||||||
SwitchTo,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn profile_preview_view(
|
|
||||||
ui: &mut Ui,
|
|
||||||
profile: Option<&'_ ProfileRecord<'_>>,
|
|
||||||
img_cache: &mut ImageCache,
|
|
||||||
is_selected: bool,
|
|
||||||
) -> Option<ProfilePreviewOp> {
|
|
||||||
let width = ui.available_width();
|
|
||||||
|
|
||||||
let preview = SimpleProfilePreview::new(profile, img_cache);
|
|
||||||
show_profile_card(ui, preview, width, is_selected)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn view_profile_previews(
|
|
||||||
app: &mut Damus,
|
|
||||||
ui: &mut egui::Ui,
|
|
||||||
add_preview_ui: fn(
|
|
||||||
ui: &mut egui::Ui,
|
|
||||||
preview: SimpleProfilePreview,
|
|
||||||
width: f32,
|
|
||||||
is_selected: bool,
|
|
||||||
index: usize,
|
|
||||||
) -> bool,
|
|
||||||
) -> Option<usize> {
|
|
||||||
let width = ui.available_width();
|
|
||||||
|
|
||||||
let txn = if let Ok(txn) = Transaction::new(app.ndb()) {
|
|
||||||
txn
|
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
for i in 0..app.accounts().num_accounts() {
|
|
||||||
let account = if let Some(account) = app.accounts().get_account(i) {
|
|
||||||
account
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let profile = app
|
|
||||||
.ndb()
|
|
||||||
.get_profile_by_pubkey(&txn, account.pubkey.bytes())
|
|
||||||
.ok();
|
|
||||||
|
|
||||||
let is_selected = if let Some(selected) = app.accounts().get_selected_account_index() {
|
|
||||||
i == selected
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
let preview = SimpleProfilePreview::new(profile.as_ref(), app.img_cache_mut());
|
|
||||||
|
|
||||||
if add_preview_ui(ui, preview, width, is_selected, i) {
|
|
||||||
return Some(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show_with_nickname(
|
|
||||||
ndb: &Ndb,
|
|
||||||
ui: &mut egui::Ui,
|
|
||||||
key: &[u8; 32],
|
|
||||||
ui_element: fn(ui: &mut egui::Ui, username: &DisplayName) -> egui::Response,
|
|
||||||
) -> Result<egui::Response> {
|
|
||||||
let txn = Transaction::new(ndb)?;
|
|
||||||
let profile = ndb.get_profile_by_pubkey(&txn, key)?;
|
|
||||||
Ok(ui_element(ui, &get_display_name(Some(&profile))))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show_with_selected_pfp(
|
|
||||||
app: &mut Damus,
|
|
||||||
ui: &mut egui::Ui,
|
|
||||||
ui_element: fn(ui: &mut egui::Ui, pfp: ProfilePic) -> egui::Response,
|
|
||||||
) -> Option<egui::Response> {
|
|
||||||
let selected_account = app.accounts().get_selected_account();
|
|
||||||
if let Some(selected_account) = selected_account {
|
|
||||||
if let Ok(txn) = Transaction::new(app.ndb()) {
|
|
||||||
let profile = app
|
|
||||||
.ndb()
|
|
||||||
.get_profile_by_pubkey(&txn, selected_account.pubkey.bytes());
|
|
||||||
|
|
||||||
return Some(ui_element(
|
|
||||||
ui,
|
|
||||||
ProfilePic::new(app.img_cache_mut(), get_profile_url(profile.ok().as_ref())),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show_with_pfp(
|
|
||||||
app: &mut Damus,
|
|
||||||
ui: &mut egui::Ui,
|
|
||||||
key: &[u8; 32],
|
|
||||||
ui_element: fn(ui: &mut egui::Ui, pfp: ProfilePic) -> egui::Response,
|
|
||||||
) -> Option<egui::Response> {
|
|
||||||
if let Ok(txn) = Transaction::new(app.ndb()) {
|
|
||||||
let profile = app.ndb().get_profile_by_pubkey(&txn, key);
|
|
||||||
|
|
||||||
return Some(ui_element(
|
|
||||||
ui,
|
|
||||||
ProfilePic::new(app.img_cache_mut(), get_profile_url(profile.ok().as_ref())),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
@ -1,17 +1,29 @@
|
|||||||
use egui::{Button, Layout, SidePanel, Vec2, Widget};
|
use egui::{vec2, Color32, InnerResponse, Layout, Margin, Separator, SidePanel, Stroke, Widget};
|
||||||
|
use tracing::info;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
account_manager::AccountsRoute,
|
account_manager::AccountsRoute,
|
||||||
|
colors,
|
||||||
column::Column,
|
column::Column,
|
||||||
|
imgcache::ImageCache,
|
||||||
route::{Route, Router},
|
route::{Route, Router},
|
||||||
ui::profile_preview_controller,
|
user_account::UserAccount,
|
||||||
Damus,
|
Damus,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{ProfilePic, View};
|
use super::{
|
||||||
|
anim::{AnimationHelper, ICON_EXPANSION_MULTIPLE},
|
||||||
|
profile::preview::get_account_url,
|
||||||
|
ProfilePic, View,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub static SIDE_PANEL_WIDTH: f32 = 64.0;
|
||||||
|
static ICON_WIDTH: f32 = 40.0;
|
||||||
|
|
||||||
pub struct DesktopSidePanel<'a> {
|
pub struct DesktopSidePanel<'a> {
|
||||||
app: &'a mut Damus,
|
ndb: &'a nostrdb::Ndb,
|
||||||
|
img_cache: &'a mut ImageCache,
|
||||||
|
selected_account: Option<&'a UserAccount>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> View for DesktopSidePanel<'a> {
|
impl<'a> View for DesktopSidePanel<'a> {
|
||||||
@ -26,6 +38,9 @@ pub enum SidePanelAction {
|
|||||||
Account,
|
Account,
|
||||||
Settings,
|
Settings,
|
||||||
Columns,
|
Columns,
|
||||||
|
ComposeNote,
|
||||||
|
Search,
|
||||||
|
ExpandSidePanel,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SidePanelResponse {
|
pub struct SidePanelResponse {
|
||||||
@ -40,33 +55,93 @@ impl SidePanelResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DesktopSidePanel<'a> {
|
impl<'a> DesktopSidePanel<'a> {
|
||||||
pub fn new(app: &'a mut Damus) -> Self {
|
pub fn new(
|
||||||
DesktopSidePanel { app }
|
ndb: &'a nostrdb::Ndb,
|
||||||
|
img_cache: &'a mut ImageCache,
|
||||||
|
selected_account: Option<&'a UserAccount>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
ndb,
|
||||||
|
img_cache,
|
||||||
|
selected_account,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn panel() -> SidePanel {
|
pub fn panel() -> SidePanel {
|
||||||
egui::SidePanel::left("side_panel")
|
egui::SidePanel::left("side_panel")
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
.exact_width(40.0)
|
.exact_width(SIDE_PANEL_WIDTH)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show(&mut self, ui: &mut egui::Ui) -> SidePanelResponse {
|
pub fn show(&mut self, ui: &mut egui::Ui) -> SidePanelResponse {
|
||||||
|
egui::Frame::none()
|
||||||
|
.inner_margin(Margin::same(8.0))
|
||||||
|
.show(ui, |ui| self.show_inner(ui))
|
||||||
|
.inner
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_inner(&mut self, ui: &mut egui::Ui) -> SidePanelResponse {
|
||||||
let dark_mode = ui.ctx().style().visuals.dark_mode;
|
let dark_mode = ui.ctx().style().visuals.dark_mode;
|
||||||
let spacing_amt = 16.0;
|
|
||||||
|
|
||||||
let inner = ui
|
let inner = ui
|
||||||
.with_layout(Layout::bottom_up(egui::Align::Center), |ui| {
|
.vertical(|ui| {
|
||||||
ui.spacing_mut().item_spacing.y = spacing_amt;
|
let top_resp = ui
|
||||||
let pfp_resp = self.pfp_button(ui);
|
.with_layout(Layout::top_down(egui::Align::Center), |ui| {
|
||||||
let settings_resp = ui.add(settings_button(dark_mode));
|
let expand_resp = ui.add(expand_side_panel_button());
|
||||||
|
ui.add_space(28.0);
|
||||||
|
let compose_resp = ui.add(compose_note_button());
|
||||||
|
let search_resp = ui.add(search_button());
|
||||||
let column_resp = ui.add(add_column_button(dark_mode));
|
let column_resp = ui.add(add_column_button(dark_mode));
|
||||||
|
|
||||||
if pfp_resp.clicked() {
|
ui.add(Separator::default().horizontal().spacing(8.0).shrink(4.0));
|
||||||
egui::InnerResponse::new(SidePanelAction::Account, pfp_resp)
|
|
||||||
|
if expand_resp.clicked() {
|
||||||
|
Some(InnerResponse::new(
|
||||||
|
SidePanelAction::ExpandSidePanel,
|
||||||
|
expand_resp,
|
||||||
|
))
|
||||||
|
} else if compose_resp.clicked() {
|
||||||
|
Some(InnerResponse::new(
|
||||||
|
SidePanelAction::ComposeNote,
|
||||||
|
compose_resp,
|
||||||
|
))
|
||||||
|
} else if search_resp.clicked() {
|
||||||
|
Some(InnerResponse::new(SidePanelAction::Search, search_resp))
|
||||||
|
} else if column_resp.clicked() {
|
||||||
|
Some(InnerResponse::new(SidePanelAction::Columns, column_resp))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.inner;
|
||||||
|
|
||||||
|
let (pfp_resp, bottom_resp) = ui
|
||||||
|
.with_layout(Layout::bottom_up(egui::Align::Center), |ui| {
|
||||||
|
let pfp_resp = self.pfp_button(ui);
|
||||||
|
let settings_resp = ui.add(settings_button(dark_mode));
|
||||||
|
|
||||||
|
let optional_inner = if pfp_resp.clicked() {
|
||||||
|
Some(egui::InnerResponse::new(
|
||||||
|
SidePanelAction::Account,
|
||||||
|
pfp_resp.clone(),
|
||||||
|
))
|
||||||
} else if settings_resp.clicked() || settings_resp.hovered() {
|
} else if settings_resp.clicked() || settings_resp.hovered() {
|
||||||
egui::InnerResponse::new(SidePanelAction::Settings, settings_resp)
|
Some(egui::InnerResponse::new(
|
||||||
} else if column_resp.clicked() || column_resp.hovered() {
|
SidePanelAction::Settings,
|
||||||
egui::InnerResponse::new(SidePanelAction::Columns, column_resp)
|
settings_resp,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
(pfp_resp, optional_inner)
|
||||||
|
})
|
||||||
|
.inner;
|
||||||
|
|
||||||
|
if let Some(bottom_inner) = bottom_resp {
|
||||||
|
bottom_inner
|
||||||
|
} else if let Some(top_inner) = top_resp {
|
||||||
|
top_inner
|
||||||
} else {
|
} else {
|
||||||
egui::InnerResponse::new(SidePanelAction::Panel, pfp_resp)
|
egui::InnerResponse::new(SidePanelAction::Panel, pfp_resp)
|
||||||
}
|
}
|
||||||
@ -77,13 +152,20 @@ impl<'a> DesktopSidePanel<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn pfp_button(&mut self, ui: &mut egui::Ui) -> egui::Response {
|
fn pfp_button(&mut self, ui: &mut egui::Ui) -> egui::Response {
|
||||||
if let Some(resp) =
|
let max_size = ICON_WIDTH * ICON_EXPANSION_MULTIPLE; // max size of the widget
|
||||||
profile_preview_controller::show_with_selected_pfp(self.app, ui, show_pfp())
|
let helper = AnimationHelper::new(ui, "pfp-button", vec2(max_size, max_size));
|
||||||
{
|
|
||||||
resp
|
let min_pfp_size = ICON_WIDTH;
|
||||||
} else {
|
let cur_pfp_size = helper.scale_1d_pos(min_pfp_size);
|
||||||
add_button_to_ui(ui, no_account_pfp())
|
|
||||||
}
|
let txn = nostrdb::Transaction::new(self.ndb).expect("should be able to create txn");
|
||||||
|
let profile_url = get_account_url(&txn, self.ndb, self.selected_account);
|
||||||
|
|
||||||
|
let widget = ProfilePic::new(self.img_cache, profile_url).size(cur_pfp_size);
|
||||||
|
|
||||||
|
ui.put(helper.get_animation_rect(), widget);
|
||||||
|
|
||||||
|
helper.take_animation_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn perform_action(router: &mut Router<Route>, action: SidePanelAction) {
|
pub fn perform_action(router: &mut Router<Route>, action: SidePanelAction) {
|
||||||
@ -109,40 +191,167 @@ impl<'a> DesktopSidePanel<'a> {
|
|||||||
router.route_to(Route::relays());
|
router.route_to(Route::relays());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SidePanelAction::Columns => (), // TODO
|
SidePanelAction::Columns => {
|
||||||
|
// TODO
|
||||||
|
info!("Clicked columns button");
|
||||||
|
}
|
||||||
|
SidePanelAction::ComposeNote => {
|
||||||
|
if router.routes().iter().any(|&r| r == Route::ComposeNote) {
|
||||||
|
router.go_back();
|
||||||
|
} else {
|
||||||
|
router.route_to(Route::ComposeNote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SidePanelAction::Search => {
|
||||||
|
// TODO
|
||||||
|
info!("Clicked search button");
|
||||||
|
}
|
||||||
|
SidePanelAction::ExpandSidePanel => {
|
||||||
|
// TODO
|
||||||
|
info!("Clicked expand side panel button");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_pfp() -> fn(ui: &mut egui::Ui, pfp: ProfilePic) -> egui::Response {
|
fn settings_button(dark_mode: bool) -> impl Widget {
|
||||||
|ui, pfp| {
|
|
||||||
let response = pfp.ui(ui);
|
|
||||||
ui.allocate_rect(response.rect, egui::Sense::click())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn settings_button(dark_mode: bool) -> egui::Button<'static> {
|
|
||||||
let _ = dark_mode;
|
let _ = dark_mode;
|
||||||
|
|ui: &mut egui::Ui| {
|
||||||
|
let img_size = 24.0;
|
||||||
|
let max_size = ICON_WIDTH * ICON_EXPANSION_MULTIPLE; // max size of the widget
|
||||||
let img_data = egui::include_image!("../../assets/icons/settings_dark_4x.png");
|
let img_data = egui::include_image!("../../assets/icons/settings_dark_4x.png");
|
||||||
|
let img = egui::Image::new(img_data).max_width(img_size);
|
||||||
|
|
||||||
egui::Button::image(egui::Image::new(img_data).max_width(32.0)).frame(false)
|
let helper = AnimationHelper::new(ui, "settings-button", vec2(max_size, max_size));
|
||||||
|
|
||||||
|
let cur_img_size = helper.scale_1d_pos(img_size);
|
||||||
|
img.paint_at(
|
||||||
|
ui,
|
||||||
|
helper
|
||||||
|
.get_animation_rect()
|
||||||
|
.shrink((max_size - cur_img_size) / 2.0),
|
||||||
|
);
|
||||||
|
|
||||||
|
helper.take_animation_response()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_button_to_ui(ui: &mut egui::Ui, button: Button) -> egui::Response {
|
fn add_column_button(dark_mode: bool) -> impl Widget {
|
||||||
ui.add_sized(Vec2::new(32.0, 32.0), button)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn no_account_pfp() -> Button<'static> {
|
|
||||||
Button::new("A")
|
|
||||||
.rounding(20.0)
|
|
||||||
.min_size(Vec2::new(38.0, 38.0))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_column_button(dark_mode: bool) -> egui::Button<'static> {
|
|
||||||
let _ = dark_mode;
|
let _ = dark_mode;
|
||||||
|
move |ui: &mut egui::Ui| {
|
||||||
|
let img_size = 24.0;
|
||||||
|
let max_size = ICON_WIDTH * ICON_EXPANSION_MULTIPLE; // max size of the widget
|
||||||
|
|
||||||
let img_data = egui::include_image!("../../assets/icons/add_column_dark_4x.png");
|
let img_data = egui::include_image!("../../assets/icons/add_column_dark_4x.png");
|
||||||
|
|
||||||
egui::Button::image(egui::Image::new(img_data).max_width(32.0)).frame(false)
|
let img = egui::Image::new(img_data).max_width(img_size);
|
||||||
|
|
||||||
|
let helper = AnimationHelper::new(ui, "add-column-button", vec2(max_size, max_size));
|
||||||
|
|
||||||
|
let cur_img_size = helper.scale_1d_pos(img_size);
|
||||||
|
img.paint_at(
|
||||||
|
ui,
|
||||||
|
helper
|
||||||
|
.get_animation_rect()
|
||||||
|
.shrink((max_size - cur_img_size) / 2.0),
|
||||||
|
);
|
||||||
|
|
||||||
|
helper.take_animation_response()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compose_note_button() -> impl Widget {
|
||||||
|
|ui: &mut egui::Ui| -> egui::Response {
|
||||||
|
let max_size = ICON_WIDTH * ICON_EXPANSION_MULTIPLE; // max size of the widget
|
||||||
|
|
||||||
|
let min_outer_circle_diameter = 40.0;
|
||||||
|
let min_plus_sign_size = 14.0; // length of the plus sign
|
||||||
|
let min_line_width = 2.25; // width of the plus sign
|
||||||
|
|
||||||
|
let helper = AnimationHelper::new(ui, "note-compose-button", vec2(max_size, max_size));
|
||||||
|
|
||||||
|
let painter = ui.painter_at(helper.get_animation_rect());
|
||||||
|
|
||||||
|
let use_background_radius = helper.scale_radius(min_outer_circle_diameter);
|
||||||
|
let use_line_width = helper.scale_1d_pos(min_line_width);
|
||||||
|
let use_edge_circle_radius = helper.scale_radius(min_line_width);
|
||||||
|
|
||||||
|
painter.circle_filled(helper.center(), use_background_radius, colors::PINK);
|
||||||
|
|
||||||
|
let min_half_plus_sign_size = min_plus_sign_size / 2.0;
|
||||||
|
let north_edge = helper.scale_from_center(0.0, min_half_plus_sign_size);
|
||||||
|
let south_edge = helper.scale_from_center(0.0, -min_half_plus_sign_size);
|
||||||
|
let west_edge = helper.scale_from_center(-min_half_plus_sign_size, 0.0);
|
||||||
|
let east_edge = helper.scale_from_center(min_half_plus_sign_size, 0.0);
|
||||||
|
|
||||||
|
painter.line_segment(
|
||||||
|
[north_edge, south_edge],
|
||||||
|
Stroke::new(use_line_width, Color32::WHITE),
|
||||||
|
);
|
||||||
|
painter.line_segment(
|
||||||
|
[west_edge, east_edge],
|
||||||
|
Stroke::new(use_line_width, Color32::WHITE),
|
||||||
|
);
|
||||||
|
painter.circle_filled(north_edge, use_edge_circle_radius, Color32::WHITE);
|
||||||
|
painter.circle_filled(south_edge, use_edge_circle_radius, Color32::WHITE);
|
||||||
|
painter.circle_filled(west_edge, use_edge_circle_radius, Color32::WHITE);
|
||||||
|
painter.circle_filled(east_edge, use_edge_circle_radius, Color32::WHITE);
|
||||||
|
|
||||||
|
helper.take_animation_response()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_button() -> impl Widget {
|
||||||
|
|ui: &mut egui::Ui| -> egui::Response {
|
||||||
|
let max_size = ICON_WIDTH * ICON_EXPANSION_MULTIPLE; // max size of the widget
|
||||||
|
let min_line_width_circle = 1.5; // width of the magnifying glass
|
||||||
|
let min_line_width_handle = 1.5;
|
||||||
|
let helper = AnimationHelper::new(ui, "search-button", vec2(max_size, max_size));
|
||||||
|
|
||||||
|
let painter = ui.painter_at(helper.get_animation_rect());
|
||||||
|
|
||||||
|
let cur_line_width_circle = helper.scale_1d_pos(min_line_width_circle);
|
||||||
|
let cur_line_width_handle = helper.scale_1d_pos(min_line_width_handle);
|
||||||
|
let min_outer_circle_radius = helper.scale_radius(15.0);
|
||||||
|
let cur_outer_circle_radius = helper.scale_1d_pos(min_outer_circle_radius);
|
||||||
|
let min_handle_length = 7.0;
|
||||||
|
let cur_handle_length = helper.scale_1d_pos(min_handle_length);
|
||||||
|
|
||||||
|
let circle_center = helper.scale_from_center(-2.0, -2.0);
|
||||||
|
|
||||||
|
let handle_vec = vec2(
|
||||||
|
std::f32::consts::FRAC_1_SQRT_2,
|
||||||
|
std::f32::consts::FRAC_1_SQRT_2,
|
||||||
|
);
|
||||||
|
|
||||||
|
let handle_pos_1 = circle_center + (handle_vec * (cur_outer_circle_radius - 3.0));
|
||||||
|
let handle_pos_2 =
|
||||||
|
circle_center + (handle_vec * (cur_outer_circle_radius + cur_handle_length));
|
||||||
|
|
||||||
|
let circle_stroke = Stroke::new(cur_line_width_circle, colors::MID_GRAY);
|
||||||
|
let handle_stroke = Stroke::new(cur_line_width_handle, colors::MID_GRAY);
|
||||||
|
|
||||||
|
painter.line_segment([handle_pos_1, handle_pos_2], handle_stroke);
|
||||||
|
painter.circle(
|
||||||
|
circle_center,
|
||||||
|
min_outer_circle_radius,
|
||||||
|
ui.style().visuals.widgets.inactive.weak_bg_fill,
|
||||||
|
circle_stroke,
|
||||||
|
);
|
||||||
|
|
||||||
|
helper.take_animation_response()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: convert to responsive button when expanded side panel impl is finished
|
||||||
|
fn expand_side_panel_button() -> impl Widget {
|
||||||
|
|ui: &mut egui::Ui| -> egui::Response {
|
||||||
|
let img_size = 40.0;
|
||||||
|
let img_data = egui::include_image!("../../assets/damus_rounded.svg");
|
||||||
|
let img = egui::Image::new(img_data).max_width(img_size);
|
||||||
|
|
||||||
|
ui.add(img)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod preview {
|
mod preview {
|
||||||
@ -173,12 +382,16 @@ mod preview {
|
|||||||
impl View for DesktopSidePanelPreview {
|
impl View for DesktopSidePanelPreview {
|
||||||
fn ui(&mut self, ui: &mut egui::Ui) {
|
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||||
StripBuilder::new(ui)
|
StripBuilder::new(ui)
|
||||||
.size(Size::exact(40.0))
|
.size(Size::exact(SIDE_PANEL_WIDTH))
|
||||||
.sizes(Size::remainder(), 0)
|
.sizes(Size::remainder(), 0)
|
||||||
.clip(true)
|
.clip(true)
|
||||||
.horizontal(|mut strip| {
|
.horizontal(|mut strip| {
|
||||||
strip.cell(|ui| {
|
strip.cell(|ui| {
|
||||||
let mut panel = DesktopSidePanel::new(&mut self.app);
|
let mut panel = DesktopSidePanel::new(
|
||||||
|
&self.app.ndb,
|
||||||
|
&mut self.app.img_cache,
|
||||||
|
self.app.accounts.get_selected_account(),
|
||||||
|
);
|
||||||
let response = panel.show(ui);
|
let response = panel.show(ui);
|
||||||
|
|
||||||
DesktopSidePanel::perform_action(
|
DesktopSidePanel::perform_action(
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use crate::draft::Draft;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
actionbar::BarAction, column::Columns, imgcache::ImageCache, notecache::NoteCache,
|
actionbar::BarAction, column::Columns, imgcache::ImageCache, notecache::NoteCache,
|
||||||
timeline::TimelineId, ui,
|
timeline::TimelineId, ui,
|
||||||
@ -6,12 +5,9 @@ use crate::{
|
|||||||
use egui::containers::scroll_area::ScrollBarVisibility;
|
use egui::containers::scroll_area::ScrollBarVisibility;
|
||||||
use egui::{Direction, Layout};
|
use egui::{Direction, Layout};
|
||||||
use egui_tabs::TabColor;
|
use egui_tabs::TabColor;
|
||||||
use enostr::FilledKeypair;
|
|
||||||
use nostrdb::{Ndb, Transaction};
|
use nostrdb::{Ndb, Transaction};
|
||||||
use tracing::{debug, error, warn};
|
use tracing::{debug, error, warn};
|
||||||
|
|
||||||
use super::note::PostResponse;
|
|
||||||
|
|
||||||
pub struct TimelineView<'a> {
|
pub struct TimelineView<'a> {
|
||||||
timeline_id: TimelineId,
|
timeline_id: TimelineId,
|
||||||
columns: &'a mut Columns,
|
columns: &'a mut Columns,
|
||||||
@ -175,27 +171,6 @@ fn timeline_ui(
|
|||||||
bar_action
|
bar_action
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn postbox_view<'a>(
|
|
||||||
ndb: &'a Ndb,
|
|
||||||
key: FilledKeypair<'a>,
|
|
||||||
draft: &'a mut Draft,
|
|
||||||
img_cache: &'a mut ImageCache,
|
|
||||||
note_cache: &'a mut NoteCache,
|
|
||||||
ui: &'a mut egui::Ui,
|
|
||||||
) -> PostResponse {
|
|
||||||
// show a postbox in the first timeline
|
|
||||||
let txn = Transaction::new(ndb).expect("txn");
|
|
||||||
ui::PostView::new(
|
|
||||||
ndb,
|
|
||||||
draft,
|
|
||||||
crate::draft::DraftSource::Compose,
|
|
||||||
img_cache,
|
|
||||||
note_cache,
|
|
||||||
key,
|
|
||||||
)
|
|
||||||
.ui(&txn, ui)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tabs_ui(ui: &mut egui::Ui) -> i32 {
|
fn tabs_ui(ui: &mut egui::Ui) -> i32 {
|
||||||
ui.spacing_mut().item_spacing.y = 0.0;
|
ui.spacing_mut().item_spacing.y = 0.0;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user