diff --git a/main/data/file_default_widget.ui b/main/data/file_default_widget.ui index 9da961c4..7da52ec2 100644 --- a/main/data/file_default_widget.ui +++ b/main/data/file_default_widget.ui @@ -88,6 +88,19 @@ + + + False + none + + + True + open-menu-symbolic + 1 + + + + diff --git a/main/src/ui/conversation_content_view/file_default_widget.vala b/main/src/ui/conversation_content_view/file_default_widget.vala index 892c7ba2..9832e527 100644 --- a/main/src/ui/conversation_content_view/file_default_widget.vala +++ b/main/src/ui/conversation_content_view/file_default_widget.vala @@ -15,12 +15,18 @@ public class FileDefaultWidget : EventBox { [GtkChild] public unowned Image content_type_image; [GtkChild] public unowned Spinner spinner; [GtkChild] public unowned EventBox stack_event_box; + [GtkChild] public MenuButton file_menu; + + public ModelButton file_open_button; + public ModelButton file_save_button; private FileTransfer.State state; public FileDefaultWidget() { this.enter_notify_event.connect(on_pointer_entered); this.leave_notify_event.connect(on_pointer_left); + file_open_button = new ModelButton() { text=_("Open"), visible=true }; + file_save_button = new ModelButton() { text=_("Save as..."), visible=true }; } public void update_file_info(string? mime_type, FileTransfer.State state, long size) { @@ -35,6 +41,15 @@ public class FileDefaultWidget : EventBox { case FileTransfer.State.COMPLETE: mime_label.label = mime_description; image_stack.set_visible_child_name("content_type_image"); + Gtk.PopoverMenu popover_menu = new Gtk.PopoverMenu(); + Box file_menu_box = new Box(Orientation.VERTICAL, 0) { margin=10, visible=true }; + file_menu_box.add(file_open_button); + file_menu_box.add(file_save_button); + popover_menu.add(file_menu_box); + file_menu.popover = popover_menu; + file_menu.clicked.connect(() => { + popover_menu.visible = true; + }); break; case FileTransfer.State.IN_PROGRESS: mime_label.label = _("Downloading %s…").printf(get_size_string(size)); @@ -67,17 +82,22 @@ public class FileDefaultWidget : EventBox { if (state == FileTransfer.State.NOT_STARTED) { image_stack.set_visible_child_name("download_image"); } + if (state == FileTransfer.State.COMPLETE) { + file_menu.visible = true; + } return false; } private bool on_pointer_left(Gdk.EventCrossing event) { if (event.detail == Gdk.NotifyType.INFERIOR) return false; + if (file_menu.popover.visible == true) return false; event.get_window().set_cursor(new Cursor.for_display(Gdk.Display.get_default(), CursorType.XTERM)); content_type_image.opacity = 0.5; if (state == FileTransfer.State.NOT_STARTED) { image_stack.set_visible_child_name("content_type_image"); } + file_menu.visible = false; return false; } diff --git a/main/src/ui/conversation_content_view/file_widget.vala b/main/src/ui/conversation_content_view/file_widget.vala index 5766ec25..d48185ec 100644 --- a/main/src/ui/conversation_content_view/file_widget.vala +++ b/main/src/ui/conversation_content_view/file_widget.vala @@ -128,6 +128,8 @@ public class FileDefaultWidgetController : Object { public FileDefaultWidgetController(FileDefaultWidget widget) { this.widget = widget; widget.button_release_event.connect(on_clicked); + widget.file_open_button.clicked.connect(open_file); + widget.file_save_button.clicked.connect(save_file); } public void set_file_transfer(FileTransfer file_transfer, StreamInteractor stream_interactor) { @@ -160,15 +162,54 @@ public class FileDefaultWidgetController : Object { widget.update_file_info(file_transfer.mime_type, file_transfer.state, file_transfer.size); } + private void open_file() { + try{ + AppInfo.launch_default_for_uri(file_uri, null); + } catch (Error err) { + warning("Failed to open %s - %s", file_uri, err.message); + } + } + + private void save_as(Gtk.Dialog dialog, int response_id) { + var save_dialog = dialog as Gtk.FileChooserDialog; + File file_src; + switch (response_id) { + case Gtk.ResponseType.ACCEPT: + file_src = GLib.File.new_for_uri(file_uri); + try{ + file_src.copy(save_dialog.get_file(), GLib.FileCopyFlags.OVERWRITE, null); + } catch (Error err) { + warning("Failed copy file %s - %s", file_uri, err.message); + } + break; + default: + break; + } + dialog.destroy(); + } + + private void save_file() { + var save_dialog = new Gtk.FileChooserDialog("Save as...", this as Gtk.Window, Gtk.FileChooserAction.SAVE, Gtk.Stock.CANCEL, Gtk.ResponseType.CANCEL, Gtk.Stock.SAVE, Gtk.ResponseType.ACCEPT); + save_dialog.set_do_overwrite_confirmation(true); + save_dialog.set_modal(true); + try { + (save_dialog as Gtk.FileChooser).set_current_name(GLib.Uri.escape_string(GLib.Path.get_basename(file_uri))); + (save_dialog as Gtk.FileChooser).set_uri(GLib.Uri.escape_string(GLib.Path.get_basename(GLib.Uri.unescape_string(file_uri)))); + } catch (GLib.Error error) { + warning("Faild to open save dialog: %s\n", error.message); + } + save_dialog.response.connect(save_as); + save_dialog.show(); + } + private bool on_clicked(EventButton event_button) { switch (state) { case FileTransfer.State.COMPLETE: - if (event_button.button == 1) { - try{ - AppInfo.launch_default_for_uri(file_uri, null); - } catch (Error err) { - warning("Failed to open %s - %s", file_uri, err.message); - } + if (event_button.button == 1 && this.widget.file_menu.popover.visible == false) { + open_file(); + } + if (event_button.button == 3 && this.widget.file_menu.popover.visible == false) { + save_file(); } break; case FileTransfer.State.NOT_STARTED: