mirror of
https://github.com/mikedilger/gossip.git
synced 2024-09-29 16:31:18 +00:00
Updated UX on image placement
This commit is contained in:
parent
ec7b7088e3
commit
0abd873073
1
assets/expand-image.svg
Normal file
1
assets/expand-image.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12.54 37.3"><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><polyline points="0.42 0.27 11.95 18.65 0.42 37.04" style="fill:none;stroke:#878787;stroke-miterlimit:10"/></g></g></svg>
|
After Width: | Height: | Size: 298 B |
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
@ -1,7 +1,6 @@
|
||||
use super::{GossipUi, NoteData, Page, RepostType};
|
||||
use crate::{feed::FeedKind};
|
||||
use crate::feed::FeedKind;
|
||||
use crate::globals::GLOBALS;
|
||||
use crate::ui::widgets::break_anywhere_hyperlink_to;
|
||||
use eframe::{
|
||||
egui::{self, Image, Response},
|
||||
epaint::Vec2,
|
||||
@ -174,8 +173,7 @@ pub(super) fn render_content(
|
||||
}
|
||||
}
|
||||
ContentSegment::Hyperlink(link) => {
|
||||
let lowercase = link.to_lowercase();
|
||||
if let Some(image_url) = as_image_url(app, &lowercase) {
|
||||
if let Some(image_url) = as_image_url(app, &link) {
|
||||
show_image_toggle(app, ui, image_url);
|
||||
//} else if is_video_url(&lowercase) {
|
||||
// TODO
|
||||
@ -224,11 +222,12 @@ fn render_event_link(app: &mut GossipUi, ui: &mut Ui, note: &NoteData, id: &Id)
|
||||
}
|
||||
|
||||
fn is_image_url(url: &str) -> bool {
|
||||
url.ends_with(".jpg")
|
||||
|| url.ends_with(".jpeg")
|
||||
|| url.ends_with(".png")
|
||||
|| url.ends_with(".gif")
|
||||
|| url.ends_with(".webp")
|
||||
let lower = url.to_lowercase();
|
||||
lower.ends_with(".jpg")
|
||||
|| lower.ends_with(".jpeg")
|
||||
|| lower.ends_with(".png")
|
||||
|| lower.ends_with(".gif")
|
||||
|| lower.ends_with(".webp")
|
||||
}
|
||||
|
||||
fn as_image_url(app: &mut GossipUi, url: &str) -> Option<Url> {
|
||||
@ -241,10 +240,11 @@ fn as_image_url(app: &mut GossipUi, url: &str) -> Option<Url> {
|
||||
|
||||
/*
|
||||
fn is_video_url(url: &str) -> bool {
|
||||
url.ends_with(".mov")
|
||||
|| url.ends_with(".mp4")
|
||||
|| url.ends_with(".mkv")
|
||||
|| url.ends_with(".webm")
|
||||
let lower = url.to_lowercase();
|
||||
lower.ends_with(".mov")
|
||||
|| lower.ends_with(".mp4")
|
||||
|| lower.ends_with(".mkv")
|
||||
|| lower.ends_with(".webm")
|
||||
}
|
||||
*/
|
||||
|
||||
@ -254,8 +254,9 @@ fn show_image_toggle(app: &mut GossipUi, ui: &mut Ui, url: Url) {
|
||||
let mut show_link = true;
|
||||
let mut hovr_response = None;
|
||||
|
||||
let show_image = (app.settings.show_media && !app.media_hide_list.contains(&url)) ||
|
||||
(!app.settings.show_media && app.media_show_list.contains(&url));
|
||||
// FIXME show/hide lists should persist app restarts
|
||||
let show_image = (app.settings.show_media && !app.media_hide_list.contains(&url))
|
||||
|| (!app.settings.show_media && app.media_show_list.contains(&url));
|
||||
|
||||
if show_image {
|
||||
if let Some(response) = try_render_media(app, ui, url.clone()) {
|
||||
@ -273,8 +274,12 @@ fn show_image_toggle(app: &mut GossipUi, ui: &mut Ui, url: Url) {
|
||||
|
||||
if show_link {
|
||||
let response = ui.link("[ Image ]");
|
||||
if !app.settings.load_media {
|
||||
response.clone().on_hover_text("Setting 'Fetch media' is disabled");
|
||||
if app.settings.load_media {
|
||||
response.clone().on_hover_text(url_string.clone());
|
||||
} else {
|
||||
response
|
||||
.clone()
|
||||
.on_hover_text("Setting 'Fetch media' is disabled");
|
||||
}
|
||||
if response.clicked() {
|
||||
if app.settings.show_media {
|
||||
@ -286,9 +291,10 @@ fn show_image_toggle(app: &mut GossipUi, ui: &mut Ui, url: Url) {
|
||||
hovr_response = Some(response);
|
||||
}
|
||||
|
||||
// from here handle both responses the same, image or link
|
||||
if let Some(response) = hovr_response {
|
||||
response.context_menu(|ui| {
|
||||
if ui.button("open in browser").clicked() {
|
||||
if ui.button("Open in browser").clicked() {
|
||||
let modifiers = ui.ctx().input(|i| i.modifiers);
|
||||
ui.ctx().output_mut(|o| {
|
||||
o.open_url = Some(egui::output::OpenUrl {
|
||||
@ -297,10 +303,10 @@ fn show_image_toggle(app: &mut GossipUi, ui: &mut Ui, url: Url) {
|
||||
});
|
||||
});
|
||||
}
|
||||
if ui.button("copy URL").clicked() {
|
||||
if ui.button("Copy URL").clicked() {
|
||||
ui.output_mut(|o| o.copied_text = url_string);
|
||||
}
|
||||
if ui.button("try reload").clicked() {
|
||||
if ui.button("Try reload ...").clicked() {
|
||||
app.retry_media(&url);
|
||||
}
|
||||
});
|
||||
@ -310,20 +316,24 @@ fn show_image_toggle(app: &mut GossipUi, ui: &mut Ui, url: Url) {
|
||||
|
||||
// workaround for egui bug where image enlarges the cursor height
|
||||
ui.set_row_height(row_height);
|
||||
|
||||
// now show a small hyperlink to the image
|
||||
// break_anywhere_hyperlink_to(ui, RichText::new(url_string.clone()).small(), url_string);
|
||||
}
|
||||
|
||||
/// Try to fetch and render a piece of media
|
||||
/// - return: true if successfully rendered, false otherwise
|
||||
fn try_render_media(app: &mut GossipUi, ui: &mut Ui, url: Url) -> Option<Response> {
|
||||
let mut response_return = None;
|
||||
if let Some(media) = app.try_get_media(ui.ctx(), url) {
|
||||
let ui_max = Vec2::new(
|
||||
ui.available_width(),
|
||||
ui.ctx().screen_rect().height() / 4.0,
|
||||
);
|
||||
if let Some(media) = app.try_get_media(ui.ctx(), url.clone()) {
|
||||
let ui_max = if app.media_full_width_list.contains(&url) {
|
||||
Vec2::new(
|
||||
ui.available_width() * 0.9,
|
||||
ui.ctx().screen_rect().height() * 0.9,
|
||||
)
|
||||
} else {
|
||||
Vec2::new(
|
||||
ui.available_width() / 2.0,
|
||||
ui.ctx().screen_rect().height() / 3.0,
|
||||
)
|
||||
};
|
||||
let msize = media.size_vec2();
|
||||
let aspect = media.aspect_ratio();
|
||||
|
||||
@ -362,22 +372,37 @@ fn try_render_media(app: &mut GossipUi, ui: &mut Ui, url: Url) -> Option<Respons
|
||||
egui::Frame::none()
|
||||
.inner_margin(egui::Margin::same(0.0))
|
||||
.outer_margin(egui::Margin {
|
||||
top: ui.available_height(), // line height
|
||||
top: 10.0,
|
||||
left: 0.0,
|
||||
right: 0.0,
|
||||
bottom: ui.available_height(), // line height
|
||||
bottom: 10.0,
|
||||
})
|
||||
.fill(egui::Color32::GRAY)
|
||||
.fill(egui::Color32::TRANSPARENT)
|
||||
.rounding(ui.style().noninteractive().rounding)
|
||||
.stroke(egui::Stroke {
|
||||
width: 1.0,
|
||||
color: egui::Color32::DARK_GRAY,
|
||||
})
|
||||
.show(ui, |ui| {
|
||||
let response = ui.add(Image::new(&media, size).sense(egui::Sense::click()));
|
||||
if response.hovered() {
|
||||
ui.ctx().set_cursor_icon(egui::CursorIcon::PointingHand);
|
||||
}
|
||||
let extend_area = egui::Rect{ min: response.rect.right_top(), max: response.rect.right_bottom() + egui::Vec2::new(20.0,0.0) };
|
||||
if let Some(pointer_pos) = ui.ctx().pointer_latest_pos() {
|
||||
if extend_area.contains( pointer_pos ) {
|
||||
if ui
|
||||
.add(
|
||||
egui::Button::new( if app.media_full_width_list.contains(&url) { "<" } else { ">" })
|
||||
.fill(egui::Color32::TRANSPARENT)
|
||||
.min_size(Vec2::new(20.0, ui.available_height())),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
if app.media_full_width_list.contains(&url) {
|
||||
app.media_full_width_list.remove(&url);
|
||||
} else {
|
||||
app.media_full_width_list.insert(url.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
response_return = Some(response);
|
||||
});
|
||||
};
|
||||
|
@ -132,6 +132,7 @@ struct GossipUi {
|
||||
about: About,
|
||||
icon: TextureHandle,
|
||||
placeholder_avatar: TextureHandle,
|
||||
expand_right_symbol: TextureHandle,
|
||||
settings: Settings,
|
||||
avatars: HashMap<PublicKeyHex, TextureHandle>,
|
||||
media: HashMap<Url, TextureHandle>,
|
||||
@ -139,6 +140,8 @@ struct GossipUi {
|
||||
media_show_list: HashSet<Url>,
|
||||
/// used when settings.show_media=false to explicitly hide
|
||||
media_hide_list: HashSet<Url>,
|
||||
/// media that the user has selected to show full-width
|
||||
media_full_width_list: HashSet<Url>,
|
||||
|
||||
// Search result
|
||||
search_result: String,
|
||||
@ -234,7 +237,7 @@ impl GossipUi {
|
||||
};
|
||||
|
||||
let placeholder_avatar_texture_handle = {
|
||||
let bytes = include_bytes!("../../placeholder_avatar.png");
|
||||
let bytes = include_bytes!("../../assets/placeholder_avatar.png");
|
||||
let image = image::load_from_memory(bytes).unwrap();
|
||||
let size = [image.width() as _, image.height() as _];
|
||||
let image_buffer = image.to_rgba8();
|
||||
@ -246,6 +249,18 @@ impl GossipUi {
|
||||
)
|
||||
};
|
||||
|
||||
let expand_right_symbol = {
|
||||
let bytes = include_bytes!("../../assets/expand-image.svg");
|
||||
let color_image = egui_extras::image::load_svg_bytes_with_size(
|
||||
bytes,
|
||||
egui_extras::image::FitTo::Size(200, 1000),
|
||||
).unwrap();
|
||||
cctx.egui_ctx.load_texture(
|
||||
"expand_right_symbol",
|
||||
color_image,
|
||||
TextureOptions::default())
|
||||
};
|
||||
|
||||
let current_dpi = (cctx.egui_ctx.pixels_per_point() * 72.0) as u32;
|
||||
let (override_dpi, override_dpi_value): (bool, u32) = match settings.override_dpi {
|
||||
Some(v) => (true, v),
|
||||
@ -281,11 +296,13 @@ impl GossipUi {
|
||||
about: crate::about::about(),
|
||||
icon: icon_texture_handle,
|
||||
placeholder_avatar: placeholder_avatar_texture_handle,
|
||||
expand_right_symbol: expand_right_symbol,
|
||||
settings,
|
||||
avatars: HashMap::new(),
|
||||
media: HashMap::new(),
|
||||
media_show_list: HashSet::new(),
|
||||
media_hide_list: HashSet::new(),
|
||||
media_full_width_list: HashSet::new(),
|
||||
search_result: "".to_owned(),
|
||||
draft: "".to_owned(),
|
||||
draft_needs_focus: false,
|
||||
@ -669,8 +686,7 @@ impl GossipUi {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_check_url(&self, url_string: &str) -> Option<Url>
|
||||
{
|
||||
pub fn try_check_url(&self, url_string: &str) -> Option<Url> {
|
||||
let unchecked_url = UncheckedUrl(url_string.to_owned());
|
||||
GLOBALS.media.check_url(unchecked_url)
|
||||
}
|
||||
@ -679,11 +695,12 @@ impl GossipUi {
|
||||
GLOBALS.media.retry_failed(&url.to_unchecked_url());
|
||||
}
|
||||
|
||||
pub fn try_get_media(
|
||||
&mut self,
|
||||
ctx: &Context,
|
||||
url: Url,
|
||||
) -> Option<TextureHandle> {
|
||||
pub fn has_media_loading_failed(&self, url_string: &str) -> bool {
|
||||
let unchecked_url = UncheckedUrl(url_string.to_owned());
|
||||
GLOBALS.media.has_failed(&unchecked_url)
|
||||
}
|
||||
|
||||
pub fn try_get_media(&mut self, ctx: &Context, url: Url) -> Option<TextureHandle> {
|
||||
// Do not keep retrying if failed
|
||||
if GLOBALS.media.has_failed(&url.to_unchecked_url()) {
|
||||
return None;
|
||||
|
Loading…
Reference in New Issue
Block a user