Move ConversationContentView+ChatInput into ConversationView, handle drag'n'drop on ConversationView level
This commit is contained in:
parent
a7e92960a3
commit
28c44380ba
|
@ -43,6 +43,7 @@ set(RESOURCE_LIST
|
|||
contact_details_dialog.ui
|
||||
conversation_list_titlebar.ui
|
||||
conversation_list_titlebar_csd.ui
|
||||
conversation_view.ui
|
||||
emojichooser.ui
|
||||
global_search.ui
|
||||
conversation_selector/chat_row_tooltip.ui
|
||||
|
@ -97,6 +98,8 @@ SOURCES
|
|||
src/ui/chat_input_controller.vala
|
||||
src/ui/conversation_list_titlebar.vala
|
||||
src/ui/conversation_list_titlebar_csd.vala
|
||||
src/ui/conversation_view.vala
|
||||
src/ui/conversation_view_controller.vala
|
||||
src/ui/global_search.vala
|
||||
src/ui/notifications.vala
|
||||
src/ui/settings_dialog.vala
|
||||
|
|
54
main/data/conversation_view.ui
Normal file
54
main/data/conversation_view.ui
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="DinoUiConversationView" parent="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="visible">True</property>
|
||||
<style>
|
||||
<class name="dino-conversation"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkOverlay">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="DinoUiConversationSummaryConversationView" id="conversation_frame">
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="overlay">
|
||||
<object class="GtkRevealer" id="goto_end_revealer">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">end</property>
|
||||
<property name="transition-type">crossfade</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="margin-end">30</property>
|
||||
<property name="margin-bottom">30</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="goto_end_button">
|
||||
<property name="vexpand">False</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">end</property>
|
||||
<property name="visible">True</property>
|
||||
<style>
|
||||
<class name="circular"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="icon-name">go-down-symbolic</property>
|
||||
<property name="icon-size">1</property>
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="DinoUiChatInputView" id="chat_input">
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
|
@ -69,55 +69,8 @@
|
|||
<object class="GtkStack" id="right_stack">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkOverlay">
|
||||
<object class="DinoUiConversationView" id="conversation_view">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="visible">True</property>
|
||||
<style>
|
||||
<class name="dino-conversation"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="DinoUiConversationSummaryConversationView" id="conversation_frame">
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="DinoUiChatInputView" id="chat_input">
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="overlay">
|
||||
<object class="GtkRevealer" id="goto_end_revealer">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">end</property>
|
||||
<property name="transition-type">crossfade</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="margin-end">30</property>
|
||||
<property name="margin-bottom">70</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="goto_end_button">
|
||||
<property name="vexpand">False</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">end</property>
|
||||
<property name="visible">True</property>
|
||||
<style>
|
||||
<class name="circular"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="icon-name">go-down-symbolic</property>
|
||||
<property name="icon-size">1</property>
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">content</property>
|
||||
|
|
|
@ -23,6 +23,8 @@ public class ChatInputController : Object {
|
|||
this.status_description_label = chat_input.chat_input_status;
|
||||
this.stream_interactor = stream_interactor;
|
||||
|
||||
chat_input.init(stream_interactor);
|
||||
|
||||
reset_input_field_status();
|
||||
|
||||
chat_input.text_input.buffer.changed.connect(on_text_input_changed);
|
||||
|
@ -40,6 +42,7 @@ public class ChatInputController : Object {
|
|||
|
||||
reset_input_field_status();
|
||||
|
||||
chat_input.initialize_for_conversation(conversation);
|
||||
chat_input.occupants_tab_completor.initialize_for_conversation(conversation);
|
||||
chat_input.edit_history.initialize_for_conversation(conversation);
|
||||
chat_input.encryption_widget.set_conversation(conversation);
|
||||
|
|
|
@ -56,7 +56,6 @@ public class ConversationSelector : ListBox {
|
|||
if (!rows.has_key(conversation)) {
|
||||
add_conversation(conversation);
|
||||
}
|
||||
rows[conversation].grab_focus();
|
||||
this.select_row(rows[conversation]);
|
||||
}
|
||||
|
||||
|
@ -86,8 +85,8 @@ public class ConversationSelector : ListBox {
|
|||
if (this.drag_timeout != null)
|
||||
return false;
|
||||
this.drag_timeout = Timeout.add(200, () => {
|
||||
if (widget.get_type().is_a(typeof(ConversationRow))) {
|
||||
ConversationRow row = widget as ConversationRow;
|
||||
if (widget.get_type().is_a(typeof(ConversationSelectorRow))) {
|
||||
ConversationSelectorRow row = widget as ConversationSelectorRow;
|
||||
conversation_selected(row.conversation);
|
||||
}
|
||||
this.drag_timeout = null;
|
||||
|
|
|
@ -4,15 +4,6 @@ using Pango;
|
|||
|
||||
using Dino.Entities;
|
||||
|
||||
enum Target {
|
||||
URI_LIST,
|
||||
STRING
|
||||
}
|
||||
|
||||
const TargetEntry[] target_list = {
|
||||
{ "text/uri-list", 0, Target.URI_LIST },
|
||||
};
|
||||
|
||||
namespace Dino.Ui.ConversationSummary {
|
||||
|
||||
[GtkTemplate (ui = "/im/dino/Dino/conversation_summary/view.ui")]
|
||||
|
@ -67,9 +58,12 @@ public class ConversationView : Box, Plugins.ConversationItemCollection, Plugins
|
|||
return true;
|
||||
});
|
||||
|
||||
drag_dest_unset(main);
|
||||
drag_dest_set(scrolled, DestDefaults.ALL, target_list, Gdk.DragAction.COPY);
|
||||
scrolled.drag_data_received.connect(this.on_drag_data_received);
|
||||
const TargetEntry[] target_list = {
|
||||
{ "text/uri-list", 0, Target.URI_LIST }
|
||||
};
|
||||
// drag_dest_unset(main);
|
||||
// drag_dest_set(scrolled, DestDefaults.ALL, target_list, Gdk.DragAction.COPY);
|
||||
// scrolled.drag_data_received.connect(() => print("a\n"));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -185,28 +179,6 @@ public class ConversationView : Box, Plugins.ConversationItemCollection, Plugins
|
|||
do_insert_item(item);
|
||||
}
|
||||
|
||||
public void on_drag_data_received(Widget widget, Gdk.DragContext context,
|
||||
int x, int y,
|
||||
SelectionData selection_data,
|
||||
uint target_type, uint time) {
|
||||
if ((selection_data != null) && (selection_data.get_length() >= 0)) {
|
||||
switch (target_type) {
|
||||
case Target.URI_LIST:
|
||||
string[] uris = selection_data.get_uris();
|
||||
for (int i = 0; i < uris.length; i++) {
|
||||
try {
|
||||
string filename = Filename.from_uri(uris[i]);
|
||||
stream_interactor.get_module(FileManager.IDENTITY).send_file(filename, conversation);
|
||||
} catch (Error err) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void do_insert_item(Plugins.MetaConversationItem item) {
|
||||
lock (meta_items) {
|
||||
insert_new(item);
|
||||
|
|
19
main/src/ui/conversation_view.vala
Normal file
19
main/src/ui/conversation_view.vala
Normal file
|
@ -0,0 +1,19 @@
|
|||
using Gee;
|
||||
using Gdk;
|
||||
using Gtk;
|
||||
|
||||
using Dino.Entities;
|
||||
|
||||
namespace Dino.Ui {
|
||||
|
||||
[GtkTemplate (ui = "/im/dino/Dino/conversation_view.ui")]
|
||||
public class ConversationView : Gtk.Box {
|
||||
|
||||
[GtkChild] public Revealer goto_end_revealer;
|
||||
[GtkChild] public Button goto_end_button;
|
||||
[GtkChild] public ChatInput.View chat_input;
|
||||
[GtkChild] public ConversationSummary.ConversationView conversation_frame;
|
||||
|
||||
}
|
||||
|
||||
}
|
96
main/src/ui/conversation_view_controller.vala
Normal file
96
main/src/ui/conversation_view_controller.vala
Normal file
|
@ -0,0 +1,96 @@
|
|||
using Gee;
|
||||
using Gdk;
|
||||
using Gtk;
|
||||
|
||||
using Dino.Entities;
|
||||
|
||||
namespace Dino.Ui {
|
||||
|
||||
enum Target {
|
||||
URI_LIST,
|
||||
STRING
|
||||
}
|
||||
|
||||
const TargetEntry[] target_list = {
|
||||
{ "text/uri-list", 0, Target.URI_LIST }
|
||||
};
|
||||
|
||||
public class ConversationViewController {
|
||||
|
||||
private ConversationView widget;
|
||||
|
||||
private ChatInputController chat_input_controller;
|
||||
private StreamInteractor stream_interactor;
|
||||
private Conversation? conversation;
|
||||
|
||||
public ConversationViewController(ConversationView widget, StreamInteractor stream_interactor) {
|
||||
this.widget = widget;
|
||||
this.stream_interactor = stream_interactor;
|
||||
|
||||
this.chat_input_controller = new ChatInputController(widget.chat_input, stream_interactor);
|
||||
|
||||
widget.conversation_frame.init(stream_interactor);
|
||||
|
||||
// drag 'n drop file upload
|
||||
Gtk.drag_dest_unset(widget.chat_input.text_input);
|
||||
Gtk.drag_dest_set(widget, DestDefaults.ALL, target_list, Gdk.DragAction.COPY);
|
||||
widget.drag_data_received.connect(this.on_drag_data_received);
|
||||
|
||||
// forward key presses
|
||||
widget.chat_input.key_press_event.connect(forward_key_press_to_chat_input);
|
||||
widget.conversation_frame.key_press_event.connect(forward_key_press_to_chat_input);
|
||||
|
||||
// goto-end floating button
|
||||
var vadjustment = widget.conversation_frame.scrolled.vadjustment;
|
||||
vadjustment.notify["value"].connect(() => {
|
||||
widget.goto_end_revealer.reveal_child = vadjustment.value < vadjustment.upper - vadjustment.page_size;
|
||||
});
|
||||
widget.goto_end_button.clicked.connect(() => {
|
||||
widget.conversation_frame.initialize_for_conversation(conversation);
|
||||
});
|
||||
}
|
||||
|
||||
public void select_conversation(Conversation? conversation, bool default_initialize_conversation) {
|
||||
this.conversation = conversation;
|
||||
|
||||
chat_input_controller.set_conversation(conversation);
|
||||
|
||||
if (default_initialize_conversation) {
|
||||
widget.conversation_frame.initialize_for_conversation(conversation);
|
||||
}
|
||||
}
|
||||
|
||||
public void on_drag_data_received(Widget widget, Gdk.DragContext context, int x, int y, SelectionData selection_data, uint target_type, uint time) {
|
||||
if ((selection_data != null) && (selection_data.get_length() >= 0)) {
|
||||
switch (target_type) {
|
||||
case Target.URI_LIST:
|
||||
string[] uris = selection_data.get_uris();
|
||||
for (int i = 0; i < uris.length; i++) {
|
||||
try {
|
||||
string filename = Filename.from_uri(uris[i]);
|
||||
stream_interactor.get_module(FileManager.IDENTITY).send_file.begin(filename, conversation);
|
||||
} catch (Error err) {}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool forward_key_press_to_chat_input(EventKey event) {
|
||||
// Don't forward / change focus on Control / Alt
|
||||
if (event.keyval == Gdk.Key.Control_L || event.keyval == Gdk.Key.Control_R ||
|
||||
event.keyval == Gdk.Key.Alt_L || event.keyval == Gdk.Key.Alt_R) {
|
||||
return false;
|
||||
}
|
||||
// Don't forward / change focus on Control + ...
|
||||
if ((event.state & ModifierType.CONTROL_MASK) > 0) {
|
||||
return false;
|
||||
}
|
||||
widget.chat_input.text_input.key_press_event(event);
|
||||
widget.chat_input.text_input.grab_focus();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,9 +16,8 @@ public class UnifiedWindow : Gtk.Window {
|
|||
public WelcomePlceholder welcome_placeholder = new WelcomePlceholder() { visible=true };
|
||||
public NoAccountsPlaceholder accounts_placeholder = new NoAccountsPlaceholder() { visible=true };
|
||||
public NoConversationsPlaceholder conversations_placeholder = new NoConversationsPlaceholder() { visible=true };
|
||||
public ChatInput.View chat_input;
|
||||
public ConversationView conversation_view;
|
||||
public ConversationSelector conversation_selector;
|
||||
public ConversationSummary.ConversationView conversation_frame;
|
||||
public ConversationTitlebar conversation_titlebar;
|
||||
public ConversationTitlebarCsd conversation_titlebar_csd;
|
||||
public ConversationListTitlebarCsd conversation_list_titlebar_csd;
|
||||
|
@ -26,8 +25,6 @@ public class UnifiedWindow : Gtk.Window {
|
|||
public Box box = new Box(Orientation.VERTICAL, 0) { orientation=Orientation.VERTICAL, visible=true };
|
||||
public Paned headerbar_paned = new Paned(Orientation.HORIZONTAL) { visible=true };
|
||||
public Paned paned;
|
||||
public Revealer goto_end_revealer;
|
||||
public Button goto_end_button;
|
||||
public Revealer search_revealer;
|
||||
public SearchEntry search_entry;
|
||||
public GlobalSearch search_box;
|
||||
|
@ -72,13 +69,8 @@ public class UnifiedWindow : Gtk.Window {
|
|||
box.add(paned);
|
||||
left_stack = (Stack) builder.get_object("left_stack");
|
||||
right_stack = (Stack) builder.get_object("right_stack");
|
||||
chat_input = ((ChatInput.View) builder.get_object("chat_input")).init(stream_interactor);
|
||||
chat_input.key_press_event.connect(forward_key_press_to_chat_input);
|
||||
conversation_frame = ((ConversationSummary.ConversationView) builder.get_object("conversation_frame")).init(stream_interactor);
|
||||
conversation_frame.key_press_event.connect(forward_key_press_to_chat_input);
|
||||
conversation_view = (ConversationView) builder.get_object("conversation_view");
|
||||
conversation_selector = ((ConversationSelector) builder.get_object("conversation_list")).init(stream_interactor);
|
||||
goto_end_revealer = (Revealer) builder.get_object("goto_end_revealer");
|
||||
goto_end_button = (Button) builder.get_object("goto_end_button");
|
||||
search_box = ((GlobalSearch) builder.get_object("search_box")).init(stream_interactor);
|
||||
search_revealer = (Revealer) builder.get_object("search_revealer");
|
||||
search_entry = (SearchEntry) builder.get_object("search_entry");
|
||||
|
@ -103,7 +95,7 @@ public class UnifiedWindow : Gtk.Window {
|
|||
|
||||
box.add(headerbar_paned);
|
||||
}
|
||||
headerbar_paned.key_press_event.connect(forward_key_press_to_chat_input);
|
||||
// headerbar_paned.key_press_event.connect(forward_key_press_to_chat_input); TODO
|
||||
}
|
||||
|
||||
private void set_window_buttons() {
|
||||
|
@ -153,21 +145,6 @@ public class UnifiedWindow : Gtk.Window {
|
|||
}
|
||||
}
|
||||
|
||||
private bool forward_key_press_to_chat_input(EventKey event) {
|
||||
// Don't forward / change focus on Control / Alt
|
||||
if (event.keyval == Gdk.Key.Control_L || event.keyval == Gdk.Key.Control_R ||
|
||||
event.keyval == Gdk.Key.Alt_L || event.keyval == Gdk.Key.Alt_R) {
|
||||
return false;
|
||||
}
|
||||
// Don't forward / change focus on Control + ...
|
||||
if ((event.state & ModifierType.CONTROL_MASK) > 0) {
|
||||
return false;
|
||||
}
|
||||
chat_input.text_input.key_press_event(event);
|
||||
chat_input.text_input.grab_focus();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void loop_conversations(bool backwards) {
|
||||
conversation_selector.loop_conversations(backwards);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ public class UnifiedWindowController : Object {
|
|||
|
||||
private SearchMenuEntry search_menu_entry = new SearchMenuEntry();
|
||||
|
||||
private ChatInputController chat_input_controller;
|
||||
private ConversationViewController conversation_view_controller;
|
||||
|
||||
public UnifiedWindowController(Application application, StreamInteractor stream_interactor, Database db) {
|
||||
this.app = application;
|
||||
|
@ -54,18 +54,15 @@ public class UnifiedWindowController : Object {
|
|||
public void set_window(UnifiedWindow window) {
|
||||
this.window = window;
|
||||
|
||||
this.chat_input_controller = new ChatInputController(window.chat_input, stream_interactor);
|
||||
this.conversation_view_controller = new ConversationViewController(window.conversation_view, stream_interactor);
|
||||
|
||||
this.bind_property("conversation-display-name", window, "title");
|
||||
this.bind_property("conversation-topic", window, "subtitle");
|
||||
search_menu_entry.search_button.bind_property("active", window.search_revealer, "reveal_child");
|
||||
|
||||
window.goto_end_button.clicked.connect(() => {
|
||||
window.conversation_frame.initialize_for_conversation(conversation);
|
||||
});
|
||||
window.search_revealer.notify["child-revealed"].connect(() => {
|
||||
if (window.search_revealer.child_revealed) {
|
||||
if (window.conversation_frame.conversation != null && window.search_box.search_entry.text == "") {
|
||||
if (window.conversation_view.conversation_frame.conversation != null && window.search_box.search_entry.text == "") {
|
||||
reset_search_entry();
|
||||
}
|
||||
window.search_box.search_entry.grab_focus_without_selecting();
|
||||
|
@ -74,7 +71,7 @@ public class UnifiedWindowController : Object {
|
|||
});
|
||||
window.search_box.selected_item.connect((item) => {
|
||||
select_conversation(item.conversation, false, false);
|
||||
window.conversation_frame.initialize_around_message(item.conversation, item);
|
||||
window.conversation_view.conversation_frame.initialize_around_message(item.conversation, item);
|
||||
close_search();
|
||||
});
|
||||
|
||||
|
@ -88,10 +85,6 @@ public class UnifiedWindowController : Object {
|
|||
window.conversations_placeholder.secondary_button.clicked.connect(() => { app.activate_action("add_conference", null); });
|
||||
window.conversation_selector.conversation_selected.connect((conversation) => select_conversation(conversation));
|
||||
|
||||
var vadjustment = window.conversation_frame.scrolled.vadjustment;
|
||||
vadjustment.notify["value"].connect(() => {
|
||||
window.goto_end_revealer.reveal_child = vadjustment.value < vadjustment.upper - vadjustment.page_size;
|
||||
});
|
||||
window.event.connect((event) => {
|
||||
if (event.type == EventType.BUTTON_PRESS) {
|
||||
int dest_x, dest_y;
|
||||
|
@ -124,6 +117,8 @@ public class UnifiedWindowController : Object {
|
|||
public void select_conversation(Conversation? conversation, bool do_reset_search = true, bool default_initialize_conversation = true) {
|
||||
this.conversation = conversation;
|
||||
|
||||
conversation_view_controller.select_conversation(conversation, default_initialize_conversation);
|
||||
|
||||
update_conversation_display_name();
|
||||
update_conversation_topic();
|
||||
|
||||
|
@ -141,11 +136,6 @@ public class UnifiedWindowController : Object {
|
|||
if (do_reset_search) {
|
||||
reset_search_entry();
|
||||
}
|
||||
chat_input_controller.set_conversation(conversation);
|
||||
window.chat_input.initialize_for_conversation(conversation);
|
||||
if (default_initialize_conversation) {
|
||||
window.conversation_frame.initialize_for_conversation(conversation);
|
||||
}
|
||||
}
|
||||
|
||||
private void check_unset_conversation() {
|
||||
|
@ -188,7 +178,7 @@ public class UnifiedWindowController : Object {
|
|||
}
|
||||
|
||||
private void reset_search_entry() {
|
||||
if (window.conversation_frame.conversation != null) {
|
||||
if (window.conversation_view.conversation_frame.conversation != null) {
|
||||
switch (conversation.type_) {
|
||||
case Conversation.Type.CHAT:
|
||||
case Conversation.Type.GROUPCHAT_PM:
|
||||
|
|
Loading…
Reference in a new issue