session: Add action to copy an image in event's context menu
This commit is contained in:
parent
4a31e667a3
commit
b73c149a22
|
@ -41,7 +41,7 @@
|
|||
<attribute name="hidden-when">action-missing</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Copy Image</attribute>
|
||||
<attribute name="label" translatable="yes">_Copy Thumbnail</attribute>
|
||||
<attribute name="action">event.copy-image</attribute>
|
||||
<attribute name="hidden-when">action-missing</attribute>
|
||||
</item>
|
||||
|
|
|
@ -359,6 +359,11 @@ impl ImagePaintable {
|
|||
pub fn is_animation(&self) -> bool {
|
||||
self.imp().frames.borrow().is_some()
|
||||
}
|
||||
|
||||
/// Get the current frame of this `ImagePaintable`, if any.
|
||||
pub fn current_frame(&self) -> Option<gdk::Texture> {
|
||||
self.imp().frame.borrow().clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn texture_from_data(
|
||||
|
|
|
@ -303,4 +303,15 @@ impl MediaContentViewer {
|
|||
location.set_location(geo_uri);
|
||||
self.show_viewer();
|
||||
}
|
||||
|
||||
/// Get the texture displayed by this widget, if any.
|
||||
pub fn texture(&self) -> Option<gdk::Texture> {
|
||||
self.imp()
|
||||
.viewer
|
||||
.child()
|
||||
.and_then(|w| w.downcast::<gtk::Picture>().ok())
|
||||
.and_then(|p| p.paintable())
|
||||
.and_then(|p| p.downcast::<ImagePaintable>().ok())
|
||||
.and_then(|p| p.current_frame())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@ use crate::{
|
|||
message_row::MessageRow, DividerRow, RoomHistory, StateRow, TypingRow,
|
||||
},
|
||||
room::{
|
||||
Event, EventActions, PlaceholderKind, SupportedEvent, TimelineDayDivider, TimelineItem,
|
||||
TimelineNewMessagesDivider, TimelinePlaceholder,
|
||||
Event, EventActions, EventTexture, PlaceholderKind, SupportedEvent, TimelineDayDivider,
|
||||
TimelineItem, TimelineNewMessagesDivider, TimelinePlaceholder,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -345,4 +345,11 @@ impl ItemRow {
|
|||
}
|
||||
}
|
||||
|
||||
impl EventActions for ItemRow {}
|
||||
impl EventActions for ItemRow {
|
||||
fn texture(&self) -> Option<EventTexture> {
|
||||
self.child()
|
||||
.and_then(|w| w.downcast::<MessageRow>().ok())
|
||||
.and_then(|r| r.texture())
|
||||
.map(EventTexture::Thumbnail)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use adw::{prelude::*, subclass::prelude::*};
|
||||
use gettextrs::gettext;
|
||||
use gtk::{glib, glib::clone};
|
||||
use gtk::{gdk, glib, glib::clone};
|
||||
use log::warn;
|
||||
use matrix_sdk::ruma::events::{
|
||||
room::message::{MessageType, Relation},
|
||||
|
@ -137,6 +137,17 @@ impl MessageContent {
|
|||
build_content(self, event, format);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the texture displayed by this widget, if any.
|
||||
pub fn texture(&self) -> Option<gdk::Texture> {
|
||||
let mut content = self.child()?;
|
||||
|
||||
if let Some(reply) = content.downcast_ref::<MessageReply>() {
|
||||
content = reply.content().child()?;
|
||||
}
|
||||
|
||||
content.downcast_ref::<MessageMedia>()?.texture()
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the content widget of `event` as a child of `parent`.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use adw::{prelude::*, subclass::prelude::*};
|
||||
use gettextrs::gettext;
|
||||
use gtk::{
|
||||
gio,
|
||||
gdk, gio,
|
||||
glib::{self, clone},
|
||||
CompositeTemplate,
|
||||
};
|
||||
|
@ -476,4 +476,15 @@ impl MessageMedia {
|
|||
})
|
||||
);
|
||||
}
|
||||
|
||||
/// Get the texture displayed by this widget, if any.
|
||||
pub fn texture(&self) -> Option<gdk::Texture> {
|
||||
self.imp()
|
||||
.media
|
||||
.child()
|
||||
.and_then(|w| w.downcast::<gtk::Picture>().ok())
|
||||
.and_then(|p| p.paintable())
|
||||
.and_then(|p| p.downcast::<ImagePaintable>().ok())
|
||||
.and_then(|p| p.current_frame())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ mod text;
|
|||
|
||||
use adw::{prelude::*, subclass::prelude::*};
|
||||
use gtk::{
|
||||
glib,
|
||||
gdk, glib,
|
||||
glib::{clone, signal::SignalHandlerId},
|
||||
CompositeTemplate,
|
||||
};
|
||||
|
@ -196,4 +196,9 @@ impl MessageRow {
|
|||
fn update_content(&self, event: &SupportedEvent) {
|
||||
self.imp().content.update_for_event(event);
|
||||
}
|
||||
|
||||
/// Get the texture displayed by this widget, if any.
|
||||
pub fn texture(&self) -> Option<gdk::Texture> {
|
||||
self.imp().content.texture()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use gtk::{gdk, gio, glib, glib::clone, CompositeTemplate};
|
|||
use log::warn;
|
||||
use matrix_sdk::ruma::events::{room::message::MessageType, AnyMessageLikeEventContent};
|
||||
|
||||
use super::room::EventActions;
|
||||
use super::room::{EventActions, EventTexture};
|
||||
use crate::{
|
||||
components::{ContentType, ImagePaintable, MediaContentViewer},
|
||||
session::room::SupportedEvent,
|
||||
|
@ -293,4 +293,8 @@ impl MediaViewer {
|
|||
}
|
||||
}
|
||||
|
||||
impl EventActions for MediaViewer {}
|
||||
impl EventActions for MediaViewer {
|
||||
fn texture(&self) -> Option<EventTexture> {
|
||||
self.imp().media.texture().map(EventTexture::Original)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use gettextrs::gettext;
|
||||
use gtk::{gio, glib, glib::clone, prelude::*};
|
||||
use gtk::{gdk, gio, glib, glib::clone, prelude::*};
|
||||
use log::error;
|
||||
use matrix_sdk::ruma::events::{room::message::MessageType, AnyMessageLikeEventContent};
|
||||
use once_cell::sync::Lazy;
|
||||
|
@ -213,6 +213,27 @@ where
|
|||
}
|
||||
|
||||
MessageType::Image(_) => {
|
||||
// Copy the texture to the clipboard.
|
||||
gtk_macros::action!(
|
||||
&action_group,
|
||||
"copy-image",
|
||||
clone!(@weak self as widget, @weak event => move |_, _| {
|
||||
let texture = widget.texture().expect("A widget with an image should have a texture");
|
||||
|
||||
match texture {
|
||||
EventTexture::Original(texture) => {
|
||||
widget.clipboard().set_texture(&texture);
|
||||
toast!(widget, gettext("Image copied to clipboard"));
|
||||
}
|
||||
EventTexture::Thumbnail(texture) => {
|
||||
widget.clipboard().set_texture(&texture);
|
||||
toast!(widget, gettext("Thumbnail copied to clipboard"));
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// Save the image to a file.
|
||||
gtk_macros::action!(
|
||||
&action_group,
|
||||
"save-image",
|
||||
|
@ -294,4 +315,16 @@ where
|
|||
})
|
||||
);
|
||||
}
|
||||
|
||||
/// Get the texture displayed by this widget, if any.
|
||||
fn texture(&self) -> Option<EventTexture>;
|
||||
}
|
||||
|
||||
/// A texture from an event.
|
||||
pub enum EventTexture {
|
||||
/// The texture is the original image.
|
||||
Original(gdk::Texture),
|
||||
|
||||
/// The texture is a thumbnail of the image.
|
||||
Thumbnail(gdk::Texture),
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ use ruma::events::{typing::TypingEventContent, MessageLikeEventContent, SyncEphe
|
|||
|
||||
pub use self::{
|
||||
event::*,
|
||||
event_actions::EventActions,
|
||||
event_actions::{EventActions, EventTexture},
|
||||
highlight_flags::HighlightFlags,
|
||||
member::{Member, Membership},
|
||||
member_list::MemberList,
|
||||
|
|
Loading…
Reference in New Issue