fractal/session/view/content/room_history/message_toolbar/
attachment_dialog.rsuse adw::{prelude::*, subclass::prelude::*};
use futures_channel::oneshot;
use gtk::{gdk, gio, glib, glib::clone, CompositeTemplate};
use tracing::error;
use crate::{components::MediaContentViewer, spawn};
mod imp {
use std::cell::RefCell;
use super::*;
#[derive(Debug, Default, CompositeTemplate)]
#[template(
resource = "/org/gnome/Fractal/ui/session/view/content/room_history/message_toolbar/attachment_dialog.ui"
)]
pub struct AttachmentDialog {
#[template_child]
cancel_button: TemplateChild<gtk::Button>,
#[template_child]
send_button: TemplateChild<gtk::Button>,
#[template_child]
media: TemplateChild<MediaContentViewer>,
sender: RefCell<Option<oneshot::Sender<gtk::ResponseType>>>,
}
#[glib::object_subclass]
impl ObjectSubclass for AttachmentDialog {
const NAME: &'static str = "AttachmentDialog";
type Type = super::AttachmentDialog;
type ParentType = adw::Dialog;
fn class_init(klass: &mut Self::Class) {
Self::bind_template(klass);
Self::bind_template_callbacks(klass);
}
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
obj.init_template();
}
}
impl ObjectImpl for AttachmentDialog {
fn constructed(&self) {
self.parent_constructed();
self.set_loading(true);
}
}
impl WidgetImpl for AttachmentDialog {
fn grab_focus(&self) -> bool {
let loading = !self.send_button.is_sensitive();
if loading {
self.cancel_button.grab_focus()
} else {
self.send_button.grab_focus()
}
}
}
impl AdwDialogImpl for AttachmentDialog {
fn closed(&self) {
self.send_response(gtk::ResponseType::Cancel);
}
}
#[gtk::template_callbacks]
impl AttachmentDialog {
fn set_loading(&self, loading: bool) {
self.send_button.set_sensitive(!loading);
self.grab_focus();
}
fn send_response(&self, response: gtk::ResponseType) {
if let Some(sender) = self.sender.take() {
if sender.send(response).is_err() {
error!("Could not send attachment dialog response {response:?}");
}
}
}
pub(super) fn set_image(&self, image: &gdk::Texture) {
self.media.view_image(image);
self.set_loading(false);
}
pub(super) async fn set_file(&self, file: gio::File) {
self.media.view_file(file.into(), None).await;
self.set_loading(false);
}
pub(super) fn set_location(&self, geo_uri: &geo_uri::GeoUri) {
self.media.view_location(geo_uri);
self.set_loading(false);
}
#[template_callback]
fn send(&self) {
self.send_response(gtk::ResponseType::Ok);
self.obj().close();
}
pub(super) async fn response_future(&self, parent: >k::Widget) -> gtk::ResponseType {
let (sender, receiver) = oneshot::channel();
self.sender.replace(Some(sender));
self.obj().present(Some(parent));
receiver.await.unwrap_or(gtk::ResponseType::Cancel)
}
}
}
glib::wrapper! {
pub struct AttachmentDialog(ObjectSubclass<imp::AttachmentDialog>)
@extends gtk::Widget, adw::Dialog;
}
impl AttachmentDialog {
pub fn new(title: &str) -> Self {
glib::Object::builder().property("title", title).build()
}
pub(crate) fn set_image(&self, image: &gdk::Texture) {
self.imp().set_image(image);
}
pub(crate) fn set_file(&self, file: gio::File) {
let imp = self.imp();
spawn!(clone!(
#[weak]
imp,
async move {
imp.set_file(file).await;
}
));
}
pub(crate) fn set_location(&self, geo_uri: &geo_uri::GeoUri) {
self.imp().set_location(geo_uri);
}
pub(crate) async fn response_future(
&self,
parent: &impl IsA<gtk::Widget>,
) -> gtk::ResponseType {
self.imp().response_future(parent.upcast_ref()).await
}
}