aboutsummaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
authorfiaxh <git@lightrise.org>2026-08-14 11:45:08 +0200
committerfiaxh <git@lightrise.org>2026-08-21 18:18:03 +0200
commit8d49d83b3b45ab22d7b9d945c4b32296b07cb49e (patch)
tree5a0bf3d777c4efd806388163fc9dc74c87edd07b /main
parent6d0706bcaa6d54354e416174e3d2654a2bff81fe (diff)
Add initial support for multi-file transfers
Diffstat (limited to 'main')
-rw-r--r--main/data/style.css5
-rw-r--r--main/meson.build1
-rw-r--r--main/src/ui/application.vala10
-rw-r--r--main/src/ui/chat_input/chat_input_controller.vala8
-rw-r--r--main/src/ui/conversation_content_view/content_populator.vala2
-rw-r--r--main/src/ui/conversation_content_view/file_default_widget.vala40
-rw-r--r--main/src/ui/conversation_content_view/file_group_widget.vala120
-rw-r--r--main/src/ui/conversation_content_view/file_image_widget.vala105
-rw-r--r--main/src/ui/conversation_content_view/file_transmission_progress.vala6
-rw-r--r--main/src/ui/conversation_content_view/file_widget.vala71
-rw-r--r--main/src/ui/conversation_selector/conversation_selector_row.vala19
-rw-r--r--main/src/ui/conversation_view.vala21
-rw-r--r--main/src/ui/conversation_view_controller.vala4
13 files changed, 289 insertions, 123 deletions
diff --git a/main/data/style.css b/main/data/style.css
index 1700a624..2c6d3d03 100644
--- a/main/data/style.css
+++ b/main/data/style.css
@@ -188,6 +188,11 @@ window.dino-main .file-image-widget .file-box-outer button:hover {
border-radius: 100%;
}
+/* Image file group */
+.dino-main .image-group {
+ border-radius: 8px;
+}
+
/* Call widget */
window.dino-main .call-box-outer.incoming {
diff --git a/main/meson.build b/main/meson.build
index 38c1a733..5b1aab08 100644
--- a/main/meson.build
+++ b/main/meson.build
@@ -49,6 +49,7 @@ sources = files(
'src/ui/conversation_content_view/file_default_widget.vala',
'src/ui/conversation_content_view/file_image_widget.vala',
'src/ui/conversation_content_view/file_transmission_progress.vala',
+ 'src/ui/conversation_content_view/file_group_widget.vala',
'src/ui/conversation_content_view/file_widget.vala',
'src/ui/conversation_content_view/item_actions.vala',
'src/ui/conversation_content_view/message_widget.vala',
diff --git a/main/src/ui/application.vala b/main/src/ui/application.vala
index 1b4dc049..62495871 100644
--- a/main/src/ui/application.vala
+++ b/main/src/ui/application.vala
@@ -244,6 +244,16 @@ public class Dino.Ui.Application : Adw.Application, Dino.Application {
call_state.reject();
});
add_action(deny_call_action);
+
+ SimpleAction save_file_action = new SimpleAction("file_open_save_dialog", VariantType.INT32);
+ save_file_action.activate.connect((variant) => {
+ print("action open save dialog\n");
+ int file_transfer_id = variant.get_int32();
+ FileTransfer? file_transfer = stream_interactor.get_module(FileTransferStorage.IDENTITY).get_file_by_id(file_transfer_id, null);
+
+ window.conversation_view.open_save_file_dialog(file_transfer);
+ });
+ add_action(save_file_action);
}
private void show_preferences_window() {
diff --git a/main/src/ui/chat_input/chat_input_controller.vala b/main/src/ui/chat_input/chat_input_controller.vala
index c93a9e22..afbef637 100644
--- a/main/src/ui/chat_input/chat_input_controller.vala
+++ b/main/src/ui/chat_input/chat_input_controller.vala
@@ -245,11 +245,11 @@ public class ChatInputController : Object {
send_text();
}
- foreach (File file in files_to_send) {
- stream_interactor.get_module(FileManager.IDENTITY).send_file.begin(file, conversation);
+ if (!files_to_send.is_empty) {
+ stream_interactor.get_module(FileManager2.IDENTITY).send_files.begin(files_to_send, conversation);
+ files_to_send = new ArrayList<File>();
+ chat_input.clear_files();
}
- files_to_send = new ArrayList<File>();
- chat_input.clear_files();
}
private void on_text_input_changed() {
diff --git a/main/src/ui/conversation_content_view/content_populator.vala b/main/src/ui/conversation_content_view/content_populator.vala
index ef859bde..4d1b8c90 100644
--- a/main/src/ui/conversation_content_view/content_populator.vala
+++ b/main/src/ui/conversation_content_view/content_populator.vala
@@ -70,6 +70,8 @@ public class ContentProvider : ContentItemCollection, Object {
return new FileMetaItem(content_item, stream_interactor);
} else if (content_item.type_ == CallItem.TYPE) {
return new CallMetaItem(content_item, stream_interactor);
+ } else if (content_item.type_ == FileGroupItem.TYPE) {
+ return new FileGroupMetaItem(content_item, stream_interactor);
}
critical("Got unknown content item type %s", content_item.type_);
return null;
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 a21e2afb..1ad3d6c2 100644
--- a/main/src/ui/conversation_content_view/file_default_widget.vala
+++ b/main/src/ui/conversation_content_view/file_default_widget.vala
@@ -51,13 +51,13 @@ public class FileDefaultWidget : Box {
mime_label.label = content_type != null ? content_type.get_description() : null;
}
- public void update_file_info(Xmpp.FileContentType? content_type, FileTransfer.State state, bool direction, int64 size, int64 transferred_bytes) {
- this.state = state;
+ public void update_file_info(FileTransfer file_transfer) {
+ this.state = file_transfer.state;
spinner.stop(); // A hidden spinning spinner still uses CPU. Deactivate asap
- content_type_image.icon_name = get_file_icon_name(content_type);
- string? mime_description = content_type != null ? content_type.get_description() : null;
+ content_type_image.icon_name = get_file_icon_name(file_transfer.content_type);
+ string? mime_description = file_transfer.content_type != null ? file_transfer.content_type.get_description() : null;
switch (state) {
case FileTransfer.State.COMPLETE:
@@ -66,23 +66,31 @@ public class FileDefaultWidget : Box {
// Create a menu
Menu menu_model = new Menu();
- menu_model.append(_("Open"), "file.open");
- menu_model.append(_("Save as…"), "file.save_as");
+
+ MenuItem open_file_item = new MenuItem(_("Open"), "app.file_open_externally");
+ open_file_item.set_action_and_target_value("app.file_open_externally", new Variant.int32(file_transfer.id));
+
+ MenuItem save_as_item = new MenuItem(_("Save as…"), "app.file_save_as");
+ save_as_item.set_action_and_target_value("app.file_open_save_dialog", new Variant.int32(file_transfer.id));
+
+ menu_model.append_item(open_file_item);
+ menu_model.append_item(save_as_item);
+
Gtk.PopoverMenu popover_menu = new Gtk.PopoverMenu.from_model(menu_model);
file_menu.popover = popover_menu;
popover_menu.closed.connect(on_pointer_left);
break;
case FileTransfer.State.IN_PROGRESS:
- if (direction == FileTransfer.DIRECTION_RECEIVED) {
- if (size > 0) {
- int64 progress = transferred_bytes * 100 / size;
- mime_label.label = _("Downloading %s… (%u%%)").printf(get_size_string(size), progress);
+ if (file_transfer.direction == FileTransfer.DIRECTION_RECEIVED) {
+ if (file_transfer.size > 0) {
+ int64 progress = file_transfer.transferred_bytes * 100 / file_transfer.size;
+ mime_label.label = _("Downloading %s… (%u%%)").printf(get_size_string(file_transfer.size), progress);
} else {
- mime_label.label = _("Downloading %s…").printf(get_size_string(size));
+ mime_label.label = _("Downloading %s…").printf(get_size_string(file_transfer.size));
}
} else {
- int64 progress = transferred_bytes * 100 / size;
- mime_label.label = _("Uploading %s… (%u%%)").printf(get_size_string(size), progress);
+ int64 progress = file_transfer.transferred_bytes * 100 / file_transfer.size;
+ mime_label.label = _("Uploading %s… (%u%%)").printf(get_size_string(file_transfer.size), progress);
}
spinner.start();
image_stack.set_visible_child_name("spinner");
@@ -96,9 +104,9 @@ public class FileDefaultWidget : Box {
break;
case FileTransfer.State.NOT_STARTED:
if (mime_description != null) {
- mime_label.label = _("%s offered: %s").printf(mime_description, get_size_string(size));
- } else if (size != -1) {
- mime_label.label = _("File offered: %s").printf(get_size_string(size));
+ mime_label.label = _("%s offered: %s").printf(mime_description, get_size_string(file_transfer.size));
+ } else if (file_transfer.size != -1) {
+ mime_label.label = _("File offered: %s").printf(get_size_string(file_transfer.size));
} else {
mime_label.label = _("File offered");
}
diff --git a/main/src/ui/conversation_content_view/file_group_widget.vala b/main/src/ui/conversation_content_view/file_group_widget.vala
new file mode 100644
index 00000000..80c41a7a
--- /dev/null
+++ b/main/src/ui/conversation_content_view/file_group_widget.vala
@@ -0,0 +1,120 @@
+using Gee;
+using Gdk;
+using Gtk;
+using Pango;
+using Xmpp;
+
+using Dino.Entities;
+
+namespace Dino.Ui {
+
+ public class FileGroupMetaItem : ConversationSummary.ContentMetaItem {
+
+ private StreamInteractor stream_interactor;
+ private FileGroupItem file_group_item;
+
+ public FileGroupMetaItem(ContentItem content_item, StreamInteractor stream_interactor) {
+ base(content_item);
+ this.stream_interactor = stream_interactor;
+ this.file_group_item = content_item as FileGroupItem;
+ }
+
+ public override Object? get_widget(Plugins.ConversationItemWidgetInterface outer, Plugins.WidgetType type) {
+ var file_transfers = file_group_item.file_group.file_transfers;
+
+ if (file_transfers.size > 1 && all_files_images(file_transfers)) {
+ return new ImageGroupWidget(file_transfers);
+ } else {
+ Box box = new Box(Orientation.VERTICAL, 6);
+ foreach (FileTransfer file_transfer in file_transfers) {
+ FileWidget widget = new FileWidget(file_transfer) { halign = Align.START };
+ widget.add_css_class("file-image-widget");
+ FileWidgetController widget_controller = new FileWidgetController(widget, file_transfer, stream_interactor);
+ box.append(widget);
+ }
+ return box;
+ }
+ }
+
+ public override Gee.List<Plugins.MessageAction>? get_item_actions(Plugins.WidgetType type) {
+ Gee.List<Plugins.MessageAction> actions = new ArrayList<Plugins.MessageAction>();
+ return actions;
+ }
+ }
+
+ public class ImageGroupWidget : Box {
+
+ private Gee.ArrayList<FileTransfer> file_transfers;
+
+ public ImageGroupWidget(Gee.ArrayList<FileTransfer> file_transfers) {
+ this.file_transfers = file_transfers;
+
+ if (file_transfers.size == 3) {
+ Box box = new Box(Orientation.HORIZONTAL, 4) {
+ overflow = Overflow.HIDDEN,
+ halign = Align.START
+ };
+ box.add_css_class("image-group");
+
+ var picture1 = new FileImageWidget.from_file_transfer(file_transfers[0], 200);
+ box.append(picture1);
+
+ Box box1 = new Box(Orientation.VERTICAL, 4);
+
+ var picture2 = new FileImageWidget.from_file_transfer(file_transfers[1], 100);
+ box1.append(picture2);
+ var picture3 = new FileImageWidget.from_file_transfer(file_transfers[2], 100);
+ box1.append(picture3);
+ box.append(box1);
+
+ this.append(box);
+ } else {
+ Box box = new Box(Orientation.VERTICAL, 4) {
+ overflow = Overflow.HIDDEN,
+ halign = Align.START
+ };
+ box.add_css_class("image-group");
+
+ Box row_upper_row = new Box(Orientation.HORIZONTAL, 4);
+
+ var picture1 = new FileImageWidget.from_file_transfer(file_transfers[0], 150);
+ row_upper_row.append(picture1);
+
+ var picture2 = new FileImageWidget.from_file_transfer(file_transfers[1], 150);
+ row_upper_row.append(picture2);
+ box.append(row_upper_row);
+
+ if (file_transfers.size >= 4) {
+
+ int size = 150;
+ if (file_transfers.size == 5) size = 99;
+
+ Box row_lower_row = new Box(Orientation.HORIZONTAL, 4);
+
+ var picture3 = new FileImageWidget.from_file_transfer(file_transfers[2], size);
+ row_lower_row.append(picture3);
+
+ var picture4 = new FileImageWidget.from_file_transfer(file_transfers[3], size);
+ row_lower_row.append(picture4);
+
+ if (file_transfers.size == 5) {
+ var picture5 = new FileImageWidget.from_file_transfer(file_transfers[4], size);
+ row_lower_row.append(picture5);
+ }
+
+ box.append(row_lower_row);
+ }
+ this.append(box);
+ }
+ }
+ }
+
+ public static bool all_files_images(Gee.ArrayList<FileTransfer> file_transfers) {
+ foreach (FileTransfer file_transfer in file_transfers) {
+ if (!Dino.Util.is_pixbuf_supported_content_type(file_transfer.content_type)) {
+ return false;
+ }
+ }
+ return true;
+ }
+} \ No newline at end of file
diff --git a/main/src/ui/conversation_content_view/file_image_widget.vala b/main/src/ui/conversation_content_view/file_image_widget.vala
index e936ca25..9f12f892 100644
--- a/main/src/ui/conversation_content_view/file_image_widget.vala
+++ b/main/src/ui/conversation_content_view/file_image_widget.vala
@@ -22,6 +22,8 @@ public class FileImageWidget : Widget {
private Gtk.Box image_overlay_toolbar = new Gtk.Box(Orientation.VERTICAL, 0) { halign=Align.END, valign=Align.START, margin_top=10, margin_start=10, margin_end=10, margin_bottom=10, vexpand=false, visible=false };
private Label file_size_label = new Label(null) { halign=Align.START, valign=Align.END, margin_bottom=4, margin_start=4, visible=false };
+ private int size = -1;
+
private FileTransfer file_transfer;
private FileTransmissionProgress transmission_progress = new FileTransmissionProgress() { halign=Align.CENTER, valign=Align.CENTER, visible=false };
@@ -34,22 +36,6 @@ public class FileImageWidget : Widget {
public FileImageWidget(int MAX_WIDTH=600, int MAX_HEIGHT=300) {
this.halign = Align.START;
- this.add_css_class("file-image-widget");
-
- // Setup menu button overlay
- MenuButton button = new MenuButton();
- button.icon_name = "dino-view-more";
- Menu menu_model = new Menu();
- menu_model.append(_("Open"), "file.open");
- menu_model.append(_("Save as…"), "file.save_as");
- Gtk.PopoverMenu popover_menu = new Gtk.PopoverMenu.from_model(menu_model);
- button.popover = popover_menu;
- image_overlay_toolbar.append(button);
- image_overlay_toolbar.add_css_class("card");
- image_overlay_toolbar.add_css_class("toolbar");
- image_overlay_toolbar.add_css_class("compact-card-toolbar");
- image_overlay_toolbar.set_cursor_from_name("default");
-
file_size_label.add_css_class("file-details");
overlay.set_child(stack);
@@ -65,12 +51,65 @@ public class FileImageWidget : Widget {
gesture_click_controller.button = 1; // listen for left clicks
gesture_click_controller.released.connect(on_image_clicked);
stack.add_controller(gesture_click_controller);
+ }
+
+ public FileImageWidget.from_file_transfer(FileTransfer file_transfer, int size = -1) {
+ this();
+
+ this.file_transfer = file_transfer;
+ this.size = size;
+
+ this.file_transfer.bind_property("size", file_size_label, "label", BindingFlags.SYNC_CREATE, file_size_label_transform);
+ this.file_transfer.bind_property("size", transmission_progress, "file-size", BindingFlags.SYNC_CREATE);
+ this.file_transfer.bind_property("transferred-bytes", transmission_progress, "transferred-size");
+
+ setup_signals(transmission_progress, file_transfer);
+ setup_menu_button();
+
+ file_transfer.notify["state"].connect(refresh_state);
+ file_transfer.sources_changed.connect(refresh_state);
+ refresh_state();
+ }
+
+ private static void setup_signals(FileTransmissionProgress transmission_progress, FileTransfer file_transfer) {
+ var file_transfer_id = file_transfer.id;
+
+ transmission_progress.start_download.connect(() => {
+ Dino.Application.get_default().activate_action("file_start_download", new Variant.int32(file_transfer_id));
+ });
+ transmission_progress.cancel_transfer.connect(() => {
+ Dino.Application.get_default().activate_action("file_cancel_transfer", new Variant.int32(file_transfer_id));
+ });
+ }
+
+ private void setup_menu_button() {
+ MenuButton button = new MenuButton();
+ button.icon_name = "dino-view-more";
+ Menu menu_model = new Menu();
+
+ MenuItem open_file_item = new MenuItem(_("Open"), "app.file_open_externally");
+ open_file_item.set_action_and_target_value("app.file_open_externally", new Variant.int32(file_transfer.id));
+
+ MenuItem save_as_item = new MenuItem(_("Save as…"), "app.file_save_as");
+ save_as_item.set_action_and_target_value("app.file_open_save_dialog", new Variant.int32(file_transfer.id));
+
+ menu_model.append_item(open_file_item);
+ menu_model.append_item(save_as_item);
+
+ Gtk.PopoverMenu popover_menu = new Gtk.PopoverMenu.from_model(menu_model);
+ button.popover = popover_menu;
+ image_overlay_toolbar.append(button);
+ image_overlay_toolbar.add_css_class("card");
+ image_overlay_toolbar.add_css_class("toolbar");
+ image_overlay_toolbar.add_css_class("compact-card-toolbar");
+ image_overlay_toolbar.set_cursor_from_name("default");
EventControllerMotion this_motion_events = new EventControllerMotion();
this.add_controller(this_motion_events);
this_motion_events.enter.connect((controller, x, y) => {
(controller.widget as FileImageWidget).on_motion_event_enter();
});
+
attach_on_motion_event_leave(this_motion_events, button);
}
@@ -88,18 +127,6 @@ public class FileImageWidget : Widget {
file_size_label.visible = file_transfer != null && file_transfer.direction == FileTransfer.DIRECTION_RECEIVED && file_transfer.state == FileTransfer.State.NOT_STARTED && !file_transfer.sfs_sources.is_empty;
}
- public async void set_file_transfer(FileTransfer file_transfer) {
- this.file_transfer = file_transfer;
-
- this.file_transfer.bind_property("size", file_size_label, "label", BindingFlags.SYNC_CREATE, file_size_label_transform);
- this.file_transfer.bind_property("size", transmission_progress, "file-size", BindingFlags.SYNC_CREATE);
- this.file_transfer.bind_property("transferred-bytes", transmission_progress, "transferred-size");
-
- file_transfer.notify["state"].connect(refresh_state);
- file_transfer.sources_changed.connect(refresh_state);
- refresh_state();
- }
-
private static bool file_size_label_transform(Binding binding, Value from_value, ref Value to_value) {
to_value = FileDefaultWidget.get_size_string((int64) from_value);
return true;
@@ -153,7 +180,7 @@ public class FileImageWidget : Widget {
}
public async void load_from_file(File file, string file_name) throws GLib.Error {
- FixedRatioPicture image = new FixedRatioPicture() { min_width=100, min_height=100, max_width=600, max_height=300 };
+ FixedRatioPicture image = create_picture();
FileInputStream file_stream = null;
try {
@@ -201,7 +228,7 @@ public class FileImageWidget : Widget {
throw new Error(-1, 0, "Error scaling preview image");
}
- FixedRatioPicture image = new FixedRatioPicture() { min_width=100, min_height=100, max_width=600, max_height=300 };
+ FixedRatioPicture image = create_picture();
image.paintable = Texture.for_pixbuf(pixbuf);
stack.add_child(image);
stack.set_visible_child(image);
@@ -216,12 +243,12 @@ public class FileImageWidget : Widget {
if (n_press == 1) {
image_overlay_toolbar.visible = !image_overlay_toolbar.visible;
} else if (n_press == 2) {
- this.activate_action("file.open", null);
+ Dino.Application.get_default().activate_action("file_open_externally", new Variant.int32(file_transfer.id));
image_overlay_toolbar.visible = false;
}
break;
default:
- this.activate_action("file.open", null);
+ Dino.Application.get_default().activate_action("file_open_externally", new Variant.int32(file_transfer.id));
image_overlay_toolbar.visible = false;
break;
}
@@ -237,6 +264,20 @@ public class FileImageWidget : Widget {
(file_transfer.state == FileTransfer.State.COMPLETE || file_transfer.thumbnails.size > 0);
}
+ private FixedRatioPicture create_picture() {
+ if (size == -1) {
+ return new FixedRatioPicture() {
+ min_width=100, max_width=600,
+ min_height=100, max_height=300
+ };
+ } else {
+ return new FixedRatioPicture() {
+ height_request = size, width_request = size,
+ content_fit = ContentFit.COVER, halign = Align.START
+ };
+ }
+ }
+
public override void dispose() {
if (overlay != null && overlay.parent != null) overlay.unparent();
base.dispose();
diff --git a/main/src/ui/conversation_content_view/file_transmission_progress.vala b/main/src/ui/conversation_content_view/file_transmission_progress.vala
index e3f33448..43885c1b 100644
--- a/main/src/ui/conversation_content_view/file_transmission_progress.vala
+++ b/main/src/ui/conversation_content_view/file_transmission_progress.vala
@@ -9,6 +9,9 @@ namespace Dino.Ui {
public class FileTransmissionProgress : Adw.Bin {
+ public signal void start_download();
+ public signal void cancel_transfer();
+
public enum State {
UNKNOWN_SOURCE,
DOWNLOAD_NOT_STARTED,
@@ -124,11 +127,12 @@ namespace Dino.Ui {
break;
case DOWNLOAD_NOT_STARTED_FAILED_BEFORE:
case DOWNLOAD_NOT_STARTED:
+ start_download();
this.activate_action("file.download", null);
break;
case DOWNLOADING:
case UPLOADING:
- this.activate_action("file.cancel", null);
+ cancel_transfer();
break;
}
}
diff --git a/main/src/ui/conversation_content_view/file_widget.vala b/main/src/ui/conversation_content_view/file_widget.vala
index ecc2d3e9..04185343 100644
--- a/main/src/ui/conversation_content_view/file_widget.vala
+++ b/main/src/ui/conversation_content_view/file_widget.vala
@@ -57,18 +57,6 @@ public class FileWidget : SizeRequestBin {
private FileDefaultWidgetController default_widget_controller;
private Widget? content = null;
- public signal void open_file();
- public signal void save_file_as();
- public signal void start_download();
- public signal void cancel_download();
-
- class construct {
- install_action("file.open", null, (widget, action_name) => { ((FileWidget) widget).open_file(); });
- install_action("file.save_as", null, (widget, action_name) => { ((FileWidget) widget).save_file_as(); });
- install_action("file.download", null, (widget, action_name) => { ((FileWidget) widget).start_download(); });
- install_action("file.cancel", null, (widget, action_name) => { ((FileWidget) widget).cancel_download(); });
- }
-
construct {
margin_top = 4;
size_request_mode = SizeRequestMode.HEIGHT_FOR_WIDTH;
@@ -79,11 +67,6 @@ public class FileWidget : SizeRequestBin {
this.file_transfer = file_transfer;
update_widget.begin();
-// size_allocate.connect((allocation) => {
-// if (allocation.height > parent.get_allocated_height()) {
-// Idle.add(() => { parent.queue_resize(); return false; });
-// }
-// });
file_transfer.bind_property("state", this, "file-transfer-state");
file_transfer.bind_property("content-type", this, "file-transfer-content-type");
@@ -100,8 +83,8 @@ public class FileWidget : SizeRequestBin {
FileImageWidget file_image_widget = null;
try {
- file_image_widget = new FileImageWidget();
- yield file_image_widget.set_file_transfer(file_transfer);
+ file_image_widget = new FileImageWidget.from_file_transfer(file_transfer);
+ file_image_widget.add_css_class("file-image-widget");
// If the widget changed in the meanwhile, stop
if (content != content_bak) return;
@@ -152,50 +135,6 @@ public class FileWidgetController : Object {
});
this.file_transfer = file_transfer;
this.stream_interactor = stream_interactor;
-
- widget.open_file.connect(open_file);
- widget.save_file_as.connect(save_file);
- widget.start_download.connect(start_download);
- widget.cancel_download.connect(cancel_download);
- }
-
- private void open_file() {
- try{
- AppInfo.launch_default_for_uri(file_transfer.get_file().get_uri(), null);
- } catch (Error err) {
- warning("Failed to open %s - %s", file_transfer.get_file().get_uri(), err.message);
- }
- }
-
- private void save_file() {
- var save_dialog = new FileChooserNative(_("Save as…"), widget.get_root() as Gtk.Window, FileChooserAction.SAVE, null, null);
- save_dialog.set_modal(true);
- save_dialog.set_current_name(file_transfer.file_name);
-
- save_dialog.response.connect(() => {
- File? target_file = save_dialog.get_file();
- if (target_file == null) {
- warning("No file returned from save dialog.");
- return;
- }
- try {
- file_transfer.get_file().copy(save_dialog.get_file(), GLib.FileCopyFlags.OVERWRITE, null);
- } catch (Error err) {
- warning("Failed copy file %s - %s", file_transfer.get_file().get_uri(), err.message);
- }
- });
-
- save_dialog.show();
- }
-
- private void start_download() {
- if (stream_interactor != null) {
- stream_interactor.get_module(FileManager.IDENTITY).download_file.begin(file_transfer);
- }
- }
-
- private void cancel_download() {
- file_transfer.cancellable.cancel();
}
}
@@ -234,16 +173,16 @@ public class FileDefaultWidgetController : Object {
private void update_file_info() {
state = file_transfer.state;
- widget.update_file_info(file_transfer.content_type, file_transfer.state, file_transfer.direction, file_transfer.size, file_transfer.transferred_bytes);
+ widget.update_file_info(file_transfer);
}
private void on_clicked() {
switch (state) {
case FileTransfer.State.COMPLETE:
- widget.activate_action("file.open", null);
+ Dino.Application.get_default().activate_action("file_open_externally", new GLib.Variant.int32(file_transfer.id));
break;
case FileTransfer.State.NOT_STARTED:
- widget.activate_action("file.download", null);
+ Dino.Application.get_default().activate_action("file_start_download", new GLib.Variant.int32(file_transfer.id));
break;
default:
// Clicking doesn't do anything in FAILED and IN_PROGRESS states
diff --git a/main/src/ui/conversation_selector/conversation_selector_row.vala b/main/src/ui/conversation_selector/conversation_selector_row.vala
index fd5814fa..0e565c84 100644
--- a/main/src/ui/conversation_selector/conversation_selector_row.vala
+++ b/main/src/ui/conversation_selector/conversation_selector_row.vala
@@ -226,6 +226,25 @@ public class ConversationSelectorRow : ListBoxRow {
message_label.label = (file_is_image ? _("Image received") : _("File received") );
}
break;
+ case FileGroupItem.TYPE:
+ FileGroupItem file_group_item = last_content_item as FileGroupItem;
+ FileTransfer first_transfer = file_group_item.file_group.file_transfers.get(0);
+
+ if (conversation.type_ == Conversation.Type.GROUPCHAT) {
+ // TODO properly display nick for oneself
+ nick_label.label = Util.get_participant_display_name(stream_interactor, conversation, first_transfer.from, true) + ": ";
+ } else {
+ nick_label.label = first_transfer.direction == Message.DIRECTION_SENT ? _("Me") + ": " : "";
+ }
+
+ bool all_files_images = Ui.all_files_images(file_group_item.file_group.file_transfers);
+ change_label_attribute(message_label, attr_style_new(Pango.Style.ITALIC));
+ if (first_transfer.direction == Message.DIRECTION_SENT) {
+ message_label.label = (all_files_images ? _("Images sent") : _("Files sent") );
+ } else {
+ message_label.label = (all_files_images ? _("Images received") : _("Files received") );
+ }
+ break;
case CallItem.TYPE:
CallItem call_item = (CallItem) last_content_item;
Call call = call_item.call;
diff --git a/main/src/ui/conversation_view.vala b/main/src/ui/conversation_view.vala
index 26043666..4bb1f537 100644
--- a/main/src/ui/conversation_view.vala
+++ b/main/src/ui/conversation_view.vala
@@ -17,6 +17,27 @@ public class ConversationView : Widget {
construct {
this.layout_manager = new BinLayout();
}
+
+ public void open_save_file_dialog(FileTransfer file_transfer) {
+ var save_dialog = new FileChooserNative(_("Save as…"), (Gtk.Window) this.get_root(), FileChooserAction.SAVE, null, null);
+ save_dialog.set_modal(true);
+ save_dialog.set_current_name(file_transfer.file_name);
+
+ save_dialog.response.connect(() => {
+ File? target_file = save_dialog.get_file();
+ if (target_file == null) {
+ warning("No file returned from save dialog.");
+ return;
+ }
+ try {
+ file_transfer.get_file().copy(save_dialog.get_file(), GLib.FileCopyFlags.OVERWRITE, null);
+ } catch (Error err) {
+ warning("Failed copy file %s - %s", file_transfer.get_file().get_uri(), err.message);
+ }
+ });
+
+ save_dialog.show();
+ }
}
}
diff --git a/main/src/ui/conversation_view_controller.vala b/main/src/ui/conversation_view_controller.vala
index ef13b026..9626a39d 100644
--- a/main/src/ui/conversation_view_controller.vala
+++ b/main/src/ui/conversation_view_controller.vala
@@ -216,10 +216,6 @@ public class ConversationViewController : Object {
chooser.show();
}
- private void send_file(File file) {
- stream_interactor.get_module(FileManager.IDENTITY).send_file.begin(file, conversation);
- }
-
private bool forward_key_press_to_chat_input(EventControllerKey key_controller, uint keyval, uint keycode, Gdk.ModifierType state) {
if (view.get_root().get_focus() is TextView) {
return false;