From f44cbe02c17df1f02ad49c63cd784fec0ea02d85 Mon Sep 17 00:00:00 2001 From: fiaxh Date: Sat, 14 May 2022 14:45:59 +0200 Subject: Improve Gtk4 port --- .../ui/add_conversation/add_conference_dialog.vala | 53 +++-- .../ui/add_conversation/add_groupchat_dialog.vala | 2 +- main/src/ui/add_conversation/conference_list.vala | 17 +- main/src/ui/add_conversation/list_row.vala | 6 +- main/src/ui/add_conversation/roster_list.vala | 10 - .../ui/add_conversation/select_contact_dialog.vala | 4 +- .../ui/add_conversation/select_jid_fragment.vala | 18 +- main/src/ui/application.vala | 13 +- main/src/ui/avatar_image.vala | 3 +- .../src/ui/call_window/audio_settings_popover.vala | 44 ++-- main/src/ui/call_window/call_bottom_bar.vala | 57 ++--- .../call_connection_details_window.vala | 30 +-- .../src/ui/call_window/call_encryption_button.vala | 28 +-- main/src/ui/call_window/call_window.vala | 27 +-- .../src/ui/call_window/call_window_controller.vala | 9 +- main/src/ui/call_window/participant_widget.vala | 31 +-- .../src/ui/call_window/video_settings_popover.vala | 24 +- main/src/ui/chat_input/chat_text_view.vala | 26 +-- main/src/ui/chat_input/encryption_button.vala | 54 +++-- main/src/ui/chat_input/view.vala | 20 +- main/src/ui/contact_details/blocking_provider.vala | 2 +- main/src/ui/contact_details/dialog.vala | 50 +++-- .../ui/contact_details/permissions_provider.vala | 2 +- main/src/ui/contact_details/settings_provider.vala | 4 +- .../conversation_item_factory.vala | 36 --- .../ui/conversation_content_view/call_widget.vala | 16 +- .../chat_state_populator.vala | 8 +- .../conversation_item_skeleton.vala | 40 ++-- .../conversation_view.vala | 9 +- .../date_separator_populator.vala | 8 +- .../file_default_widget.vala | 4 +- .../file_image_widget.vala | 4 +- .../ui/conversation_content_view/file_widget.vala | 12 +- .../message_item_widget.vala | 229 ------------------- .../conversation_content_view/message_widget.vala | 2 +- .../subscription_notification.vala | 8 +- .../conversation_list_item_factory.vala | 245 --------------------- .../conversation_list/conversation_list_model.vala | 141 ------------ .../conversation_list/conversation_list_row.vala | 41 ---- .../conversation_selector.vala | 50 ++--- .../conversation_selector_row.vala | 14 +- main/src/ui/conversation_titlebar/call_entry.vala | 1 - .../conversation_titlebar.vala | 14 +- main/src/ui/conversation_view.vala | 4 +- main/src/ui/conversation_view_controller.vala | 149 ++++++------- main/src/ui/file_send_overlay.vala | 31 +-- main/src/ui/global_search.vala | 24 +- main/src/ui/main_window.vala | 4 +- main/src/ui/main_window_controller.vala | 7 - .../src/ui/manage_accounts/add_account_dialog.vala | 44 ++-- main/src/ui/manage_accounts/dialog.vala | 33 +-- main/src/ui/occupant_menu/list.vala | 10 +- main/src/ui/occupant_menu/view.vala | 27 +-- main/src/ui/util/data_forms.vala | 8 +- main/src/ui/util/label_hybrid.vala | 23 +- main/src/ui/util/scaling_image.vala | 14 -- main/src/ui/util/sizing_bin.vala | 5 + 57 files changed, 541 insertions(+), 1258 deletions(-) delete mode 100644 main/src/ui/conversation_content/conversation_item_factory.vala delete mode 100644 main/src/ui/conversation_content_view/message_item_widget.vala delete mode 100644 main/src/ui/conversation_list/conversation_list_item_factory.vala delete mode 100644 main/src/ui/conversation_list/conversation_list_model.vala delete mode 100644 main/src/ui/conversation_list/conversation_list_row.vala (limited to 'main/src/ui') diff --git a/main/src/ui/add_conversation/add_conference_dialog.vala b/main/src/ui/add_conversation/add_conference_dialog.vala index e078bc62..4b7364c7 100644 --- a/main/src/ui/add_conversation/add_conference_dialog.vala +++ b/main/src/ui/add_conversation/add_conference_dialog.vala @@ -10,7 +10,7 @@ namespace Dino.Ui { public class AddConferenceDialog : Gtk.Dialog { private Stack stack = new Stack(); - private Button cancel_button = new Button() { visible=true }; + private Button cancel_button = new Button(); private Button ok_button; private SelectJidFragment select_fragment; @@ -70,12 +70,12 @@ public class AddConferenceDialog : Gtk.Dialog { stack.transition_type = StackTransitionType.SLIDE_LEFT; stack.set_visible_child_name("details"); -// animate_window_resize(); + animate_window_resize(details_fragment); } private void setup_headerbar() { - ok_button = new Button() { can_focus=true, visible=true }; - ok_button.get_style_context().add_class("suggested-action"); + ok_button = new Button() { can_focus=true }; + ok_button.add_css_class("suggested-action"); if (Util.use_csd()) { HeaderBar header_bar = get_header_bar() as HeaderBar; @@ -104,18 +104,18 @@ public class AddConferenceDialog : Gtk.Dialog { stream_interactor.get_module(MucManager.IDENTITY).remove_bookmark(conference_row.account, conference_row.bookmark); }); - Box wrap_box = new Box(Orientation.VERTICAL, 0) { visible=true }; + Box wrap_box = new Box(Orientation.VERTICAL, 0); wrap_box.append(select_fragment); stack.add_named(wrap_box, "select"); if (!Util.use_csd()) { - Box box = new Box(Orientation.HORIZONTAL, 5) { halign=Align.END, margin_bottom=15, margin_start=80, margin_end=80, visible=true }; + Box box = new Box(Orientation.HORIZONTAL, 5) { halign=Align.END, margin_bottom=15, margin_start=80, margin_end=80 }; - Button ok_button = new Button.with_label(_("Next")) { sensitive=false, halign = Align.END, can_focus=true, visible=true }; - ok_button.get_style_context().add_class("suggested-action"); + Button ok_button = new Button.with_label(_("Next")) { sensitive=false, halign = Align.END, can_focus=true }; + ok_button.add_css_class("suggested-action"); ok_button.clicked.connect(on_next_button_clicked); select_fragment.notify["done"].connect(() => { ok_button.sensitive = select_fragment.done; }); - Button cancel_button = new Button.with_label(_("Cancel")) { halign=Align.START, visible=true }; + Button cancel_button = new Button.with_label(_("Cancel")) { halign=Align.START }; cancel_button.clicked.connect(on_cancel); box.append(cancel_button); box.append(ok_button); @@ -129,18 +129,18 @@ public class AddConferenceDialog : Gtk.Dialog { details_fragment = new ConferenceDetailsFragment(stream_interactor) { ok_button=ok_button }; details_fragment.joined.connect(() => this.close()); - Box wrap_box = new Box(Orientation.VERTICAL, 0) { visible=true }; + Box wrap_box = new Box(Orientation.VERTICAL, 0); wrap_box.append(details_fragment); if (!Util.use_csd()) { - Box box = new Box(Orientation.HORIZONTAL, 5) { halign=Align.END, margin_bottom=15, margin_start=80, margin_end=80, visible=true }; + Box box = new Box(Orientation.HORIZONTAL, 5) { halign=Align.END, margin_bottom=15, margin_start=80, margin_end=80 }; - Button ok_button = new Button.with_label(_("Join")) { halign = Align.END, can_focus=true, visible=true }; - ok_button.get_style_context().add_class("suggested-action"); + Button ok_button = new Button.with_label(_("Join")) { halign = Align.END, can_focus=true }; + ok_button.add_css_class("suggested-action"); details_fragment.notify["done"].connect(() => { ok_button.sensitive = select_fragment.done; }); details_fragment.ok_button = ok_button; - Button cancel_button = new Button.with_label(_("Back")) { halign=Align.START, visible=true }; + Button cancel_button = new Button.with_label(_("Back")) { halign=Align.START }; cancel_button.clicked.connect(show_jid_add_view); box.append(cancel_button); box.append(ok_button); @@ -180,23 +180,20 @@ public class AddConferenceDialog : Gtk.Dialog { close(); } - private void animate_window_resize() { + private void animate_window_resize(Widget widget) { int curr_height = get_size(Orientation.VERTICAL); - int curr_width = get_size(Orientation.HORIZONTAL); - var natural_size = new Requisition(); - stack.get_preferred_size(null, out natural_size); + var natural_size = Requisition(); + widget.get_preferred_size(null, out natural_size); int difference = natural_size.height - curr_height; Timer timer = new Timer(); - Timeout.add((int) (stack.transition_duration / 30), - () => { - ulong microsec; - timer.elapsed(out microsec); - ulong millisec = microsec / 1000; - double partial = double.min(1, (double) millisec / stack.transition_duration); - var a = this.list_toplevels().nth_data(0); - set_size_request(curr_width, (int) (curr_height + difference * partial)); - return millisec < stack.transition_duration; - }); + Timeout.add((int) (stack.transition_duration / 30), () => { + ulong microsec; + timer.elapsed(out microsec); + ulong millisec = microsec / 1000; + double partial = double.min(1, (double) millisec / stack.transition_duration); + default_height = (int) (curr_height + difference * partial); + return millisec < stack.transition_duration; + }); } } diff --git a/main/src/ui/add_conversation/add_groupchat_dialog.vala b/main/src/ui/add_conversation/add_groupchat_dialog.vala index 786c1a0b..a94b8c86 100644 --- a/main/src/ui/add_conversation/add_groupchat_dialog.vala +++ b/main/src/ui/add_conversation/add_groupchat_dialog.vala @@ -24,7 +24,7 @@ protected class AddGroupchatDialog : Gtk.Dialog { Object(use_header_bar : 1); this.stream_interactor = stream_interactor; ok_button.label = _("Add"); - ok_button.get_style_context().add_class("suggested-action"); // TODO why doesn't it work in XML + ok_button.add_css_class("suggested-action"); // TODO why doesn't it work in XML accounts_stack.set_visible_child_name("combobox"); account_combobox.initialize(stream_interactor); diff --git a/main/src/ui/add_conversation/conference_list.vala b/main/src/ui/add_conversation/conference_list.vala index a19630e4..181c6219 100644 --- a/main/src/ui/add_conversation/conference_list.vala +++ b/main/src/ui/add_conversation/conference_list.vala @@ -20,10 +20,6 @@ protected class ConferenceList { public ConferenceList(StreamInteractor stream_interactor) { this.stream_interactor = stream_interactor; -// list_box.set_filter_func(filter); - list_box.set_header_func(header); -// list_box.set_sort_func(sort); - stream_interactor.get_module(MucManager.IDENTITY).bookmarks_updated.connect((account, conferences) => { lists[account] = conferences; refresh_conferences(); @@ -57,7 +53,12 @@ protected class ConferenceList { } public void refresh_conferences() { -// @foreach((widget) => { remove(widget); }); + foreach (Account account in widgets.keys) { + foreach (Jid jid in widgets[account].keys) { + remove_conference(account, jid); + } + } + foreach (Account account in lists.keys) { foreach (Conference conference in lists[account]) { add_conference(account, conference); @@ -74,12 +75,6 @@ protected class ConferenceList { refresh_conferences(); } - private void header(ListBoxRow row, ListBoxRow? before_row) { - if (row.get_header() == null && before_row != null) { - row.set_header(new Separator(Orientation.HORIZONTAL)); - } - } - public ListBox get_list_box() { return list_box; } diff --git a/main/src/ui/add_conversation/list_row.vala b/main/src/ui/add_conversation/list_row.vala index 326dba98..a25ecbd3 100644 --- a/main/src/ui/add_conversation/list_row.vala +++ b/main/src/ui/add_conversation/list_row.vala @@ -24,7 +24,7 @@ public class ListRow : Widget { via_label = (Label) builder.get_object("via_label"); this.layout_manager = new BinLayout(); - outer_grid.insert_after(this, null); + outer_grid.set_parent(this); } public ListRow() {} @@ -47,6 +47,10 @@ public class ListRow : Widget { name_label.label = display_name; image.set_conversation(stream_interactor, conv); } + + public override void dispose() { + outer_grid.unparent(); + } } } diff --git a/main/src/ui/add_conversation/roster_list.vala b/main/src/ui/add_conversation/roster_list.vala index a89d24e8..25827d67 100644 --- a/main/src/ui/add_conversation/roster_list.vala +++ b/main/src/ui/add_conversation/roster_list.vala @@ -20,10 +20,6 @@ protected class RosterList { this.stream_interactor = stream_interactor; this.accounts = accounts; -// set_filter_func(filter); - list_box.set_header_func(header); -// set_sort_func(sort); - handler_ids += stream_interactor.get_module(RosterManager.IDENTITY).removed_roster_item.connect( (account, jid, roster_item) => { if (accounts.contains(account)) { on_removed_roster_item(account, jid, roster_item); @@ -64,12 +60,6 @@ protected class RosterList { } } - private void header(ListBoxRow row, ListBoxRow? before_row) { - if (row.get_header() == null && before_row != null) { - row.set_header(new Separator(Orientation.HORIZONTAL)); - } - } - public ListBox get_list_box() { return list_box; } diff --git a/main/src/ui/add_conversation/select_contact_dialog.vala b/main/src/ui/add_conversation/select_contact_dialog.vala index 4bf5b193..09ac1636 100644 --- a/main/src/ui/add_conversation/select_contact_dialog.vala +++ b/main/src/ui/add_conversation/select_contact_dialog.vala @@ -40,7 +40,7 @@ public class SelectContactDialog : Gtk.Dialog { cancel_button.visible = true; ok_button = new Button(); - ok_button.get_style_context().add_class("suggested-action"); + ok_button.add_css_class("suggested-action"); ok_button.sensitive = false; ok_button.visible = true; @@ -51,7 +51,7 @@ public class SelectContactDialog : Gtk.Dialog { header_bar.pack_start(cancel_button); header_bar.pack_end(ok_button); } else { - Box box = new Box(Orientation.HORIZONTAL, 5) { halign=Align.END, margin_bottom=15, margin_start=80, margin_end=80, visible=true }; + Box box = new Box(Orientation.HORIZONTAL, 5) { halign=Align.END, margin_bottom=15, margin_start=80, margin_end=80 }; cancel_button.halign = Align.START; ok_button.halign = Align.END; diff --git a/main/src/ui/add_conversation/select_jid_fragment.vala b/main/src/ui/add_conversation/select_jid_fragment.vala index 58f019c1..a6cf0864 100644 --- a/main/src/ui/add_conversation/select_jid_fragment.vala +++ b/main/src/ui/add_conversation/select_jid_fragment.vala @@ -23,7 +23,7 @@ public class SelectJidFragment : Gtk.Box { private StreamInteractor stream_interactor; private Gee.List accounts; - private ArrayList added_rows = new ArrayList(); + private ArrayList added_rows = new ArrayList(); private ListBox list; private string[]? filter_values; @@ -39,6 +39,7 @@ public class SelectJidFragment : Gtk.Box { list.set_sort_func(sort); list.set_filter_func(filter); + list.set_header_func(header); list.row_selected.connect(check_buttons_active); list.row_selected.connect(() => { done = true; }); // just for notifying entry.changed.connect(() => { set_filter(entry.text); }); @@ -49,7 +50,7 @@ public class SelectJidFragment : Gtk.Box { public void set_filter(string str) { if (entry.text != str) entry.text = str; - foreach (AddListRow row in added_rows) list.remove(row); + foreach (Widget row in added_rows) list.remove(row); added_rows.clear(); filter_values = str == "" ? null : str.split(" "); @@ -59,9 +60,10 @@ public class SelectJidFragment : Gtk.Box { Jid parsed_jid = new Jid(str); if (parsed_jid != null && parsed_jid.localpart != null) { foreach (Account account in accounts) { - AddListRow row = new AddListRow(stream_interactor, parsed_jid, account); - list.append(row); - added_rows.add(row); + var list_row = new Gtk.ListBoxRow(); + list_row.set_child(new AddListRow(stream_interactor, parsed_jid, account)); + list.append(list_row); + added_rows.add(list_row); } } } catch (InvalidJidError ignored) { @@ -108,6 +110,12 @@ public class SelectJidFragment : Gtk.Box { return true; } + private void header(ListBoxRow row, ListBoxRow? before_row) { + if (row.get_header() == null && before_row != null) { + row.set_header(new Separator(Orientation.HORIZONTAL)); + } + } + private class AddListRow : ListRow { public AddListRow(StreamInteractor stream_interactor, Jid jid, Account account) { diff --git a/main/src/ui/application.vala b/main/src/ui/application.vala index f83e403b..2167145b 100644 --- a/main/src/ui/application.vala +++ b/main/src/ui/application.vala @@ -203,11 +203,6 @@ public class Dino.Ui.Application : Gtk.Application, Dino.Application { Builder builder = new Builder.from_resource("/im/dino/Dino/shortcuts.ui"); ShortcutsWindow dialog = (ShortcutsWindow) builder.get_object("shortcuts-window"); if (!use_csd()) { - // Hack to prevent CRITICAL in Gtk when trying to destroy non-existant headerbar - Widget shortcuts_hack = dialog.get_titlebar(); -// dialog.destroy.connect_after(() => { -// shortcuts_hack = null; -// }); dialog.set_titlebar(null); } dialog.title = _("Keyboard Shortcuts"); @@ -292,12 +287,6 @@ public class Dino.Ui.Application : Gtk.Application, Dino.Application { dialog.copyright = "Copyright © 2016-2022 - Dino Team"; dialog.license_type = License.GPL_3_0; -// dialog.response.connect((response_id) => { -// if (response_id == Gtk.ResponseType.CANCEL || response_id == Gtk.ResponseType.DELETE_EVENT) { -// dialog.destroy(); -// } -// }); - if (!use_csd()) { dialog.set_titlebar(null); } @@ -308,7 +297,7 @@ public class Dino.Ui.Application : Gtk.Application, Dino.Application { Dialog dialog = new Dialog.with_buttons(_("Join Channel"), window, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.USE_HEADER_BAR, _("Join"), ResponseType.OK, _("Cancel"), ResponseType.CANCEL); dialog.modal = true; Button ok_button = dialog.get_widget_for_response(ResponseType.OK) as Button; - ok_button.get_style_context().add_class("suggested-action"); + ok_button.add_css_class("suggested-action"); ConferenceDetailsFragment conference_fragment = new ConferenceDetailsFragment(stream_interactor) { ok_button=ok_button }; conference_fragment.jid = jid; if (account != null) { diff --git a/main/src/ui/avatar_image.vala b/main/src/ui/avatar_image.vala index a304f5a2..f348dd4b 100644 --- a/main/src/ui/avatar_image.vala +++ b/main/src/ui/avatar_image.vala @@ -24,7 +24,7 @@ public class AvatarImage : Widget { public AvatarImage() { can_focus = false; - get_style_context().add_class("avatar"); + add_css_class("avatar"); } public override void dispose() { @@ -51,7 +51,6 @@ public class AvatarImage : Widget { } public bool draw(Cairo.Context ctx_in) { - if (conversation == null || jids == null) return false; Cairo.Context ctx = ctx_in; int width = this.width, height = this.height, base_factor = 1; if (use_image_surface == -1) { diff --git a/main/src/ui/call_window/audio_settings_popover.vala b/main/src/ui/call_window/audio_settings_popover.vala index f5af90ff..f66c5eee 100644 --- a/main/src/ui/call_window/audio_settings_popover.vala +++ b/main/src/ui/call_window/audio_settings_popover.vala @@ -14,7 +14,7 @@ public class Dino.Ui.AudioSettingsPopover : Gtk.Popover { private HashMap row_speaker_device = new HashMap(); public AudioSettingsPopover() { - Box box = new Box(Orientation.VERTICAL, 15) { visible=true }; + Box box = new Box(Orientation.VERTICAL, 15); box.append(create_microphone_box()); box.append(create_speaker_box()); @@ -25,19 +25,19 @@ public class Dino.Ui.AudioSettingsPopover : Gtk.Popover { Plugins.VideoCallPlugin call_plugin = Dino.Application.get_default().plugin_registry.video_call_plugin; Gee.List devices = call_plugin.get_devices("audio", false); - Box micro_box = new Box(Orientation.VERTICAL, 10) { visible=true }; - micro_box.append(new Label("" + _("Microphones") + "") { use_markup=true, xalign=0, visible=true, can_focus=true /* grab initial focus*/ }); + Box micro_box = new Box(Orientation.VERTICAL, 10); + micro_box.append(new Label("" + _("Microphones") + "") { use_markup=true, xalign=0, can_focus=true /* grab initial focus*/ }); if (devices.size == 0) { micro_box.append(new Label(_("No microphone found."))); } else { - ListBox micro_list_box = new ListBox() { activate_on_single_click=true, selection_mode=SelectionMode.SINGLE, visible=true }; + ListBox micro_list_box = new ListBox() { activate_on_single_click=true, selection_mode=SelectionMode.SINGLE }; micro_list_box.set_header_func(listbox_header_func); - Frame micro_frame = new Frame(null) { visible=true }; + Frame micro_frame = new Frame(null); micro_frame.set_child(micro_list_box); foreach (Plugins.MediaDevice device in devices) { - Label display_name_label = new Label(device.display_name) { xalign=0, visible=true }; - Image image = new Image.from_icon_name("object-select-symbolic") { visible=true }; + Label display_name_label = new Label(device.display_name) { xalign=0 }; + Image image = new Image.from_icon_name("object-select-symbolic"); if (current_microphone_device == null || current_microphone_device.id != device.id) { image.opacity = 0; } @@ -48,19 +48,19 @@ public class Dino.Ui.AudioSettingsPopover : Gtk.Popover { image.opacity = 1; } }); - Box device_box = new Box(Orientation.HORIZONTAL, 0) { spacing=7, visible=true }; + Box device_box = new Box(Orientation.HORIZONTAL, 0) { spacing=7 }; device_box.append(image); - Box label_box = new Box(Orientation.VERTICAL, 0) { visible = true }; + Box label_box = new Box(Orientation.VERTICAL, 0); label_box.append(display_name_label); if (device.detail_name != null) { - Label detail_name_label = new Label(device.detail_name) { xalign=0, visible=true }; - detail_name_label.get_style_context().add_class("dim-label"); + Label detail_name_label = new Label(device.detail_name) { xalign=0 }; + detail_name_label.add_css_class("dim-label"); detail_name_label.attributes = new Pango.AttrList(); detail_name_label.attributes.insert(Pango.attr_scale_new(0.8)); label_box.append(detail_name_label); } device_box.append(label_box); - ListBoxRow list_box_row = new ListBoxRow() { visible=true }; + ListBoxRow list_box_row = new ListBoxRow(); list_box_row.set_child(device_box); micro_list_box.append(list_box_row); @@ -81,22 +81,22 @@ public class Dino.Ui.AudioSettingsPopover : Gtk.Popover { Plugins.VideoCallPlugin call_plugin = Dino.Application.get_default().plugin_registry.video_call_plugin; Gee.List devices = call_plugin.get_devices("audio", true); - Box speaker_box = new Box(Orientation.VERTICAL, 10) { visible=true }; - speaker_box.append(new Label("" + _("Speakers") +"") { use_markup=true, xalign=0, visible=true }); + Box speaker_box = new Box(Orientation.VERTICAL, 10); + speaker_box.append(new Label("" + _("Speakers") +"") { use_markup=true, xalign=0 }); if (devices.size == 0) { speaker_box.append(new Label(_("No speaker found."))); } else { - ListBox speaker_list_box = new ListBox() { activate_on_single_click=true, selection_mode=SelectionMode.SINGLE, visible=true }; + ListBox speaker_list_box = new ListBox() { activate_on_single_click=true, selection_mode=SelectionMode.SINGLE }; speaker_list_box.set_header_func(listbox_header_func); speaker_list_box.row_selected.connect((row) => { }); - Frame speaker_frame = new Frame(null) { visible=true }; + Frame speaker_frame = new Frame(null); speaker_frame.set_child(speaker_list_box); foreach (Plugins.MediaDevice device in devices) { - Label display_name_label = new Label(device.display_name) { xalign=0, visible=true }; - Image image = new Image.from_icon_name("object-select-symbolic") { visible=true }; + Label display_name_label = new Label(device.display_name) { xalign=0 }; + Image image = new Image.from_icon_name("object-select-symbolic"); if (current_speaker_device == null || current_speaker_device.id != device.id) { image.opacity = 0; } @@ -107,19 +107,19 @@ public class Dino.Ui.AudioSettingsPopover : Gtk.Popover { image.opacity = 1; } }); - Box device_box = new Box(Orientation.HORIZONTAL, 0) { spacing=7, visible=true }; + Box device_box = new Box(Orientation.HORIZONTAL, 0) { spacing=7 }; device_box.append(image); Box label_box = new Box(Orientation.VERTICAL, 0) { visible = true }; label_box.append(display_name_label); if (device.detail_name != null) { - Label detail_name_label = new Label(device.detail_name) { xalign=0, visible=true }; - detail_name_label.get_style_context().add_class("dim-label"); + Label detail_name_label = new Label(device.detail_name) { xalign=0 }; + detail_name_label.add_css_class("dim-label"); detail_name_label.attributes = new Pango.AttrList(); detail_name_label.attributes.insert(Pango.attr_scale_new(0.8)); label_box.append(detail_name_label); } device_box.append(label_box); - ListBoxRow list_box_row = new ListBoxRow() { visible=true }; + ListBoxRow list_box_row = new ListBoxRow(); list_box_row.set_child(device_box); speaker_list_box.append(list_box_row); diff --git a/main/src/ui/call_window/call_bottom_bar.vala b/main/src/ui/call_window/call_bottom_bar.vala index ddc196f2..c30a86e9 100644 --- a/main/src/ui/call_window/call_bottom_bar.vala +++ b/main/src/ui/call_window/call_bottom_bar.vala @@ -11,52 +11,54 @@ public class Dino.Ui.CallBottomBar : Gtk.Box { public string counterpart_display_name { get; set; } - private Button audio_button = new Button() { height_request=45, width_request=45, halign=Align.START, valign=Align.START, visible=true }; - private Overlay audio_button_overlay = new Overlay() { visible=true }; + private Button audio_button = new Button() { height_request=45, width_request=45, halign=Align.START, valign=Align.START }; + private Overlay audio_button_overlay = new Overlay(); private Image audio_image = new Image() { pixel_size=22 }; - private MenuButton audio_settings_button = new MenuButton() { icon_name="go-up-symbolic", halign=Align.END, valign=Align.END }; + private MenuButton audio_settings_button = new MenuButton() { halign=Align.END, valign=Align.END }; public AudioSettingsPopover? audio_settings_popover; - private Button video_button = new Button() { height_request=45, width_request=45, halign=Align.START, valign=Align.START, visible=true }; - private Overlay video_button_overlay = new Overlay() { visible=true }; + private Button video_button = new Button() { height_request=45, width_request=45, halign=Align.START, valign=Align.START }; + private Overlay video_button_overlay = new Overlay(); private Image video_image = new Image() { pixel_size=22 }; - private MenuButton video_settings_button = new MenuButton() { icon_name="go-up-symbolic", halign=Align.END, valign=Align.END }; + private MenuButton video_settings_button = new MenuButton() { halign=Align.END, valign=Align.END }; public VideoSettingsPopover? video_settings_popover; - private Label label = new Label("") { halign=Align.CENTER, valign=Align.CENTER, wrap=true, wrap_mode=Pango.WrapMode.WORD_CHAR, hexpand=true, visible=true }; - private Stack stack = new Stack() { visible=true }; + private Label label = new Label("") { halign=Align.CENTER, valign=Align.CENTER, wrap=true, wrap_mode=Pango.WrapMode.WORD_CHAR, hexpand=true }; + private Stack stack = new Stack(); public CallBottomBar() { Object(orientation:Orientation.HORIZONTAL, spacing:0); - Box main_buttons = new Box(Orientation.HORIZONTAL, 20) { margin_start=40, margin_end=40, margin_bottom=20, margin_top=20, halign=Align.CENTER, hexpand=true, visible=true }; + Box main_buttons = new Box(Orientation.HORIZONTAL, 20) { margin_start=40, margin_end=40, margin_bottom=20, margin_top=20, halign=Align.CENTER, hexpand=true }; audio_button.set_child(audio_image); - audio_button.get_style_context().add_class("call-button"); + audio_button.add_css_class("call-button"); audio_button.clicked.connect(() => { audio_enabled = !audio_enabled; }); audio_button.margin_end = audio_button.margin_bottom = 5; // space for the small settings button audio_button_overlay.set_child(audio_button); audio_button_overlay.add_overlay(audio_settings_button); - audio_settings_button.get_style_context().add_class("call-mediadevice-settings-button"); + audio_settings_button.set_child(new Image.from_icon_name("go-up-symbolic") { pixel_size=10 }); + audio_settings_button.add_css_class("call-mediadevice-settings-button"); main_buttons.append(audio_button_overlay); video_button.set_child(video_image); - video_button.get_style_context().add_class("call-button"); + video_button.add_css_class("call-button"); video_button.clicked.connect(() => { video_enabled = !video_enabled; }); video_button.margin_end = video_button.margin_bottom = 5; video_button_overlay.set_child(video_button); video_button_overlay.add_overlay(video_settings_button); - video_settings_button.get_style_context().add_class("call-mediadevice-settings-button"); + video_settings_button.set_child(new Image.from_icon_name("go-up-symbolic") { pixel_size=10 }); + video_settings_button.add_css_class("call-mediadevice-settings-button"); main_buttons.append(video_button_overlay); - Button button_hang = new Button() { height_request=45, width_request=45, halign=Align.START, valign=Align.START, visible=true }; + Button button_hang = new Button() { height_request=45, width_request=45, halign=Align.START, valign=Align.START }; button_hang.set_child(new Image() { icon_name="dino-phone-hangup-symbolic", pixel_size=22 }); - button_hang.get_style_context().add_class("call-button"); - button_hang.get_style_context().add_class("destructive-action"); + button_hang.add_css_class("call-button"); + button_hang.add_css_class("destructive-action"); button_hang.clicked.connect(() => hang_up()); main_buttons.append(button_hang); - label.get_style_context().add_class("text-no-controls"); + label.add_css_class("text-no-controls"); stack.add_named(main_buttons, "control-buttons"); stack.add_named(label, "label"); @@ -71,7 +73,7 @@ public class Dino.Ui.CallBottomBar : Gtk.Box { on_audio_enabled_changed(); on_video_enabled_changed(); - this.get_style_context().add_class("call-bottom-bar"); + this.add_css_class("call-bottom-bar"); } public AudioSettingsPopover? show_audio_device_choices(bool show) { @@ -112,25 +114,25 @@ public class Dino.Ui.CallBottomBar : Gtk.Box { public void on_audio_enabled_changed() { if (audio_enabled) { audio_image.icon_name = "dino-microphone-symbolic"; - audio_button.get_style_context().add_class("white-button"); - audio_button.get_style_context().remove_class("transparent-white-button"); + audio_button.add_css_class("white-button"); + audio_button.remove_css_class("transparent-white-button"); } else { audio_image.icon_name = "dino-microphone-off-symbolic"; - audio_button.get_style_context().remove_class("white-button"); - audio_button.get_style_context().add_class("transparent-white-button"); + audio_button.remove_css_class("white-button"); + audio_button.add_css_class("transparent-white-button"); } } public void on_video_enabled_changed() { if (video_enabled) { video_image.icon_name = "dino-video-symbolic"; - video_button.get_style_context().add_class("white-button"); - video_button.get_style_context().remove_class("transparent-white-button"); + video_button.add_css_class("white-button"); + video_button.remove_css_class("transparent-white-button"); } else { video_image.icon_name = "dino-video-off-symbolic"; - video_button.get_style_context().remove_class("white-button"); - video_button.get_style_context().add_class("transparent-white-button"); + video_button.remove_css_class("white-button"); + video_button.add_css_class("transparent-white-button"); } } @@ -140,6 +142,7 @@ public class Dino.Ui.CallBottomBar : Gtk.Box { } public bool is_menu_active() { - return video_settings_button.popover.visible || audio_settings_button.popover.visible; // TODO gtk4 does this work? check for null? + return (video_settings_button.popover != null && video_settings_button.popover.visible) || + (audio_settings_button.popover != null && audio_settings_button.popover.visible); } } \ No newline at end of file diff --git a/main/src/ui/call_window/call_connection_details_window.vala b/main/src/ui/call_window/call_connection_details_window.vala index 0905908c..9e9e1b3a 100644 --- a/main/src/ui/call_window/call_connection_details_window.vala +++ b/main/src/ui/call_window/call_connection_details_window.vala @@ -4,10 +4,10 @@ namespace Dino.Ui { public class CallConnectionDetailsWindow : Gtk.Window { - public Box box = new Box(Orientation.VERTICAL, 15) { halign=Align.CENTER, valign=Align.CENTER, visible=true }; + public Box box = new Box(Orientation.VERTICAL, 15) { halign=Align.CENTER, valign=Align.CENTER }; private bool video_added = false; - private CallContentDetails audio_details = new CallContentDetails("Audio") { visible=true }; + private CallContentDetails audio_details = new CallContentDetails("Audio"); private CallContentDetails video_details = new CallContentDetails("Video"); public CallConnectionDetailsWindow() { @@ -36,24 +36,24 @@ namespace Dino.Ui { public class CallContentDetails : Gtk.Grid { - public Label rtp_title = new Label("RTP") { xalign=0, visible=true }; - public Label rtcp_title = new Label("RTCP") { xalign=0, visible=true }; - public Label target_recv_title = new Label("Target receive bitrate") { xalign=0, visible=true }; - public Label target_send_title = new Label("Target send bitrate") { xalign=0, visible=true }; + public Label rtp_title = new Label("RTP") { xalign=0 }; + public Label rtcp_title = new Label("RTCP") { xalign=0 }; + public Label target_recv_title = new Label("Target receive bitrate") { xalign=0 }; + public Label target_send_title = new Label("Target send bitrate") { xalign=0 }; - public Label rtp_ready = new Label("?") { xalign=0, visible=true }; - public Label rtcp_ready = new Label("?") { xalign=0, visible=true }; - public Label sent_bps = new Label("?") { use_markup=true, xalign=0, visible=true }; - public Label recv_bps = new Label("?") { use_markup=true, xalign=0, visible=true }; - public Label codec = new Label("?") { xalign=0, visible=true }; - public Label target_receive_bitrate = new Label("n/a") { use_markup=true, xalign=0, visible=true }; - public Label target_send_bitrate = new Label("n/a") { use_markup=true, xalign=0, visible=true }; + public Label rtp_ready = new Label("?") { xalign=0 }; + public Label rtcp_ready = new Label("?") { xalign=0 }; + public Label sent_bps = new Label("?") { use_markup=true, xalign=0 }; + public Label recv_bps = new Label("?") { use_markup=true, xalign=0 }; + public Label codec = new Label("?") { xalign=0 }; + public Label target_receive_bitrate = new Label("n/a") { use_markup=true, xalign=0 }; + public Label target_send_bitrate = new Label("n/a") { use_markup=true, xalign=0 }; private PeerContentInfo? prev_info = null; private int row_at = 0; public CallContentDetails(string headline) { - attach(new Label("%s".printf(headline)) { use_markup=true, xalign=0, visible=true }, 0, row_at++, 1, 1); + attach(new Label("%s".printf(headline)) { use_markup=true, xalign=0 }, 0, row_at++, 1, 1); attach(rtp_title, 0, row_at, 1, 1); attach(rtp_ready, 1, row_at++, 1, 1); attach(rtcp_title, 0, row_at, 1, 1); @@ -104,7 +104,7 @@ namespace Dino.Ui { } private void put_row(string label) { - attach(new Label(label) { xalign=0, visible=true }, 0, row_at, 1, 1); + attach(new Label(label) { xalign=0 }, 0, row_at, 1, 1); } } } diff --git a/main/src/ui/call_window/call_encryption_button.vala b/main/src/ui/call_window/call_encryption_button.vala index 095db2b4..1b586f28 100644 --- a/main/src/ui/call_window/call_encryption_button.vala +++ b/main/src/ui/call_window/call_encryption_button.vala @@ -2,7 +2,7 @@ using Dino.Entities; using Gtk; using Pango; -public class Dino.Ui.CallEncryptionButtonController { +public class Dino.Ui.CallEncryptionButtonController : Object { private bool has_been_set = false; public bool controls_active { get; set; default=false; } @@ -21,10 +21,10 @@ public class Dino.Ui.CallEncryptionButtonController { public void set_icon(bool encrypted, string? icon_name) { if (encrypted) { button.icon_name = icon_name ?? "changes-prevent-symbolic"; - button.get_style_context().remove_class("unencrypted"); + button.remove_css_class("unencrypted"); } else { button.icon_name = icon_name ?? "changes-allow-symbolic"; - button.get_style_context().add_class("unencrypted"); + button.add_css_class("unencrypted"); } has_been_set = true; update_opacity(); @@ -35,23 +35,23 @@ public class Dino.Ui.CallEncryptionButtonController { button.set_popover(popover); if (audio_encryption == null) { - popover.set_child(new Label("This call is unencrypted.") { visible=true } ); + popover.set_child(new Label("This call is unencrypted.") ); return; } if (title != null && !show_keys) { - popover.set_child(new Label(title) { use_markup=true, visible=true } ); + popover.set_child(new Label(title) { use_markup=true } ); return; } - Box box = new Box(Orientation.VERTICAL, 10) { visible=true }; - box.append(new Label("%s".printf(title ?? "This call is end-to-end encrypted.")) { use_markup=true, xalign=0, visible=true }); + Box box = new Box(Orientation.VERTICAL, 10); + box.append(new Label("%s".printf(title ?? "This call is end-to-end encrypted.")) { use_markup=true, xalign=0 }); if (video_encryption == null) { box.append(create_media_encryption_grid(audio_encryption)); } else { - box.append(new Label("Audio") { use_markup=true, xalign=0, visible=true }); + box.append(new Label("Audio") { use_markup=true, xalign=0 }); box.append(create_media_encryption_grid(audio_encryption)); - box.append(new Label("Video") { use_markup=true, xalign=0, visible=true }); + box.append(new Label("Video") { use_markup=true, xalign=0 }); box.append(create_media_encryption_grid(video_encryption)); } popover.set_child(box); @@ -62,14 +62,14 @@ public class Dino.Ui.CallEncryptionButtonController { } private Grid create_media_encryption_grid(Xmpp.Xep.Jingle.ContentEncryption? encryption) { - Grid ret = new Grid() { row_spacing=3, column_spacing=5, visible=true }; + Grid ret = new Grid() { row_spacing=3, column_spacing=5 }; if (encryption.peer_key.length > 0) { - ret.attach(new Label("Peer call key") { xalign=0, visible=true }, 1, 2, 1, 1); - ret.attach(new Label("" + format_fingerprint(encryption.peer_key) + "") { use_markup=true, max_width_chars=25, ellipsize=EllipsizeMode.MIDDLE, xalign=0, hexpand=true, visible=true }, 2, 2, 1, 1); + ret.attach(new Label("Peer call key") { xalign=0 }, 1, 2, 1, 1); + ret.attach(new Label("" + format_fingerprint(encryption.peer_key) + "") { use_markup=true, max_width_chars=25, ellipsize=EllipsizeMode.MIDDLE, xalign=0, hexpand=true }, 2, 2, 1, 1); } if (encryption.our_key.length > 0) { - ret.attach(new Label("Your call key") { xalign=0, visible=true }, 1, 3, 1, 1); - ret.attach(new Label("" + format_fingerprint(encryption.our_key) + "") { use_markup=true, max_width_chars=25, ellipsize=EllipsizeMode.MIDDLE, xalign=0, hexpand=true, visible=true }, 2, 3, 1, 1); + ret.attach(new Label("Your call key") { xalign=0 }, 1, 3, 1, 1); + ret.attach(new Label("" + format_fingerprint(encryption.our_key) + "") { use_markup=true, max_width_chars=25, ellipsize=EllipsizeMode.MIDDLE, xalign=0, hexpand=true }, 2, 3, 1, 1); } return ret; } diff --git a/main/src/ui/call_window/call_window.vala b/main/src/ui/call_window/call_window.vala index cd05848a..cf89d8e8 100644 --- a/main/src/ui/call_window/call_window.vala +++ b/main/src/ui/call_window/call_window.vala @@ -11,13 +11,13 @@ namespace Dino.Ui { public CallWindowController controller; - public Overlay overlay = new Overlay() { visible=true }; - public Grid grid = new Grid() { visible=true }; - public CallBottomBar bottom_bar = new CallBottomBar() { visible=true }; - public Revealer bottom_bar_revealer = new Revealer() { valign=Align.END, transition_type=RevealerTransitionType.CROSSFADE, transition_duration=200, visible=true }; - public HeaderBar header_bar = new HeaderBar() { valign=Align.START, halign=Align.END, show_title_buttons=true, visible=true, opacity=0.0 }; - public Revealer header_bar_revealer = new Revealer() { halign=Align.END, valign=Align.START, transition_type=RevealerTransitionType.SLIDE_LEFT, transition_duration=200, visible=true, reveal_child=false }; - public Box own_video_box = new Box(Orientation.HORIZONTAL, 0) { halign=Align.END, valign=Align.END, visible=true }; + public Overlay overlay = new Overlay(); + public Grid grid = new Grid(); + public CallBottomBar bottom_bar = new CallBottomBar(); + public Revealer bottom_bar_revealer = new Revealer() { valign=Align.END, transition_type=RevealerTransitionType.CROSSFADE, transition_duration=200 }; + public HeaderBar header_bar = new HeaderBar() { valign=Align.START, halign=Align.END, show_title_buttons=true, opacity=0.0 }; + public Revealer header_bar_revealer = new Revealer() { halign=Align.END, valign=Align.START, transition_type=RevealerTransitionType.SLIDE_LEFT, transition_duration=200, reveal_child=false }; + public Box own_video_box = new Box(Orientation.HORIZONTAL, 0) { halign=Align.END, valign=Align.END }; private Widget? own_video = null; private HashMap participant_widgets = new HashMap(); private ArrayList participants = new ArrayList(); @@ -32,14 +32,14 @@ namespace Dino.Ui { public bool controls_active { get; set; default=true; } construct { - header_bar.get_style_context().add_class("call-header-bar"); + header_bar.add_css_class("call-header-bar"); header_bar.title_widget = new Box(Orientation.VERTICAL, 0); // header_bar.spacing = 0; header_bar_revealer.set_child(header_bar); bottom_bar_revealer.set_child(bottom_bar); - own_video_box.get_style_context().add_class("own-video"); + own_video_box.add_css_class("own-video"); - this.get_style_context().add_class("dino-call-window"); + this.add_css_class("dino-call-window"); overlay.set_child(grid); overlay.add_overlay(own_video_box); @@ -64,7 +64,7 @@ namespace Dino.Ui { this.notify["default-width"].connect(reposition_participant_widgets); this.notify["default-height"].connect(reposition_participant_widgets); - this.set_titlebar(new OutsideHeaderBar(this.header_bar) { visible=true }); + this.set_titlebar(new OutsideHeaderBar(this.header_bar)); reveal_control_elements(); } @@ -72,7 +72,7 @@ namespace Dino.Ui { public void add_participant(string participant, ParticipantWidget participant_widget) { participant_widget.visible = true; this.bind_property("controls-active", participant_widget, "controls-active", BindingFlags.SYNC_CREATE); - this.bind_property("controls-active", participant_widget.encryption_button, "controls-active", BindingFlags.SYNC_CREATE); + this.bind_property("controls-active", participant_widget.encryption_button_controller, "controls-active", BindingFlags.SYNC_CREATE); participants.add(participant); participant_widgets[participant] = participant_widget; @@ -153,8 +153,9 @@ namespace Dino.Ui { own_video = widget_; if (own_video == null) { - own_video = new Box(Orientation.HORIZONTAL, 0) { hexpand=true, vexpand=true }; + own_video = new Box(Orientation.HORIZONTAL, 0); } + own_video.hexpand = own_video.vexpand = true; own_video.visible = true; own_video_box.append(own_video); } diff --git a/main/src/ui/call_window/call_window_controller.vala b/main/src/ui/call_window/call_window_controller.vala index e3f8b670..e0eca6dc 100644 --- a/main/src/ui/call_window/call_window_controller.vala +++ b/main/src/ui/call_window/call_window_controller.vala @@ -134,10 +134,11 @@ public class Dino.Ui.CallWindowController : Object { warning("suspend inhibit request failed or unsupported"); } - call_window.destroy.connect(() => { + call_window.close_request.connect(() => { if (inhibit_cookie != 0) { app.uninhibit(inhibit_cookie); } + return false; }); } @@ -235,7 +236,7 @@ public class Dino.Ui.CallWindowController : Object { ParticipantWidget participant_widget = new ParticipantWidget(participant_name); participant_widget.may_show_invite_button = !participant_widgets.is_empty; participant_widget.debug_information_clicked.connect(() => { - var conn_details_window = new CallConnectionDetailsWindow() { title=participant_name, visible=true }; + var conn_details_window = new CallConnectionDetailsWindow() { title=participant_name }; conn_details_window.update_content(peer_states[participant_id].get_info()); uint timeout_handle_id = Timeout.add_seconds(1, () => { conn_details_window.update_content(peer_states[participant_id].get_info()); @@ -361,7 +362,9 @@ public class Dino.Ui.CallWindowController : Object { public override void dispose() { foreach (ulong handler_id in call_window_handler_ids) call_window.disconnect(handler_id); foreach (ulong handler_id in bottom_bar_handler_ids) call_window.bottom_bar.disconnect(handler_id); - participant_widgets.keys.@foreach((peer_id) => { remove_participant(peer_id); return true; }); + foreach (string peer_id in participant_widgets.keys) { + remove_participant(peer_id); + } call_window_handler_ids = bottom_bar_handler_ids = new ulong[0]; own_video.detach(); diff --git a/main/src/ui/call_window/participant_widget.vala b/main/src/ui/call_window/participant_widget.vala index ecd6cbb3..180923f1 100644 --- a/main/src/ui/call_window/participant_widget.vala +++ b/main/src/ui/call_window/participant_widget.vala @@ -10,15 +10,15 @@ namespace Dino.Ui { public Overlay overlay = new Overlay(); public Widget main_widget; - public HeaderBar header_bar = new HeaderBar() { valign=Align.START, visible=true }; + public HeaderBar header_bar = new HeaderBar() { valign=Align.START }; public Label title_label = new Label(""); public Label subtitle_label = new Label(""); - public Box inner_box = new Box(Orientation.HORIZONTAL, 0) { margin_start=5, margin_top=5, hexpand=true, visible=true }; - public Box title_box = new Box(Orientation.VERTICAL, 0) { valign=Align.CENTER, hexpand=true, visible=true }; - public MenuButton encryption_button = new MenuButton() { opacity=0, has_frame=false, height_request=30, width_request=30, margin_end=5, visible=true }; + public Box inner_box = new Box(Orientation.HORIZONTAL, 0) { margin_start=5, margin_top=5, hexpand=true }; + public Box title_box = new Box(Orientation.VERTICAL, 0) { valign=Align.CENTER, hexpand=true }; + public MenuButton encryption_button = new MenuButton() { opacity=0, has_frame=false, height_request=30, width_request=30, margin_end=5 }; public CallEncryptionButtonController encryption_button_controller; - public MenuButton menu_button = new MenuButton() { icon_name="open-menu-symbolic", has_frame=false, visible=true }; - public Button invite_button = new Button.from_icon_name("dino-account-plus") { has_frame=false, visible=true }; + public MenuButton menu_button = new MenuButton() { icon_name="open-menu-symbolic", has_frame=false }; + public Button invite_button = new Button.from_icon_name("dino-account-plus") { has_frame=false }; public bool shows_video = false; public string? participant_name; @@ -40,18 +40,19 @@ namespace Dino.Ui { this.participant_name = participant_name; Box titles_box = new Box(Orientation.VERTICAL, 0) { valign=Align.CENTER }; + titles_box.add_css_class("titles"); title_label.attributes = new AttrList(); title_label.attributes.insert(Pango.attr_weight_new(Weight.BOLD)); titles_box.append(title_label); subtitle_label.attributes = new AttrList(); subtitle_label.attributes.insert(Pango.attr_scale_new(Pango.Scale.SMALL)); - subtitle_label.get_style_context().add_class("dim-label"); + subtitle_label.add_css_class("dim-label"); titles_box.append(subtitle_label); header_bar.set_title_widget(titles_box); title_label.label = participant_name; - header_bar.get_style_context().add_class("participant-header-bar"); + header_bar.add_css_class("participant-header-bar"); header_bar.pack_start(invite_button); header_bar.pack_start(encryption_button); header_bar.pack_end(menu_button); @@ -73,14 +74,14 @@ namespace Dino.Ui { header_bar.show_title_buttons = is_highest_row; if (is_highest_row) { - header_bar.get_style_context().add_class("call-header-background"); + header_bar.add_css_class("call-header-background"); Gtk.Settings? gtk_settings = Gtk.Settings.get_default(); if (gtk_settings != null) { string[] buttons = gtk_settings.gtk_decoration_layout.split(":"); header_bar.decoration_layout = (is_start ? buttons[0] : "") + ":" + (is_end && buttons.length == 2 ? buttons[1] : ""); } } else { - header_bar.get_style_context().remove_class("call-header-background"); + header_bar.remove_css_class("call-header-background"); } reveal_or_hide_controls(); } @@ -93,9 +94,9 @@ namespace Dino.Ui { public void set_placeholder(Conversation? conversation, StreamInteractor stream_interactor) { shows_video = false; - Box box = new Box(Orientation.HORIZONTAL, 0) { visible=true }; - box.get_style_context().add_class("video-placeholder-box"); - AvatarImage avatar = new AvatarImage() { allow_gray=false, hexpand=true, vexpand=true, halign=Align.CENTER, valign=Align.CENTER, height=100, width=100, visible=true }; + Box box = new Box(Orientation.HORIZONTAL, 0); + box.add_css_class("video-placeholder-box"); + AvatarImage avatar = new AvatarImage() { allow_gray=false, hexpand=true, vexpand=true, halign=Align.CENTER, valign=Align.CENTER, height=100, width=100 }; if (conversation != null) { avatar.set_conversation(stream_interactor, conversation); } else { @@ -133,6 +134,10 @@ namespace Dino.Ui { } } + public bool is_menu_active() { + return false; + } + private void reveal_or_hide_controls() { header_bar.opacity = controls_active ? 1.0 : 0.0; invite_button.visible = may_show_invite_button && is_highest_row && is_start_row; diff --git a/main/src/ui/call_window/video_settings_popover.vala b/main/src/ui/call_window/video_settings_popover.vala index c931c466..58967bd2 100644 --- a/main/src/ui/call_window/video_settings_popover.vala +++ b/main/src/ui/call_window/video_settings_popover.vala @@ -11,7 +11,7 @@ public class Dino.Ui.VideoSettingsPopover : Gtk.Popover { private HashMap row_device = new HashMap(); public VideoSettingsPopover() { - Box box = new Box(Orientation.VERTICAL, 15) { visible=true }; + Box box = new Box(Orientation.VERTICAL, 15); box.append(create_camera_box()); this.set_child(box); @@ -21,19 +21,19 @@ public class Dino.Ui.VideoSettingsPopover : Gtk.Popover { Plugins.VideoCallPlugin call_plugin = Dino.Application.get_default().plugin_registry.video_call_plugin; Gee.List devices = call_plugin.get_devices("video", false); - Box camera_box = new Box(Orientation.VERTICAL, 10) { visible=true }; - camera_box.append(new Label("" + _("Cameras") + "") { use_markup=true, xalign=0, visible=true, can_focus=true /* grab initial focus*/ }); + Box camera_box = new Box(Orientation.VERTICAL, 10); + camera_box.append(new Label("" + _("Cameras") + "") { use_markup=true, xalign=0, can_focus=true /* grab initial focus*/ }); if (devices.size == 0) { - camera_box.append(new Label(_("No camera found.")) { visible=true }); + camera_box.append(new Label(_("No camera found."))); } else { - ListBox list_box = new ListBox() { activate_on_single_click=true, selection_mode=SelectionMode.SINGLE, visible=true }; + ListBox list_box = new ListBox() { activate_on_single_click=true, selection_mode=SelectionMode.SINGLE }; list_box.set_header_func(listbox_header_func); - Frame frame = new Frame(null) { visible=true }; + Frame frame = new Frame(null); frame.set_child(list_box); foreach (Plugins.MediaDevice device in devices) { - Label display_name_label = new Label(device.display_name) { xalign=0, visible=true }; - Image image = new Image.from_icon_name("object-select-symbolic") { visible=true }; + Label display_name_label = new Label(device.display_name) { xalign=0 }; + Image image = new Image.from_icon_name("object-select-symbolic"); if (current_device == null || current_device.id != device.id) { image.opacity = 0; } @@ -44,19 +44,19 @@ public class Dino.Ui.VideoSettingsPopover : Gtk.Popover { image.opacity = 1; } }); - Box device_box = new Box(Orientation.HORIZONTAL, 0) { spacing=7, visible=true }; + Box device_box = new Box(Orientation.HORIZONTAL, 0) { spacing=7 }; device_box.append(image); Box label_box = new Box(Orientation.VERTICAL, 0) { visible = true }; label_box.append(display_name_label); if (device.detail_name != null) { - Label detail_name_label = new Label(device.detail_name) { xalign=0, visible=true }; - detail_name_label.get_style_context().add_class("dim-label"); + Label detail_name_label = new Label(device.detail_name) { xalign=0 }; + detail_name_label.add_css_class("dim-label"); detail_name_label.attributes = new Pango.AttrList(); detail_name_label.attributes.insert(Pango.attr_scale_new(0.8)); label_box.append(detail_name_label); } device_box.append(label_box); - ListBoxRow list_box_row = new ListBoxRow() { visible=true }; + ListBoxRow list_box_row = new ListBoxRow(); list_box_row.set_child(device_box); list_box.append(list_box_row); diff --git a/main/src/ui/chat_input/chat_text_view.vala b/main/src/ui/chat_input/chat_text_view.vala index b1f719b6..437950ea 100644 --- a/main/src/ui/chat_input/chat_text_view.vala +++ b/main/src/ui/chat_input/chat_text_view.vala @@ -26,7 +26,6 @@ public class ChatTextViewController : Object { public void initialize_for_conversation(Conversation conversation) { occupants_tab_completor.initialize_for_conversation(conversation); - widget.initialize_for_conversation(conversation); } } @@ -39,40 +38,31 @@ public class ChatTextView : Box { public TextView text_view = new TextView() { hexpand=true, wrap_mode=Gtk.WrapMode.WORD_CHAR, valign=Align.CENTER, margin_top=7, margin_bottom=7 }; private int vscrollbar_min_height; private SmileyConverter smiley_converter; -// private SpellChecker spell_checker; construct { scrolled_window.set_child(text_view); this.append(scrolled_window); - smiley_converter = new SmileyConverter(text_view); - -// scrolled_window.get_vscrollbar().get_preferred_size(out vscrollbar_min_size, null); - scrolled_window.vadjustment.notify["upper"].connect(on_upper_notify); - var text_input_key_events = new EventControllerKey(); text_input_key_events.key_pressed.connect(on_text_input_key_press); text_view.add_controller(text_input_key_events); + smiley_converter = new SmileyConverter(text_view); + + scrolled_window.vadjustment.changed.connect(on_upper_notify); + text_view.realize.connect(() => { var minimum_size = new Requisition(); scrolled_window.get_preferred_size(out minimum_size, null); vscrollbar_min_height = minimum_size.height; }); -// Gtk.drag_dest_unset(text_view); } - public void initialize_for_conversation(Conversation conversation) { -// spell_checker.initialize_for_conversation(conversation); - } - -// public override void get_preferred_size(out Gtk.Requisition minimum_size, out Gtk.Requisition natural_size) { -// base.get_preferred_height(out min_height, out nat_height); -// min_height = nat_height; -// } - private void on_upper_notify() { - scrolled_window.vadjustment.value = scrolled_window.vadjustment.upper - scrolled_window.vadjustment.page_size; + // hack. otherwise the textview would only show the last row(s) when entering a new row on some systems. + if (text_view.get_height() < scrolled_window.max_content_height - 20) { + scrolled_window.vadjustment.page_size = scrolled_window.vadjustment.upper; + } // hack for vscrollbar not requiring space and making textview higher //TODO doesn't resize immediately scrolled_window.get_vscrollbar().visible = (scrolled_window.vadjustment.upper > scrolled_window.max_content_height - 2 * this.vscrollbar_min_height); diff --git a/main/src/ui/chat_input/encryption_button.vala b/main/src/ui/chat_input/encryption_button.vala index e5831802..ab463f44 100644 --- a/main/src/ui/chat_input/encryption_button.vala +++ b/main/src/ui/chat_input/encryption_button.vala @@ -15,16 +15,39 @@ public class EncryptionButton { private Map encryption_radios = new HashMap(); private string? current_icon; private StreamInteractor stream_interactor; + private SimpleAction action; public EncryptionButton(StreamInteractor stream_interactor, MenuButton menu_button) { this.stream_interactor = stream_interactor; this.menu_button = menu_button; - Builder builder = new Builder.from_resource("/im/dino/Dino/menu_encryption.ui"); - menu_button.popover = builder.get_object("menu_encryption") as PopoverMenu; - Box encryption_box = builder.get_object("encryption_box") as Box; - button_unencrypted = builder.get_object("button_unencrypted") as CheckButton; - button_unencrypted.toggled.connect(encryption_button_toggled); + // Build menu model including "Unencrypted" and all registered encryption entries + Menu menu_model = new Menu(); + + MenuItem unencrypted_item = new MenuItem(_("Unencrypted"), "enc.encryption"); + unencrypted_item.set_action_and_target_value("enc.encryption", new Variant.int32(Encryption.NONE)); + menu_model.append_item(unencrypted_item); + + Application app = GLib.Application.get_default() as Application; + foreach (var e in app.plugin_registry.encryption_list_entries) { + MenuItem item = new MenuItem(e.name, "enc.encryption"); + item.set_action_and_target_value("enc.encryption", new Variant.int32(e.encryption)); + menu_model.append_item(item); + } + + // Create action to act on menu selections (stateful => radio buttons) + SimpleActionGroup action_group = new SimpleActionGroup(); + action = new SimpleAction.stateful("encryption", VariantType.INT32, new Variant.int32(Encryption.NONE)); + action.activate.connect((parameter) => { + action.set_state(parameter); + this.conversation.encryption = (Encryption) parameter.get_int32(); + }); + action_group.insert(action); + menu_button.insert_action_group("enc", action_group); + + // Create and set popover menu + Gtk.PopoverMenu popover_menu = new Gtk.PopoverMenu.from_model(menu_model); + menu_button.popover = popover_menu; stream_interactor.get_module(MucManager.IDENTITY).room_info_updated.connect((account, muc_jid) => { if (conversation != null && conversation.account.equals(account) && conversation.counterpart.equals(muc_jid)) { @@ -32,15 +55,6 @@ public class EncryptionButton { } }); - Application app = GLib.Application.get_default() as Application; - foreach (var e in app.plugin_registry.encryption_list_entries) { - CheckButton btn = new CheckButton.with_label(e.name); - btn.set_group(button_unencrypted); - encryption_radios[btn] = e; - btn.toggled.connect(encryption_button_toggled); - btn.visible = true; - encryption_box.prepend(btn); - } menu_button.activate.connect(update_encryption_menu_state); } @@ -61,16 +75,8 @@ public class EncryptionButton { } private void update_encryption_menu_state() { - foreach (CheckButton e in encryption_radios.keys) { - if (conversation.encryption == encryption_radios[e].encryption) { - e.set_active(true); - encryption_changed(encryption_radios[e]); - } - } - if (conversation.encryption == Encryption.NONE) { - button_unencrypted.set_active(true); - encryption_changed(null); - } + action.set_state(new Variant.int32(conversation.encryption)); + action.change_state(new Variant.int32(conversation.encryption)); } private void set_icon(string icon) { diff --git a/main/src/ui/chat_input/view.vala b/main/src/ui/chat_input/view.vala index 6524a825..81f2bd0f 100644 --- a/main/src/ui/chat_input/view.vala +++ b/main/src/ui/chat_input/view.vala @@ -66,28 +66,28 @@ public class View : Box { public void set_input_state(Plugins.InputFieldStatus.MessageType message_type) { switch (message_type) { case Plugins.InputFieldStatus.MessageType.NONE: - this.get_style_context().remove_class("dino-input-warning"); - this.get_style_context().remove_class("dino-input-error"); + this.remove_css_class("dino-input-warning"); + this.remove_css_class("dino-input-error"); break; case Plugins.InputFieldStatus.MessageType.INFO: - this.get_style_context().remove_class("dino-input-warning"); - this.get_style_context().remove_class("dino-input-error"); + this.remove_css_class("dino-input-warning"); + this.remove_css_class("dino-input-error"); break; case Plugins.InputFieldStatus.MessageType.WARNING: - this.get_style_context().add_class("dino-input-warning"); - this.get_style_context().remove_class("dino-input-error"); + this.add_css_class("dino-input-warning"); + this.remove_css_class("dino-input-error"); break; case Plugins.InputFieldStatus.MessageType.ERROR: - this.get_style_context().remove_class("dino-input-warning"); - this.get_style_context().add_class("dino-input-error"); + this.remove_css_class("dino-input-warning"); + this.add_css_class("dino-input-error"); break; } } public void highlight_state_description() { - chat_input_status.get_style_context().add_class("input-status-highlight-once"); + chat_input_status.add_css_class("input-status-highlight-once"); Timeout.add_seconds(1, () => { - chat_input_status.get_style_context().remove_class("input-status-highlight-once"); + chat_input_status.remove_css_class("input-status-highlight-once"); return false; }); } diff --git a/main/src/ui/contact_details/blocking_provider.vala b/main/src/ui/contact_details/blocking_provider.vala index 76e5d000..7e4a475d 100644 --- a/main/src/ui/contact_details/blocking_provider.vala +++ b/main/src/ui/contact_details/blocking_provider.vala @@ -19,7 +19,7 @@ public class BlockingProvider : Plugins.ContactDetailsProvider, Object { if (stream_interactor.get_module(BlockingManager.IDENTITY).is_supported(conversation.account)) { bool is_blocked = stream_interactor.get_module(BlockingManager.IDENTITY).is_blocked(conversation.account, conversation.counterpart); - Switch sw = new Switch() { active=is_blocked, valign=Align.CENTER, visible=true }; + Switch sw = new Switch() { active=is_blocked, valign=Align.CENTER }; sw.state_set.connect((state) => { if (state) { stream_interactor.get_module(BlockingManager.IDENTITY).block(conversation.account, conversation.counterpart); diff --git a/main/src/ui/contact_details/dialog.vala b/main/src/ui/contact_details/dialog.vala index b07ab9c9..36bef391 100644 --- a/main/src/ui/contact_details/dialog.vala +++ b/main/src/ui/contact_details/dialog.vala @@ -37,7 +37,18 @@ public class Dialog : Gtk.Dialog { title = conversation.type_ == Conversation.Type.GROUPCHAT ? _("Conference Details") : _("Contact Details"); if (Util.use_csd()) { // TODO get_header_bar directly returns a HeaderBar in vala > 0.48 -// ((HeaderBar) get_header_bar()).set_subtitle(Util.get_conversation_display_name(stream_interactor, conversation)); + Box titles_box = new Box(Orientation.VERTICAL, 0) { valign=Align.CENTER }; + var title_label = new Label(title); + title_label.attributes = new AttrList(); + title_label.attributes.insert(Pango.attr_weight_new(Weight.BOLD)); + titles_box.append(title_label); + var subtitle_label = new Label(Util.get_conversation_display_name(stream_interactor, conversation)); + subtitle_label.attributes = new AttrList(); + subtitle_label.attributes.insert(Pango.attr_scale_new(Pango.Scale.SMALL)); + subtitle_label.add_css_class("dim-label"); + titles_box.append(subtitle_label); + + get_header_bar().set_title_widget(titles_box); } setup_top(); @@ -53,9 +64,10 @@ public class Dialog : Gtk.Dialog { provider.populate(conversation, contact_details, Plugins.WidgetType.GTK4); } -// destroy.connect(() => { -// contact_details.save(); -// }); + close_request.connect(() => { + contact_details.save(); + return false; + }); } private void setup_top() { @@ -83,16 +95,16 @@ public class Dialog : Gtk.Dialog { Widget w = (Widget) wo; add_category(category); - ListBoxRow list_row = new ListBoxRow() { activatable=false, visible=true }; - Box row = new Box(Orientation.HORIZONTAL, 20) { margin_start=15, margin_end=15, margin_top=3, margin_bottom=3, visible=true }; + ListBoxRow list_row = new ListBoxRow() { activatable=false }; + Box row = new Box(Orientation.HORIZONTAL, 20) { margin_start=15, margin_end=15, margin_top=3, margin_bottom=3 }; list_row.set_child(row); - Label label_label = new Label(label) { xalign=0, yalign=0.5f, hexpand=true, visible=true }; + Label label_label = new Label(label) { xalign=0, yalign=0.5f, hexpand=true }; if (description != null && description != "") { - Box box = new Box(Orientation.VERTICAL, 0) { visible=true }; + Box box = new Box(Orientation.VERTICAL, 0); box.append(label_label); - Label desc_label = new Label("") { xalign=0, yalign=0.5f, hexpand=true, visible=true }; + Label desc_label = new Label("") { xalign=0, yalign=0.5f, hexpand=true }; desc_label.set_markup("%s".printf(Markup.escape_text(description))); - desc_label.get_style_context().add_class("dim-label"); + desc_label.add_css_class("dim-label"); box.append(desc_label); row.append(box); } else { @@ -101,11 +113,11 @@ public class Dialog : Gtk.Dialog { Widget widget = w; if (widget.get_type().is_a(typeof(Entry))) { - Util.EntryLabelHybrid hybrid = new Util.EntryLabelHybrid.wrap(widget as Entry) { xalign=1, visible=true }; + Util.EntryLabelHybrid hybrid = new Util.EntryLabelHybrid.wrap(widget as Entry) { xalign=1 }; hybrid_group.add(hybrid); widget = hybrid; } else if (widget.get_type().is_a(typeof(ComboBoxText))) { - Util.ComboBoxTextLabelHybrid hybrid = new Util.ComboBoxTextLabelHybrid.wrap(widget as ComboBoxText) { xalign=1, visible=true }; + Util.ComboBoxTextLabelHybrid hybrid = new Util.ComboBoxTextLabelHybrid.wrap(widget as ComboBoxText) { xalign=1 }; hybrid_group.add(hybrid); widget = hybrid; } @@ -116,26 +128,26 @@ public class Dialog : Gtk.Dialog { row.append(widget); categories[category].append(list_row); + int width = get_content_area().get_width(); int pref_height, pref_width; -// get_content_area().get_preferred_height(null, out pref_height); -// get_preferred_width(out pref_width, null); -// resize(pref_width, int.min(500, pref_height)); + get_content_area().measure(Orientation.VERTICAL, width, null, out pref_height, null, null); + default_height = pref_height; } private void add_category(string category) { if (!categories.has_key(category)) { - ListBox list_box = new ListBox() { selection_mode=SelectionMode.NONE, visible=true }; + ListBox list_box = new ListBox() { selection_mode=SelectionMode.NONE }; categories[category] = list_box; list_box.set_header_func((row, before_row) => { if (row.get_header() == null && before_row != null) { row.set_header(new Separator(Orientation.HORIZONTAL)); } }); - Box box = new Box(Orientation.VERTICAL, 5) { margin_top=12, margin_bottom=12, visible=true }; - Label category_label = new Label("") { xalign=0, visible=true }; + Box box = new Box(Orientation.VERTICAL, 5) { margin_top=12, margin_bottom=12 }; + Label category_label = new Label("") { xalign=0 }; category_label.set_markup(@"$(Markup.escape_text(category))"); box.append(category_label); - Frame frame = new Frame(null) { visible=true }; + Frame frame = new Frame(null); frame.set_child(list_box); box.append(frame); main_box.append(box); diff --git a/main/src/ui/contact_details/permissions_provider.vala b/main/src/ui/contact_details/permissions_provider.vala index d87658ff..ed0756e8 100644 --- a/main/src/ui/contact_details/permissions_provider.vala +++ b/main/src/ui/contact_details/permissions_provider.vala @@ -20,7 +20,7 @@ public class PermissionsProvider : Plugins.ContactDetailsProvider, Object { if (own_jid == null) return; if (stream_interactor.get_module(MucManager.IDENTITY).get_role(own_jid, conversation.account) == Xmpp.Xep.Muc.Role.VISITOR){ - Button voice_request = new Button.with_label(_("Request")) { visible=true }; + Button voice_request = new Button.with_label(_("Request")); voice_request.clicked.connect(()=>stream_interactor.get_module(MucManager.IDENTITY).request_voice(conversation.account, conversation.counterpart)); contact_details.add(_("Permissions"), _("Request permission to send messages"), "", voice_request); } diff --git a/main/src/ui/contact_details/settings_provider.vala b/main/src/ui/contact_details/settings_provider.vala index 42c690e5..140ebcab 100644 --- a/main/src/ui/contact_details/settings_provider.vala +++ b/main/src/ui/contact_details/settings_provider.vala @@ -39,7 +39,7 @@ public class SettingsProvider : Plugins.ContactDetailsProvider, Object { combobox_notifications.active_id = get_notify_setting_id(conversation.notify_setting); combobox_notifications.changed.connect(() => { conversation.notify_setting = get_notify_setting(combobox_notifications.active_id); } ); } else if (conversation.type_ == Conversation.Type.GROUPCHAT) { - ComboBoxText combobox = new ComboBoxText() { visible=true }; + ComboBoxText combobox = new ComboBoxText(); combobox.append("default", get_notify_setting_string(Conversation.NotifySetting.DEFAULT, conversation.get_notification_default_setting(stream_interactor))); combobox.append("highlight", get_notify_setting_string(Conversation.NotifySetting.HIGHLIGHT)); combobox.append("on", get_notify_setting_string(Conversation.NotifySetting.ON)); @@ -119,7 +119,7 @@ public class SettingsProvider : Plugins.ContactDetailsProvider, Object { private ComboBoxText get_combobox(bool default_val) { ComboBoxText combobox = new ComboBoxText(); - combobox = new ComboBoxText() { visible=true }; + combobox = new ComboBoxText(); string default_setting = default_val ? _("On") : _("Off"); combobox.append("default", _("Default: %s").printf(default_setting) ); combobox.append("on", _("On")); diff --git a/main/src/ui/conversation_content/conversation_item_factory.vala b/main/src/ui/conversation_content/conversation_item_factory.vala deleted file mode 100644 index 29a83785..00000000 --- a/main/src/ui/conversation_content/conversation_item_factory.vala +++ /dev/null @@ -1,36 +0,0 @@ -using Gtk; - -namespace Dino.Ui { - - public static ListItemFactory get_item_factory() { - SignalListItemFactory item_factory = new SignalListItemFactory(); - item_factory.setup.connect((list_item) => { on_setup(list_item); }); - item_factory.bind.connect((list_item) => { on_bind(list_item); }); - return item_factory; - } - - public static void on_setup(ListItem listitem) { - listitem.child = new ConversationItemWidget(); - } - - public static void on_bind(ListItem listitem) { - MessageViewModel view_model = (MessageViewModel) listitem.get_item(); - ConversationItemWidget view = (ConversationItemWidget) listitem.get_child(); - - view_model.bind_property("name", view.name_label, "label", BindingFlags.SYNC_CREATE); - view_model.bind_property("time", view.time_label, "label", BindingFlags.SYNC_CREATE); - - Label? label = view.content_widget as Label; - if (label == null) { - label = new Label("") { use_markup=true, xalign=0, selectable=true, wrap=true, wrap_mode=Pango.WrapMode.WORD_CHAR, hexpand=true, vexpand=true }; - view.set_content_widget(label); - } - view_model.bind_property("message", label, "label", BindingFlags.SYNC_CREATE); - - view_model.bind_property("encryption-icon-name", view.encrypted_image, "icon-name", BindingFlags.SYNC_CREATE); - view_model.bind_property("encryption-icon-tooltip", view.encrypted_image, "tooltip-text", BindingFlags.SYNC_CREATE); - - view_model.bind_property("marked-icon-name", view.marked_image, "icon-name", BindingFlags.SYNC_CREATE); - view_model.bind_property("marked-icon-tooltip", view.marked_image, "tooltip-text", BindingFlags.SYNC_CREATE); - } -} \ No newline at end of file diff --git a/main/src/ui/conversation_content_view/call_widget.vala b/main/src/ui/conversation_content_view/call_widget.vala index 645c31c1..df4b7386 100644 --- a/main/src/ui/conversation_content_view/call_widget.vala +++ b/main/src/ui/conversation_content_view/call_widget.vala @@ -20,7 +20,7 @@ namespace Dino.Ui { public override Object? get_widget(Plugins.ConversationItemWidgetInterface outer, Plugins.WidgetType type) { CallItem call_item = content_item as CallItem; CallState? call_state = stream_interactor.get_module(Calls.IDENTITY).call_states[call_item.call]; - return new CallWidget(stream_interactor, call_item.call, call_state, call_item.conversation) { visible=true }; + return new CallWidget(stream_interactor, call_item.call, call_state, call_item.conversation); } public override Gee.List? get_item_actions(Plugins.WidgetType type) { return null; } @@ -94,17 +94,17 @@ namespace Dino.Ui { } foreach (Jid counterpart in call.counterparts) { - AvatarImage image = new AvatarImage() { force_gray=true, margin_top=2, visible=true }; + AvatarImage image = new AvatarImage() { force_gray=true, margin_top=2 }; image.set_conversation_participant(stream_interactor, conversation, counterpart.bare_jid); multiparty_peer_box.append(image); multiparty_peer_widgets.add(image); } - AvatarImage image2 = new AvatarImage() { force_gray=true, margin_top=2, visible=true }; + AvatarImage image2 = new AvatarImage() { force_gray=true, margin_top=2 }; image2.set_conversation_participant(stream_interactor, conversation, call.account.bare_jid); multiparty_peer_box.append(image2); multiparty_peer_widgets.add(image2); - outer_additional_box.get_style_context().add_class("multiparty-participants"); + outer_additional_box.add_css_class("multiparty-participants"); multiparty_peer_box.visible = true; incoming_call_box.visible = false; @@ -113,8 +113,8 @@ namespace Dino.Ui { private void update_call_state() { incoming_call_revealer.reveal_child = false; - incoming_call_revealer.get_style_context().remove_class("incoming"); - outer_additional_box.get_style_context().remove_class("incoming-call-box"); + incoming_call_revealer.remove_css_class("incoming"); + outer_additional_box.remove_css_class("incoming-call-box"); // It doesn't make sense to display MUC calls as missed or declined by the whole MUC. Just display as ended. // TODO: maybe not let them be missed/declined in first place. @@ -139,8 +139,8 @@ namespace Dino.Ui { subtitle_label.label = "Ring ring…!"; incoming_call_box.visible = true; incoming_call_revealer.reveal_child = true; - incoming_call_revealer.get_style_context().add_class("incoming"); - outer_additional_box.get_style_context().add_class("incoming-call-box"); + incoming_call_revealer.add_css_class("incoming"); + outer_additional_box.add_css_class("incoming-call-box"); } else { subtitle_label.label = "Dependencies for call support not met"; } diff --git a/main/src/ui/conversation_content_view/chat_state_populator.vala b/main/src/ui/conversation_content_view/chat_state_populator.vala index 0665caac..803739c8 100644 --- a/main/src/ui/conversation_content_view/chat_state_populator.vala +++ b/main/src/ui/conversation_content_view/chat_state_populator.vala @@ -77,11 +77,11 @@ private class MetaChatStateItem : Plugins.MetaConversationItem { } public override Object? get_widget(Plugins.ConversationItemWidgetInterface outer, Plugins.WidgetType widget_type) { - label = new Label("") { xalign=0, vexpand=true, visible=true }; - label.get_style_context().add_class("dim-label"); - image = new AvatarImage() { margin_top=2, valign=Align.START, visible=true }; + label = new Label("") { xalign=0, vexpand=true }; + label.add_css_class("dim-label"); + image = new AvatarImage() { margin_top=2, valign=Align.START }; - Box image_content_box = new Box(Orientation.HORIZONTAL, 8) { visible=true }; + Box image_content_box = new Box(Orientation.HORIZONTAL, 8); image_content_box.append(image); image_content_box.append(label); diff --git a/main/src/ui/conversation_content_view/conversation_item_skeleton.vala b/main/src/ui/conversation_content_view/conversation_item_skeleton.vala index 3e4ce88b..ae2d835f 100644 --- a/main/src/ui/conversation_content_view/conversation_item_skeleton.vala +++ b/main/src/ui/conversation_content_view/conversation_item_skeleton.vala @@ -18,7 +18,12 @@ public class ConversationItemSkeleton : Plugins.ConversationItemWidgetInterface, public Widget? content_widget = null; - public bool show_skeleton { get; set; default=false; } + private bool show_skeleton_ = false; + public bool show_skeleton { + get { return show_skeleton_; } + set { + show_skeleton_ = value && content_meta_item != null && content_meta_item.requires_header && content_meta_item.requires_avatar; } + } public bool last_group_item { get; set; default=true; } public StreamInteractor stream_interactor; @@ -26,7 +31,7 @@ public class ConversationItemSkeleton : Plugins.ConversationItemWidgetInterface, public Plugins.MetaConversationItem item; public bool item_in_edit_mode { get; set; } public Entities.Message.Marked item_mark { get; set; } - public ContentMetaItem? content_meta_item = null; + public ContentMetaItem content_meta_item = null; public Widget? widget = null; private uint time_update_timeout = 0; @@ -40,7 +45,7 @@ public class ConversationItemSkeleton : Plugins.ConversationItemWidgetInterface, Builder builder = new Builder.from_resource("/im/dino/Dino/conversation_item_widget.ui"); main_grid = (Grid) builder.get_object("main_grid"); - main_grid.get_style_context().add_class("message-box"); + main_grid.add_css_class("message-box"); name_label = (Label) builder.get_object("name_label"); time_label = (Label) builder.get_object("time_label"); avatar_image = (AvatarImage) builder.get_object("avatar_image"); @@ -65,7 +70,7 @@ public class ConversationItemSkeleton : Plugins.ConversationItemWidgetInterface, } private void set_header() { - if (!show_skeleton || !item.requires_header) return; + if (!show_skeleton) return; update_name_label(); // name_label.style_updated.connect(update_name_label); @@ -102,34 +107,32 @@ public class ConversationItemSkeleton : Plugins.ConversationItemWidgetInterface, encryption_image.visible = show_skeleton; received_image.visible = show_skeleton; - if (show_skeleton) { - main_grid.get_style_context().add_class("has-skeleton"); + if (show_skeleton || content_meta_item == null) { + main_grid.add_css_class("has-skeleton"); } if (last_group_item) { - main_grid.get_style_context().add_class("last-group-item"); + main_grid.add_css_class("last-group-item"); } } private void update_edit_mode() { if (item.in_edit_mode) { - main_grid.get_style_context().add_class("edit-mode"); + main_grid.add_css_class("edit-mode"); } else { - main_grid.get_style_context().remove_class("edit-mode"); + main_grid.remove_css_class("edit-mode"); } } private void update_error_mode() { if (item_mark == Message.Marked.ERROR) { - main_grid.get_style_context().add_class("error"); + main_grid.add_css_class("error"); } else { - main_grid.get_style_context().remove_class("error"); + main_grid.remove_css_class("error"); } } private void update_encryption_icon() { - encryption_image.visible = true; - Application app = GLib.Application.get_default() as Application; ContentMetaItem ci = item as ContentMetaItem; @@ -141,7 +144,8 @@ public class ConversationItemSkeleton : Plugins.ConversationItemWidgetInterface, break; } } - encryption_image.icon_name = icon_name ?? "dino-changes-prevent-symbolic"; + encryption_image.icon_name = icon_name ?? "changes-prevent-symbolic"; + encryption_image.visible = true; } if (item.encryption == Encryption.NONE) { @@ -149,6 +153,7 @@ public class ConversationItemSkeleton : Plugins.ConversationItemWidgetInterface, encryption_image.icon_name = "dino-changes-allowed-symbolic"; encryption_image.tooltip_text = _("Unencrypted"); Util.force_error_color(encryption_image); + encryption_image.visible = true; } else if (conversation.encryption == Encryption.NONE) { encryption_image.icon_name = null; encryption_image.visible = false; @@ -176,8 +181,11 @@ public class ConversationItemSkeleton : Plugins.ConversationItemWidgetInterface, case Message.Marked.READ: received_image.icon_name = "dino-double-tick-symbolic"; break; case Message.Marked.WONTSEND: received_image.icon_name = "dialog-warning-symbolic"; - received_image.icon_name = _("Unable to send message"); - // TODO error color on marked icon and time + Util.force_error_color(received_image); + Util.force_error_color(time_label); + string error_text = _("Unable to send message"); + received_image.tooltip_text = error_text; + time_label.tooltip_text = error_text; break; default: received_image.icon_name = null; break; } diff --git a/main/src/ui/conversation_content_view/conversation_view.vala b/main/src/ui/conversation_content_view/conversation_view.vala index 8d46281f..bfee3cbb 100644 --- a/main/src/ui/conversation_content_view/conversation_view.vala +++ b/main/src/ui/conversation_content_view/conversation_view.vala @@ -108,7 +108,7 @@ public class ConversationView : Widget, Plugins.ConversationItemCollection, Plug private void on_leave_notify_event() { if (currently_highlighted != null) { - currently_highlighted.get_style_context().remove_class("highlight"); + currently_highlighted.remove_css_class("highlight"); currently_highlighted = null; } message_menu_box.visible = false; @@ -134,7 +134,7 @@ public class ConversationView : Widget, Plugins.ConversationItemCollection, Plug } }; - if (currently_highlighted != null) currently_highlighted.get_style_context().remove_class("highlight"); + if (currently_highlighted != null) currently_highlighted.remove_css_class("highlight"); currently_highlighted = null; current_meta_item = null; @@ -160,7 +160,7 @@ public class ConversationView : Widget, Plugins.ConversationItemCollection, Plug if (current_meta_item != null) { // Highlight widget currently_highlighted = w; - currently_highlighted.get_style_context().add_class("highlight"); + currently_highlighted.add_css_class("highlight"); // Move message menu message_menu_box.margin_top = (int)(widget_y - 10); @@ -233,7 +233,7 @@ public class ConversationView : Widget, Plugins.ConversationItemCollection, Plug i++; } scrolled.vadjustment.value = h - scrolled.vadjustment.page_size * 1/3; - w.get_style_context().add_class("highlight-once"); + w.add_css_class("highlight-once"); reload_messages = true; stack.set_visible_child_name("main"); return false; @@ -414,6 +414,7 @@ public class ConversationView : Widget, Plugins.ConversationItemCollection, Plug }); } } else if (scrolled.vadjustment.value < scrolled.vadjustment.upper - scrolled.vadjustment.page_size - 1) { + print("move!\n"); scrolled.vadjustment.value = scrolled.vadjustment.upper - was_upper + scrolled.vadjustment.value; // stay at same content } was_upper = scrolled.vadjustment.upper; diff --git a/main/src/ui/conversation_content_view/date_separator_populator.vala b/main/src/ui/conversation_content_view/date_separator_populator.vala index 40bf0693..25ef7a51 100644 --- a/main/src/ui/conversation_content_view/date_separator_populator.vala +++ b/main/src/ui/conversation_content_view/date_separator_populator.vala @@ -83,12 +83,12 @@ public class DateSeparatorWidget : Box { visible = true; this.date = date; - label = new Label("") { use_markup=true, halign=Align.CENTER, hexpand=false, visible=true }; - label.get_style_context().add_class("dim-label"); + label = new Label("") { use_markup=true, halign=Align.CENTER, hexpand=false }; + label.add_css_class("dim-label"); - this.append(new Separator(Orientation.HORIZONTAL) { valign=Align.CENTER, hexpand=true, visible=true }); + this.append(new Separator(Orientation.HORIZONTAL) { valign=Align.CENTER, hexpand=true }); this.append(label); - this.append(new Separator(Orientation.HORIZONTAL) { valign=Align.CENTER, hexpand=true, visible=true }); + this.append(new Separator(Orientation.HORIZONTAL) { valign=Align.CENTER, hexpand=true }); update_time(); } 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 3bd5842f..9efc130f 100644 --- a/main/src/ui/conversation_content_view/file_default_widget.vala +++ b/main/src/ui/conversation_content_view/file_default_widget.vala @@ -9,6 +9,7 @@ namespace Dino.Ui { [GtkTemplate (ui = "/im/dino/Dino/file_default_widget.ui")] public class FileDefaultWidget : Box { + public signal void clicked(); public signal void open_file(); public signal void save_file_as(); public signal void cancel_download(); @@ -35,6 +36,7 @@ public class FileDefaultWidget : Box { this_motion_events.leave.connect(on_pointer_left_event); GestureClick gesture_click_controller = new GestureClick(); + gesture_click_controller.set_button(1); // listen for left clicks this.add_controller(gesture_click_controller); gesture_click_controller.pressed.connect((n_press, x, y) => { // Check whether the click was inside the file menu. Otherwise, open the file. @@ -42,7 +44,7 @@ public class FileDefaultWidget : Box { this.translate_coordinates(file_menu, x, y, out x_button, out y_button); if (file_menu.contains(x_button, y_button)) return; - this.open_file(); + this.clicked(); }); } 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 aad220e8..285e397e 100644 --- a/main/src/ui/conversation_content_view/file_image_widget.vala +++ b/main/src/ui/conversation_content_view/file_image_widget.vala @@ -15,7 +15,7 @@ public class FileImageWidget : Box { public FileImageWidget() { this.halign = Align.START; - this.get_style_context().add_class("file-image-widget"); + this.add_css_class("file-image-widget"); } public async void load_from_file(File file, string file_name, int MAX_WIDTH=600, int MAX_HEIGHT=300) throws GLib.Error { @@ -52,7 +52,7 @@ public class FileImageWidget : Box { file_default_widget_controller = new FileDefaultWidgetController(file_default_widget); file_default_widget_controller.set_file(file, file_name, mime_type); - Overlay overlay = new Overlay() { visible=true }; + Overlay overlay = new Overlay(); overlay.set_child(image); overlay.add_overlay(file_default_widget); overlay.set_measure_overlay(image, true); diff --git a/main/src/ui/conversation_content_view/file_widget.vala b/main/src/ui/conversation_content_view/file_widget.vala index 6378c298..8dbc3dc8 100644 --- a/main/src/ui/conversation_content_view/file_widget.vala +++ b/main/src/ui/conversation_content_view/file_widget.vala @@ -19,7 +19,7 @@ public class FileMetaItem : ConversationSummary.ContentMetaItem { public override Object? get_widget(Plugins.ConversationItemWidgetInterface outer, Plugins.WidgetType type) { FileItem file_item = content_item as FileItem; FileTransfer transfer = file_item.file_transfer; - return new FileWidget(stream_interactor, transfer) { visible=true }; + return new FileWidget(stream_interactor, transfer); } public override Gee.List? get_item_actions(Plugins.WidgetType type) { return null; } @@ -70,7 +70,7 @@ public class FileWidget : SizeRequestBox { FileImageWidget file_image_widget = null; try { - file_image_widget = new FileImageWidget() { visible=true }; + file_image_widget = new FileImageWidget(); yield file_image_widget.load_from_file(file_transfer.get_file(), file_transfer.file_name); // If the widget changed in the meanwhile, stop @@ -86,7 +86,7 @@ public class FileWidget : SizeRequestBox { if (state != State.DEFAULT) { if (content != null) this.remove(content); - FileDefaultWidget default_file_widget = new FileDefaultWidget() { visible=true }; + FileDefaultWidget default_file_widget = new FileDefaultWidget(); default_widget_controller = new FileDefaultWidgetController(default_file_widget); default_widget_controller.set_file_transfer(file_transfer, stream_interactor); content = default_file_widget; @@ -129,14 +129,10 @@ public class FileDefaultWidgetController : Object { public FileDefaultWidgetController(FileDefaultWidget widget) { this.widget = widget; + widget.clicked.connect(on_clicked); widget.open_file.connect(open_file); widget.save_file_as.connect(save_file); widget.cancel_download.connect(cancel_download); - - var gesture_controller = new GestureClick(); - gesture_controller.set_button(1); // listen for left clicks - gesture_controller.released.connect(on_clicked); - widget.add_controller(gesture_controller); } public void set_file_transfer(FileTransfer file_transfer, StreamInteractor stream_interactor) { diff --git a/main/src/ui/conversation_content_view/message_item_widget.vala b/main/src/ui/conversation_content_view/message_item_widget.vala deleted file mode 100644 index 23a499d9..00000000 --- a/main/src/ui/conversation_content_view/message_item_widget.vala +++ /dev/null @@ -1,229 +0,0 @@ -using Dino.Entities; -using Gtk; - -namespace Dino.Ui { - public class MessageItemWidget : SizeRequestBin { - - public signal void edit_cancelled(); - public signal void edit_sent(string text); - - enum AdditionalInfo { - NONE, - PENDING, - DELIVERY_FAILED - } - - StreamInteractor stream_interactor; - public ContentItem content_item; - public Message.Marked marked { get; set; } - - Label label = new Label("") { use_markup=true, xalign=0, selectable=true, wrap=true, wrap_mode=Pango.WrapMode.WORD_CHAR, vexpand=true, visible=true }; - MessageItemEditMode? edit_mode = null; - ChatTextViewController? controller = null; - AdditionalInfo additional_info = AdditionalInfo.NONE; - - ulong realize_id = -1; - ulong style_updated_id = -1; - ulong marked_notify_handler_id = -1; - - construct { - this.append(label); - label.activate_link.connect(on_label_activate_link); - this.size_request_mode = SizeRequestMode.HEIGHT_FOR_WIDTH; - } - - public MessageItemWidget(StreamInteractor stream_interactor, ContentItem content_item) { - this.stream_interactor = stream_interactor; - this.content_item = content_item; - - Message message = ((MessageItem) content_item).message; - if (message.direction == Message.DIRECTION_SENT && !(message.marked in Message.MARKED_RECEIVED)) { - var binding = message.bind_property("marked", this, "marked"); - marked_notify_handler_id = this.notify["marked"].connect(() => { - // Currently "pending", but not anymore - if (additional_info == AdditionalInfo.PENDING && - message.marked != Message.Marked.SENDING && message.marked != Message.Marked.UNSENT) { - update_label(); - } - - // Currently "error", but not anymore - if (additional_info == AdditionalInfo.DELIVERY_FAILED && message.marked != Message.Marked.ERROR) { - update_label(); - } - - // Currently not error, but should be - if (additional_info != AdditionalInfo.DELIVERY_FAILED && message.marked == Message.Marked.ERROR) { - update_label(); - } - - // Nothing bad can happen anymore - if (message.marked in Message.MARKED_RECEIVED) { - binding.unbind(); - this.disconnect(marked_notify_handler_id); - } - }); - } - - update_label(); - } - - public void set_edit_mode() { - - MessageItem message_item = content_item as MessageItem; - Message message = message_item.message; - - if (edit_mode == null) { - edit_mode = new MessageItemEditMode(); - controller = new ChatTextViewController(edit_mode.chat_text_view, stream_interactor); - Conversation conversation = message_item.conversation; - controller.initialize_for_conversation(conversation); - - edit_mode.cancelled.connect(() => { - edit_cancelled(); - unset_edit_mode(); - }); - edit_mode.send.connect(() => { - if (((MessageItem) content_item).message.body != edit_mode.chat_text_view.text_view.buffer.text) { - edit_sent(edit_mode.chat_text_view.text_view.buffer.text); - } else { - edit_cancelled(); - } - unset_edit_mode(); - }); - } - - edit_mode.chat_text_view.text_view.buffer.text = message.body; - - this.remove(label); - this.append(edit_mode); - - edit_mode.chat_text_view.text_view.grab_focus(); - } - - public void unset_edit_mode() { - this.remove(edit_mode); - this.append(label); - label.grab_focus(); - label.selectable = false; - label.selectable = true; - } - - public void update_label() { - label.label = generate_markup_text(content_item); - } - - private string generate_markup_text(ContentItem item) { - MessageItem message_item = item as MessageItem; - Conversation conversation = message_item.conversation; - Message message = message_item.message; - - bool theme_dependent = false; - - string markup_text = message.body; - if (markup_text.length > 10000) { - markup_text = markup_text.substring(0, 10000) + " [" + _("Message too long") + "]"; - } - if (message.body.has_prefix("/me ")) { - markup_text = markup_text.substring(4); - } - - if (conversation.type_ == Conversation.Type.GROUPCHAT) { - markup_text = Util.parse_add_markup_theme(markup_text, conversation.nickname, true, true, true, Util.is_dark_theme(this), ref theme_dependent); - } else { - markup_text = Util.parse_add_markup_theme(markup_text, null, true, true, true, Util.is_dark_theme(this), ref theme_dependent); - } - - if (message.body.has_prefix("/me ")) { - string display_name = Util.get_participant_display_name(stream_interactor, conversation, message.from); - markup_text = @"$(Markup.escape_text(display_name)) " + markup_text + ""; - } - - int only_emoji_count = Util.get_only_emoji_count(markup_text); - if (only_emoji_count != -1) { - string size_str = only_emoji_count < 5 ? "xx-large" : "large"; - markup_text = @"" + markup_text + ""; - } - - string dim_color = Util.is_dark_theme(this) ? "#BDBDBD" : "#707070"; - - if (message.edit_to != null) { - markup_text += @" (%s)".printf(_("edited")); - theme_dependent = true; - } - - // Append message status info - additional_info = AdditionalInfo.NONE; - if (message.direction == Message.DIRECTION_SENT && (message.marked == Message.Marked.SENDING || message.marked == Message.Marked.UNSENT)) { - // Append "pending..." iff message has not been sent yet - if (message.time.compare(new DateTime.now_utc().add_seconds(-10)) < 0) { - markup_text += @" %s".printf(_("pending…")); - theme_dependent = true; - additional_info = AdditionalInfo.PENDING; - } else { - int time_diff = (- (int) message.time.difference(new DateTime.now_utc()) / 1000); - Timeout.add(10000 - time_diff, () => { - update_label(); - return false; - }); - } - } else if (message.direction == Message.DIRECTION_SENT && message.marked == Message.Marked.ERROR) { - // Append "delivery failed" if there was a server error - string error_color = Util.rgba_to_hex(Util.get_label_pango_color(label, "@error_color")); - markup_text += " %s".printf(error_color, _("delivery failed")); - theme_dependent = true; - additional_info = AdditionalInfo.DELIVERY_FAILED; - } - - if (theme_dependent && realize_id == -1) { - realize_id = label.realize.connect(update_label); - // style_updated_id = label.style_updated.connect(update_label); - } else if (!theme_dependent && realize_id != -1) { - label.disconnect(realize_id); - label.disconnect(style_updated_id); - } - return markup_text; - } - - public static bool on_label_activate_link(string uri) { - // Always handle xmpp URIs with Dino - if (!uri.has_prefix("xmpp:")) return false; - File file = File.new_for_uri(uri); - Dino.Application.get_default().open(new File[]{file}, ""); - return true; - } - } - - [GtkTemplate (ui = "/im/dino/Dino/message_item_widget_edit_mode.ui")] - public class MessageItemEditMode : Box { - - public signal void cancelled(); - public signal void send(); - - [GtkChild] public unowned MenuButton emoji_button; - [GtkChild] public unowned ChatTextView chat_text_view; - [GtkChild] public unowned Button cancel_button; - [GtkChild] public unowned Button send_button; - [GtkChild] public unowned Frame frame; - - construct { - Util.force_css(frame, "* { border-radius: 3px; }"); - - EmojiChooser chooser = new EmojiChooser(); - chooser.emoji_picked.connect((emoji) => { - chat_text_view.text_view.buffer.insert_at_cursor(emoji, emoji.data.length); - }); - emoji_button.set_popover(chooser); - - chat_text_view.text_view.buffer.changed.connect_after(on_text_view_changed); - - cancel_button.clicked.connect(() => cancelled()); - send_button.clicked.connect(() => send()); - chat_text_view.cancel_input.connect(() => cancelled()); - chat_text_view.send_text.connect(() => send()); - } - - private void on_text_view_changed() { - send_button.sensitive = chat_text_view.text_view.buffer.text != ""; - } - } -} \ No newline at end of file diff --git a/main/src/ui/conversation_content_view/message_widget.vala b/main/src/ui/conversation_content_view/message_widget.vala index 3ebce0ee..346a6f71 100644 --- a/main/src/ui/conversation_content_view/message_widget.vala +++ b/main/src/ui/conversation_content_view/message_widget.vala @@ -28,7 +28,7 @@ public class MessageMetaItem : ContentMetaItem { ulong style_updated_id = -1; ulong marked_notify_handler_id = -1; - public Label label = new Label("") { use_markup=true, xalign=0, selectable=true, wrap=true, wrap_mode=Pango.WrapMode.WORD_CHAR, hexpand=true, vexpand=true, can_focus=false }; + public Label label = new Label("") { use_markup=true, xalign=0, selectable=true, wrap=true, wrap_mode=Pango.WrapMode.WORD_CHAR, hexpand=true, vexpand=true }; public MessageMetaItem(ContentItem content_item, StreamInteractor stream_interactor) { base(content_item); diff --git a/main/src/ui/conversation_content_view/subscription_notification.vala b/main/src/ui/conversation_content_view/subscription_notification.vala index 1f0f39d8..b825f4ad 100644 --- a/main/src/ui/conversation_content_view/subscription_notification.vala +++ b/main/src/ui/conversation_content_view/subscription_notification.vala @@ -33,9 +33,9 @@ public class SubscriptionNotitication : Object { } private void show_notification() { - Box box = new Box(Orientation.HORIZONTAL, 5) { visible=true }; - Button accept_button = new Button.with_label(_("Accept")) { visible=true }; - Button deny_button = new Button.with_label(_("Deny")) { visible=true }; + Box box = new Box(Orientation.HORIZONTAL, 5); + Button accept_button = new Button.with_label(_("Accept")); + Button deny_button = new Button.with_label(_("Deny")); GLib.Application app = GLib.Application.get_default(); accept_button.clicked.connect(() => { app.activate_action("accept-subscription", conversation.id); @@ -45,7 +45,7 @@ public class SubscriptionNotitication : Object { app.activate_action("deny-subscription", conversation.id); conversation_view.remove_notification(box); }); - box.append(new Label(_("This contact would like to add you to their contact list")) { margin_end=10, visible=true }); + box.append(new Label(_("This contact would like to add you to their contact list")) { margin_end=10 }); box.append(accept_button); box.append(deny_button); conversation_view.add_notification(box); diff --git a/main/src/ui/conversation_list/conversation_list_item_factory.vala b/main/src/ui/conversation_list/conversation_list_item_factory.vala deleted file mode 100644 index dc26d2f1..00000000 --- a/main/src/ui/conversation_list/conversation_list_item_factory.vala +++ /dev/null @@ -1,245 +0,0 @@ -using Gtk; -using Dino.Entities; -using Dino; -using Gee; -using Pango; -using Xmpp; - -namespace Dino.Ui.ConversationList { - - public static ListItemFactory get_item_factory() { - SignalListItemFactory item_factory = new SignalListItemFactory(); - item_factory.setup.connect((list_item) => { on_setup(list_item); }); - item_factory.bind.connect((list_item) => { on_bind(list_item); }); - return item_factory; - } - - public static void on_setup(ListItem listitem) { - listitem.child = new ConversationListRow(); - } - - public static void on_bind(ListItem listitem) { - ConversationViewModel list_model = (ConversationViewModel) listitem.get_item(); - ConversationListRow view = (ConversationListRow) listitem.get_child(); - StreamInteractor stream_interactor = list_model.stream_interactor; - - list_model.bind_property("name", view.name_label, "label"); - list_model.notify["latest-content-item"].connect((obj, _) => { - update_content_item(view, list_model.conversation, stream_interactor, ((ConversationViewModel) obj).latest_content_item); - }); - list_model.notify["unread-count"].connect((obj, _) => { - update_read(view, list_model.conversation, stream_interactor, (int) obj); - }); - - view.x_button.clicked.connect(() => list_model.closed() ); - - ConversationViewModel view_model = (ConversationViewModel) listitem.get_item(); - view.name_label.label = view_model.name; - if (view_model.latest_content_item != null) { - update_content_item(view, view_model.conversation, stream_interactor, view_model.latest_content_item); - } - update_read(view, view_model.conversation, stream_interactor, view_model.unread_count); - } - - private static void update_content_item(ConversationListRow view, Conversation conversation, StreamInteractor stream_interactor, ContentItem last_content_item) { - view.time_label.label = get_relative_time(last_content_item.time.to_local()); - view.image.set_conversation(stream_interactor, conversation); - - Label nick_label = view.nick_label; - Label message_label = view.message_label; - - switch (last_content_item.type_) { - case MessageItem.TYPE: - MessageItem message_item = last_content_item as MessageItem; - Message last_message = message_item.message; - - string body = last_message.body; - bool me_command = body.has_prefix("/me "); - - /* If we have a /me command, we always show the display - * name, and we don't set me_is_me on - * get_participant_display_name, since that will return - * "Me" (internationalized), whereas /me commands expect to - * be in the third person. We also omit the colon in this - * case, and strip off the /me prefix itself. */ - - if (conversation.type_ == Conversation.Type.GROUPCHAT || me_command) { - nick_label.label = Util.get_participant_display_name(stream_interactor, conversation, last_message.from, !me_command); - } else if (last_message.direction == Message.DIRECTION_SENT) { - nick_label.label = _("Me"); - } else { - nick_label.label = ""; - } - - if (me_command) { - /* Don't slice off the space after /me */ - body = body.slice("/me".length, body.length); - } else if (nick_label.label.length > 0) { - /* TODO: Is this valid for RTL languages? */ - nick_label.label += ": "; - } - - message_label.attributes.filter((attr) => attr.equal(attr_style_new(Pango.Style.ITALIC))); - message_label.label = Util.summarize_whitespaces_to_space(body); - - break; - case FileItem.TYPE: - FileItem file_item = last_content_item as FileItem; - FileTransfer transfer = file_item.file_transfer; - - if (conversation.type_ == Conversation.Type.GROUPCHAT) { - // TODO properly display nick for oneself - nick_label.label = Util.get_participant_display_name(stream_interactor, conversation, file_item.file_transfer.from, true) + ": "; - } else { - nick_label.label = transfer.direction == Message.DIRECTION_SENT ? _("Me") + ": " : ""; - } - - bool file_is_image = transfer.mime_type != null && transfer.mime_type.has_prefix("image"); - message_label.attributes.insert(attr_style_new(Pango.Style.ITALIC)); - if (transfer.direction == Message.DIRECTION_SENT) { - message_label.label = (file_is_image ? _("Image sent") : _("File sent") ); - } else { - message_label.label = (file_is_image ? _("Image received") : _("File received") ); - } - break; - case CallItem.TYPE: - CallItem call_item = (CallItem) last_content_item; - Call call = call_item.call; - - nick_label.label = call.direction == Call.DIRECTION_OUTGOING ? _("Me") + ": " : ""; - message_label.attributes.insert(attr_style_new(Pango.Style.ITALIC)); - message_label.label = call.direction == Call.DIRECTION_OUTGOING ? _("Outgoing call") : _("Incoming call"); - break; - } - nick_label.visible = true; - message_label.visible = true; - } - - private void update_read(ConversationListRow view, Conversation conversation, StreamInteractor stream_interactor, int num_unread) { - Label unread_count_label = view.unread_count_label; - Label name_label = view.name_label; - Label time_label = view.time_label; - Label nick_label = view.nick_label; - Label message_label = view.message_label; - if (num_unread == 0) { - unread_count_label.visible = false; - - name_label.attributes.filter((attr) => attr.equal(attr_weight_new(Weight.BOLD))); - time_label.attributes.filter((attr) => attr.equal(attr_weight_new(Weight.BOLD))); - nick_label.attributes.filter((attr) => attr.equal(attr_weight_new(Weight.BOLD))); - message_label.attributes.filter((attr) => attr.equal(attr_weight_new(Weight.BOLD))); - } else { - unread_count_label.label = num_unread.to_string(); - unread_count_label.visible = true; - - if (conversation.get_notification_setting(stream_interactor) == Conversation.NotifySetting.ON) { - unread_count_label.get_style_context().add_class("unread-count-notify"); - unread_count_label.get_style_context().remove_class("unread-count"); - } else { - unread_count_label.get_style_context().add_class("unread-count"); - unread_count_label.get_style_context().remove_class("unread-count-notify"); - } - - name_label.attributes.insert(attr_weight_new(Weight.BOLD)); - time_label.attributes.insert(attr_weight_new(Weight.BOLD)); - nick_label.attributes.insert(attr_weight_new(Weight.BOLD)); - message_label.attributes.insert(attr_weight_new(Weight.BOLD)); - } - - name_label.label = name_label.label; // TODO initializes redrawing, which would otherwise not happen. nicer? - time_label.label = time_label.label; - nick_label.label = nick_label.label; - message_label.label = message_label.label; - } - - private Widget generate_tooltip(StreamInteractor stream_interactor, Conversation conversation) { - Grid grid = new Grid() { row_spacing=5, column_homogeneous=false, column_spacing=5, margin_start=7, margin_end=7, margin_top=7, margin_bottom=7 }; - - Label label = new Label(conversation.counterpart.to_string()) { valign=Align.START, xalign=0, visible=true }; - label.attributes = new AttrList(); - label.attributes.insert(attr_weight_new(Weight.BOLD)); - - grid.attach(label, 0, 0, 2, 1); - - Gee.List? full_jids = stream_interactor.get_module(PresenceManager.IDENTITY).get_full_jids(conversation.counterpart, conversation.account); - if (full_jids == null) return grid; - - for (int i = 0; i < full_jids.size; i++) { - Jid full_jid = full_jids[i]; - string? show = stream_interactor.get_module(PresenceManager.IDENTITY).get_last_show(full_jid, conversation.account); - if (show == null) continue; - - int i_cache = i; - stream_interactor.get_module(EntityInfo.IDENTITY).get_identity.begin(conversation.account, full_jid, (_, res) => { - Xep.ServiceDiscovery.Identity? identity = stream_interactor.get_module(EntityInfo.IDENTITY).get_identity.end(res); - - Image image = new Image() { hexpand=false, valign=Align.CENTER, visible=true }; - if (identity != null && (identity.type_ == Xep.ServiceDiscovery.Identity.TYPE_PHONE || identity.type_ == Xep.ServiceDiscovery.Identity.TYPE_TABLET)) { - image.set_from_icon_name("dino-device-phone-symbolic"); - } else { - image.set_from_icon_name("dino-device-desktop-symbolic"); - } - - if (show == Presence.Stanza.SHOW_AWAY) { - Util.force_color(image, "#FF9800"); - } else if (show == Presence.Stanza.SHOW_XA || show == Presence.Stanza.SHOW_DND) { - Util.force_color(image, "#FF5722"); - } else { - Util.force_color(image, "#4CAF50"); - } - - string? status = null; - if (show == Presence.Stanza.SHOW_AWAY) { - status = "away"; - } else if (show == Presence.Stanza.SHOW_XA) { - status = "not available"; - } else if (show == Presence.Stanza.SHOW_DND) { - status = "do not disturb"; - } - - var sb = new StringBuilder(); - if (identity != null && identity.name != null) { - sb.append(identity.name); - } else if (full_jid.resourcepart != null) { - sb.append(full_jid.resourcepart); - } else { - return; - } - if (status != null) { - sb.append(" (").append(status).append(")"); - } - - Label resource = new Label(sb.str) { use_markup=true, hexpand=true, xalign=0, visible=true }; - - grid.attach(image, 0, i_cache + 1, 1, 1); - grid.attach(resource, 1, i_cache + 1, 1, 1); - }); - } - return grid; - } - - private static string get_relative_time(DateTime datetime) { - DateTime now = new DateTime.now_local(); - TimeSpan timespan = now.difference(datetime); - if (timespan > 365 * TimeSpan.DAY) { - return datetime.get_year().to_string(); - } else if (timespan > 7 * TimeSpan.DAY) { - // Day and month - // xgettext:no-c-format - return datetime.format(_("%b %d")); - } else if (timespan > 2 * TimeSpan.DAY) { - return datetime.format("%a"); - } else if (datetime.get_day_of_month() != now.get_day_of_month()) { - return _("Yesterday"); - } else if (timespan > 9 * TimeSpan.MINUTE) { - return datetime.format(Util.is_24h_format() ? - /* xgettext:no-c-format */ /* Time in 24h format (w/o seconds) */ _("%H∶%M") : - /* xgettext:no-c-format */ /* Time in 12h format (w/o seconds) */ _("%l∶%M %p")); - } else if (timespan > 1 * TimeSpan.MINUTE) { - ulong mins = (ulong) (timespan.abs() / TimeSpan.MINUTE); - return n("%i min ago", "%i mins ago", mins).printf(mins); - } else { - return _("Just now"); - } - } -} \ No newline at end of file diff --git a/main/src/ui/conversation_list/conversation_list_model.vala b/main/src/ui/conversation_list/conversation_list_model.vala deleted file mode 100644 index 9412e64a..00000000 --- a/main/src/ui/conversation_list/conversation_list_model.vala +++ /dev/null @@ -1,141 +0,0 @@ -using Gtk; -using Dino.Entities; -using Dino; -using Gee; -using Xmpp; - -public class Dino.Ui.ConversationViewModel : Object { - public signal void closed(); - - public StreamInteractor stream_interactor { get; set; } - public Conversation conversation { get; set; } - public string name { get; set; } - public ContentItem? latest_content_item { get; set; } - public int unread_count { get; set; } -} - -public class Dino.Ui.ConversationListModel : Object, ListModel { - - public signal void closed_conversation(Conversation conversation); - - private HashMap conversation_view_model_hm = new HashMap(Conversation.hash_func, Conversation.equals_func); - private ArrayList view_models = new ArrayList(); - private StreamInteractor stream_interactor; - - public ConversationListModel(StreamInteractor stream_interactor) { - this.stream_interactor = stream_interactor; - - stream_interactor.get_module(ConversationManager.IDENTITY).conversation_activated.connect(add_conversation); - stream_interactor.get_module(ConversationManager.IDENTITY).conversation_deactivated.connect(remove_conversation); - stream_interactor.get_module(ContentItemStore.IDENTITY).new_item.connect(on_content_item_received); - - foreach (Conversation conversation in stream_interactor.get_module(ConversationManager.IDENTITY).get_active_conversations()) { - var view_model = create_view_model(conversation); - view_models.add(view_model); - conversation_view_model_hm[conversation] = view_model; - } - view_models.sort(sort); - items_changed(0, 0, get_n_items()); - - stream_interactor.get_module(RosterManager.IDENTITY).updated_roster_item.connect((account, jid, roster_item) => { - ConversationViewModel? view_model = get_view_model(account, jid, Conversation.Type.CHAT); - if (view_model == null) return; - view_model.name = Util.get_conversation_display_name(stream_interactor, view_model.conversation); - }); - stream_interactor.get_module(MucManager.IDENTITY).room_info_updated.connect((account, jid) => { - ConversationViewModel? view_model = get_view_model(account, jid, Conversation.Type.GROUPCHAT); - if (view_model == null) return; - view_model.name = Util.get_conversation_display_name(stream_interactor, view_model.conversation); - // bubble color might have changed - view_model.unread_count = stream_interactor.get_module(ChatInteraction.IDENTITY).get_num_unread(view_model.conversation); - }); - stream_interactor.get_module(MucManager.IDENTITY).private_room_occupant_updated.connect((account, room, occupant) => { - ConversationViewModel? view_model = get_view_model(account, room.bare_jid, Conversation.Type.GROUPCHAT); - if (view_model == null) return; - view_model.name = Util.get_conversation_display_name(stream_interactor, view_model.conversation); - }); - } - - public GLib.Object? get_item (uint position) { - if (position >= view_models.size) return null; - return view_models[(int)position]; - } - - public GLib.Type get_item_type () { - return GLib.Type.OBJECT; - } - - public uint get_n_items () { - return view_models.size; - } - - private ConversationViewModel create_view_model(Conversation conversation) { - var view_model = new ConversationViewModel(); - view_model.stream_interactor = stream_interactor; - view_model.conversation = conversation; - view_model.name = Util.get_conversation_display_name(stream_interactor, conversation); - view_model.latest_content_item = stream_interactor.get_module(ContentItemStore.IDENTITY).get_latest(conversation); - view_model.unread_count = stream_interactor.get_module(ChatInteraction.IDENTITY).get_num_unread(conversation); - view_model.closed.connect(() => closed_conversation(conversation)); - - return view_model; - } - - private void add_conversation(Conversation conversation) { - var view_model = create_view_model(conversation); - - view_models.add(view_model); - conversation_view_model_hm[conversation] = view_model; - view_models.sort(sort); - - int idx = view_models.index_of(view_model); - items_changed(idx, 0, 1); - } - - private async void remove_conversation(Conversation conversation) { - ConversationViewModel? view_model = conversation_view_model_hm[conversation]; - if (view_model == null) return; - - int idx = view_models.index_of(view_model); - view_models.remove(view_model); - conversation_view_model_hm.unset(conversation); - items_changed(idx, 1, 0); - } - - private void on_content_item_received(ContentItem item, Conversation conversation) { - ConversationViewModel? view_model = conversation_view_model_hm[conversation]; - if (view_model == null) return; - - view_model.latest_content_item = stream_interactor.get_module(ContentItemStore.IDENTITY).get_latest(conversation); - view_model.unread_count = stream_interactor.get_module(ChatInteraction.IDENTITY).get_num_unread(conversation); - - view_models.sort(sort); - items_changed(0, view_models.size, view_models.size); // TODO better - } - - private ConversationViewModel? get_view_model(Account account, Jid jid, Conversation.Type? conversation_ty) { - foreach (ConversationViewModel view_model in view_models) { - Conversation conversation = view_model.conversation; - if (conversation.account.equals(account) && conversation.counterpart.equals(jid)) { - if (conversation_ty != null && conversation.type_ != conversation_ty) continue; - return view_model; - } - } - return null; - } - - private int sort(ConversationViewModel vm1, ConversationViewModel vm2) { - Conversation c1 = vm1.conversation; - Conversation c2 = vm2.conversation; - - if (c1 == null || c2 == null) return 0; - if (c1.last_active == null) return -1; - if (c2.last_active == null) return 1; - - int comp = c2.last_active.compare(c1.last_active); - if (comp != 0) return comp; - - return Util.get_conversation_display_name(stream_interactor, c1) - .collate(Util.get_conversation_display_name(stream_interactor, c2)); - } -} \ No newline at end of file diff --git a/main/src/ui/conversation_list/conversation_list_row.vala b/main/src/ui/conversation_list/conversation_list_row.vala deleted file mode 100644 index ab4e8cee..00000000 --- a/main/src/ui/conversation_list/conversation_list_row.vala +++ /dev/null @@ -1,41 +0,0 @@ -using Gee; -using Gdk; -using Gtk; -using Pango; - -using Dino; -using Dino.Entities; -using Xmpp; - -[GtkTemplate (ui = "/im/dino/Dino/conversation_row.ui")] -public class Dino.Ui.ConversationListRow : ListBoxRow { - - [GtkChild] public unowned AvatarImage image; - [GtkChild] public unowned Label name_label; - [GtkChild] public unowned Label time_label; - [GtkChild] public unowned Label nick_label; - [GtkChild] public unowned Label message_label; - [GtkChild] public unowned Label unread_count_label; - [GtkChild] public unowned Button x_button; - [GtkChild] public unowned Revealer time_revealer; - [GtkChild] public unowned Revealer xbutton_revealer; - [GtkChild] public unowned Revealer unread_count_revealer; - [GtkChild] public unowned Revealer main_revealer; - - construct { - name_label.attributes = new AttrList(); - } - - public override void state_flags_changed(StateFlags flags) { - StateFlags curr_flags = get_state_flags(); - if ((curr_flags & StateFlags.PRELIGHT) != 0) { - time_revealer.set_reveal_child(false); - unread_count_revealer.set_reveal_child(false); - xbutton_revealer.set_reveal_child(true); - } else { - time_revealer.set_reveal_child(true); - unread_count_revealer.set_reveal_child(true); - xbutton_revealer.set_reveal_child(false); - } - } -} \ No newline at end of file diff --git a/main/src/ui/conversation_selector/conversation_selector.vala b/main/src/ui/conversation_selector/conversation_selector.vala index 2e262bf1..609e1be1 100644 --- a/main/src/ui/conversation_selector/conversation_selector.vala +++ b/main/src/ui/conversation_selector/conversation_selector.vala @@ -1,3 +1,4 @@ +using Gdk; using Gee; using Gtk; @@ -18,7 +19,7 @@ public class ConversationSelector : Widget { public ConversationSelector init(StreamInteractor stream_interactor) { this.stream_interactor = stream_interactor; - list_box.insert_after(this, null); + list_box.set_parent(this); this.layout_manager = new BinLayout(); stream_interactor.get_module(ConversationManager.IDENTITY).conversation_activated.connect(add_conversation); @@ -36,7 +37,7 @@ public class ConversationSelector : Widget { } construct { - get_style_context().add_class("sidebar"); + add_css_class("sidebar"); list_box.set_header_func(header); list_box.set_sort_func(sort); @@ -78,36 +79,29 @@ public class ConversationSelector : Widget { rows[conversation] = row; list_box.append(row); row.main_revealer.set_reveal_child(true); -// drag_dest_set(row, DestDefaults.MOTION, null, Gdk.DragAction.COPY); -// drag_dest_set_track_motion(row, true); -// row.drag_motion.connect(this.on_drag_motion); -// row.drag_leave.connect(this.on_drag_leave); + + // Set up drag motion behaviour (select conversation after timeout) + DropControllerMotion drop_motion_controller = new DropControllerMotion(); + uint drag_timeout = 0; + drop_motion_controller.motion.connect((x, y) => { + if (drag_timeout != 0) return; + drag_timeout = Timeout.add(200, () => { + conversation_selected(conversation); + drag_timeout = 0; + return false; + }); + }); + drop_motion_controller.leave.connect(() => { + if (drag_timeout != 0) { + Source.remove(drag_timeout); + drag_timeout = 0; + } + }); + row.add_controller(drop_motion_controller); } list_box.invalidate_sort(); } - /*public bool on_drag_motion(Widget widget, Gdk.DragContext context, - int x, int y, uint time) { - if (this.drag_timeout != null) - return false; - this.drag_timeout = Timeout.add(200, () => { - if (widget.get_type().is_a(typeof(ConversationSelectorRow))) { - ConversationSelectorRow row = widget as ConversationSelectorRow; - conversation_selected(row.conversation); - } - this.drag_timeout = null; - return false; - }); - return false; - } - - public void on_drag_leave(Widget widget, Gdk.DragContext context, uint time) { - if (this.drag_timeout != null) { - Source.remove(this.drag_timeout); - this.drag_timeout = null; - } - }*/ - private void select_fallback_conversation(Conversation conversation) { if (list_box.get_selected_row() == rows[conversation]) { int index = rows[conversation].get_index(); diff --git a/main/src/ui/conversation_selector/conversation_selector_row.vala b/main/src/ui/conversation_selector/conversation_selector_row.vala index f813ddfc..76cbabb3 100644 --- a/main/src/ui/conversation_selector/conversation_selector_row.vala +++ b/main/src/ui/conversation_selector/conversation_selector_row.vala @@ -229,11 +229,11 @@ public class ConversationSelectorRow : ListBoxRow { unread_count_label.visible = true; if (conversation.get_notification_setting(stream_interactor) == Conversation.NotifySetting.ON) { - unread_count_label.get_style_context().add_class("unread-count-notify"); - unread_count_label.get_style_context().remove_class("unread-count"); + unread_count_label.add_css_class("unread-count-notify"); + unread_count_label.remove_css_class("unread-count"); } else { - unread_count_label.get_style_context().add_class("unread-count"); - unread_count_label.get_style_context().remove_class("unread-count-notify"); + unread_count_label.add_css_class("unread-count"); + unread_count_label.remove_css_class("unread-count-notify"); } name_label.attributes.insert(attr_weight_new(Weight.BOLD)); @@ -266,7 +266,7 @@ public class ConversationSelectorRow : ListBoxRow { private Widget generate_tooltip() { Grid grid = new Grid() { row_spacing=5, column_homogeneous=false, column_spacing=5, margin_start=7, margin_end=7, margin_top=7, margin_bottom=7 }; - Label label = new Label(conversation.counterpart.to_string()) { valign=Align.START, xalign=0, visible=true }; + Label label = new Label(conversation.counterpart.to_string()) { valign=Align.START, xalign=0 }; label.attributes = new AttrList(); label.attributes.insert(attr_weight_new(Weight.BOLD)); @@ -284,7 +284,7 @@ public class ConversationSelectorRow : ListBoxRow { stream_interactor.get_module(EntityInfo.IDENTITY).get_identity.begin(conversation.account, full_jid, (_, res) => { Xep.ServiceDiscovery.Identity? identity = stream_interactor.get_module(EntityInfo.IDENTITY).get_identity.end(res); - Image image = new Image() { hexpand=false, valign=Align.CENTER, visible=true }; + Image image = new Image() { hexpand=false, valign=Align.CENTER }; if (identity != null && (identity.type_ == Xep.ServiceDiscovery.Identity.TYPE_PHONE || identity.type_ == Xep.ServiceDiscovery.Identity.TYPE_TABLET)) { image.set_from_icon_name("dino-device-phone-symbolic"); } else { @@ -322,7 +322,7 @@ public class ConversationSelectorRow : ListBoxRow { sb.append(" (").append(status).append(")"); } - Label resource = new Label(sb.str) { use_markup=true, hexpand=true, xalign=0, visible=true }; + Label resource = new Label(sb.str) { use_markup=true, hexpand=true, xalign=0 }; grid.attach(image, 0, i_cache + 1, 1, 1); grid.attach(resource, 1, i_cache + 1, 1, 1); diff --git a/main/src/ui/conversation_titlebar/call_entry.vala b/main/src/ui/conversation_titlebar/call_entry.vala index 72376126..0a658b10 100644 --- a/main/src/ui/conversation_titlebar/call_entry.vala +++ b/main/src/ui/conversation_titlebar/call_entry.vala @@ -73,7 +73,6 @@ namespace Dino.Ui { } public new void set_conversation(Conversation conversation) { - print(@"set_conversation $(conversation.counterpart)\n"); this.conversation = conversation; update_visibility.begin(); diff --git a/main/src/ui/conversation_titlebar/conversation_titlebar.vala b/main/src/ui/conversation_titlebar/conversation_titlebar.vala index 0d13e48b..26fd9639 100644 --- a/main/src/ui/conversation_titlebar/conversation_titlebar.vala +++ b/main/src/ui/conversation_titlebar/conversation_titlebar.vala @@ -31,27 +31,27 @@ public class ConversationTitlebarNoCsd : ConversationTitlebar, Object { } } - private Box widgets_box = new Box(Orientation.HORIZONTAL, 0) { margin_start=15, valign=Align.END, visible=true }; - private Label title_label = new Label("") { ellipsize=EllipsizeMode.END, visible=true }; + private Box widgets_box = new Box(Orientation.HORIZONTAL, 7) { margin_start=15, valign=Align.END }; + private Label title_label = new Label("") { ellipsize=EllipsizeMode.END }; private Label subtitle_label = new Label("") { use_markup=true, ellipsize=EllipsizeMode.END, visible=false }; construct { - Box content_box = new Box(Orientation.HORIZONTAL, 0) { margin_start=15, margin_end=10, hexpand=true, visible=true }; + Box content_box = new Box(Orientation.HORIZONTAL, 0) { margin_start=15, margin_end=10, hexpand=true }; main.append(content_box); - Box titles_box = new Box(Orientation.VERTICAL, 0) { valign=Align.CENTER, hexpand=true, visible=true }; + Box titles_box = new Box(Orientation.VERTICAL, 0) { valign=Align.CENTER, hexpand=true }; content_box.append(titles_box); titles_box.append(title_label); subtitle_label.attributes = new AttrList(); - subtitle_label.get_style_context().add_class("dim-label"); + subtitle_label.add_css_class("dim-label"); titles_box.append(subtitle_label); content_box.append(widgets_box); } public ConversationTitlebarNoCsd() { - main.get_style_context().add_class("dino-header-right"); + main.add_css_class("dino-header-right"); } public void insert_button(Widget button) { @@ -79,7 +79,7 @@ public class ConversationTitlebarCsd : ConversationTitlebar, Object { titles_box.append(title_label); subtitle_label.attributes = new AttrList(); subtitle_label.attributes.insert(Pango.attr_scale_new(Pango.Scale.SMALL)); - subtitle_label.get_style_context().add_class("dim-label"); + subtitle_label.add_css_class("dim-label"); titles_box.append(subtitle_label); header_bar.set_title_widget(titles_box); diff --git a/main/src/ui/conversation_view.vala b/main/src/ui/conversation_view.vala index a51b2381..6e07b0e8 100644 --- a/main/src/ui/conversation_view.vala +++ b/main/src/ui/conversation_view.vala @@ -34,7 +34,7 @@ public class ConversationView : Widget { } public void add_overlay_dialog(Widget widget) { - Revealer revealer = new Revealer() { transition_type=RevealerTransitionType.CROSSFADE , transition_duration= 100, visible=true }; + Revealer revealer = new Revealer() { transition_type=RevealerTransitionType.CROSSFADE , transition_duration= 100 }; revealer.set_child(widget); overlay.add_overlay(revealer); @@ -43,7 +43,7 @@ public class ConversationView : Widget { white_revealer.visible = true; white_revealer.reveal_child = true; widget.destroy.connect(() => { - revealer.destroy(); // GTK4: this.remove_overlay(revealer); + overlay.remove_overlay(revealer); white_revealer.reveal_child = false; chat_input.do_focus(); }); diff --git a/main/src/ui/conversation_view_controller.vala b/main/src/ui/conversation_view_controller.vala index 759984c8..6786117c 100644 --- a/main/src/ui/conversation_view_controller.vala +++ b/main/src/ui/conversation_view_controller.vala @@ -6,15 +6,6 @@ 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 : Object { public new string? conversation_display_name { get; set; } @@ -26,6 +17,7 @@ public class ConversationViewController : Object { private ConversationTitlebar titlebar; public SearchMenuEntry search_menu_entry = new SearchMenuEntry(); public ListView list_view = new ListView(null, null); + private DropTarget drop_event_controller = new DropTarget(typeof(File), DragAction.COPY ); private ChatInputController chat_input_controller; private StreamInteractor stream_interactor; @@ -38,21 +30,29 @@ public class ConversationViewController : Object { this.app = GLib.Application.get_default() as Application; this.chat_input_controller = new ChatInputController(view.chat_input, stream_interactor); -// chat_input_controller.activate_last_message_correction.connect(view.conversation_frame.activate_last_message_correction); + chat_input_controller.activate_last_message_correction.connect(view.conversation_frame.activate_last_message_correction); chat_input_controller.file_picker_selected.connect(open_file_picker); chat_input_controller.clipboard_pasted.connect(on_clipboard_paste); view.conversation_frame.init(stream_interactor); // drag 'n drop file upload -// view.drag_data_received.connect(this.on_drag_data_received); + drop_event_controller.on_drop.connect(this.on_drag_data_received); // forward key presses -// view.chat_input.key_press_event.connect(forward_key_press_to_chat_input); -// view.conversation_frame.key_press_event.connect(forward_key_press_to_chat_input); -// titlebar.key_press_event.connect(forward_key_press_to_chat_input); + var key_controller = new EventControllerKey(); + key_controller.key_pressed.connect((v, c, s) => forward_key_press_to_chat_input(key_controller, v, c, s)); + view.conversation_frame.add_controller(key_controller); + + var key_controller2 = new EventControllerKey(); + key_controller2.key_pressed.connect((v, c, s) => forward_key_press_to_chat_input(key_controller2, v, c, s)); + view.chat_input.add_controller(key_controller2); + + var key_controller3 = new EventControllerKey(); + key_controller3.key_pressed.connect((v, c, s) => forward_key_press_to_chat_input(key_controller3, v, c, s)); + titlebar.get_widget().add_controller(key_controller3); -// goto-end floating button +// goto-end floating button var vadjustment = view.conversation_frame.scrolled.vadjustment; vadjustment.notify["value"].connect(() => { bool button_active = vadjustment.value < vadjustment.upper - vadjustment.page_size; @@ -102,17 +102,16 @@ public class ConversationViewController : Object { titlebar.insert_button(button); } -// AccelGroup accel_group = new AccelGroup(); -// accel_group.connect(Gdk.Key.U, ModifierType.CONTROL_MASK, AccelFlags.VISIBLE, () => { -// if (conversation == null) return false; -// stream_interactor.get_module(FileManager.IDENTITY).is_upload_available.begin(conversation, (_, res) => { -// if (stream_interactor.get_module(FileManager.IDENTITY).is_upload_available.end(res)) { -// open_file_picker(); -// } -// }); -// return false; -// }); -// ((Gtk.Window)view.get_toplevel()).add_accel_group(accel_group); + Shortcut shortcut = new Shortcut(new KeyvalTrigger(Key.U, ModifierType.CONTROL_MASK), new CallbackAction(() => { + if (conversation == null) return false; + stream_interactor.get_module(FileManager.IDENTITY).is_upload_available.begin(conversation, (_, res) => { + if (stream_interactor.get_module(FileManager.IDENTITY).is_upload_available.end(res)) { + open_file_picker(); + } + }); + return false; + })); + ((Gtk.Window)view.get_root()).add_shortcut(shortcut); } public void select_conversation(Conversation? conversation, bool default_initialize_conversation) { @@ -159,10 +158,14 @@ public class ConversationViewController : Object { stream_interactor.get_module(FileManager.IDENTITY).is_upload_available.begin(conversation, (_, res) => { bool upload_available = stream_interactor.get_module(FileManager.IDENTITY).is_upload_available.end(res); chat_input_controller.set_file_upload_active(upload_available); - if (upload_available && overlay_dialog == null) { -// Gtk.drag_dest_set(view, DestDefaults.ALL, target_list, Gdk.DragAction.COPY); + if (conversation.account.bare_jid.to_string().has_prefix("f")) { + if (drop_event_controller.widget == null) { + view.add_controller(drop_event_controller); + } } else { -// Gtk.drag_dest_unset(view); + if (drop_event_controller.widget != null) { + view.remove_controller(drop_event_controller); + } } }); } @@ -186,48 +189,28 @@ public class ConversationViewController : Object { } } - private void on_clipboard_paste() { + private async void on_clipboard_paste() { Clipboard clipboard = view.get_clipboard(); -// if (clipboard.wait_is_image_available()) { -// clipboard.request_image((_, pixbuf) => { -// File file = File.new_for_path(Path.build_filename(FileManager.get_storage_dir(), Xmpp.random_uuid() + ".png")); -// try { -// FileOutputStream fos = file.create(FileCreateFlags.REPLACE_DESTINATION); -// pixbuf.save_to_stream_async.begin(fos, "png", null, () => { -// open_send_file_overlay(file); -// }); -// } catch (Error e) { -// warning("Could not create file to store pasted image in %s, %s", file.get_path(), e.message); -// } -// }); -// } + Gdk.Texture? texture = yield clipboard.read_texture_async(null); // TODO critical + var file_name = Path.build_filename(FileManager.get_storage_dir(), Xmpp.random_uuid() + ".png"); + texture.save_to_png(file_name); + open_send_file_overlay(File.new_for_path(file_name)); } -// private 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 now we only process the first dragged file -// if (uris.length >= 1) { -// try { -// string file_path = Filename.from_uri(uris[0]); -// open_send_file_overlay(File.new_for_path(file_path)); -// } catch (ConvertError e) { -// warning("Could not handle dragged file %s, %s", uris[0], e.message); -// } -// } -// break; -// default: -// break; -// } -// } -// } + private bool on_drag_data_received(DropTarget target, Value val, double x, double y) { + if (val.type() == typeof(File)) { + open_send_file_overlay((File)val); + return true; + } + return false; + } private void open_file_picker() { FileChooserNative chooser = new FileChooserNative(_("Select file"), view.get_root() as Gtk.Window, FileChooserAction.OPEN, _("Select"), _("Cancel")); - chooser.response.connect(() => { - open_send_file_overlay(File.new_for_path(chooser.get_file().get_path())); + chooser.response.connect((response) => { + if (response == ResponseType.ACCEPT) { + open_send_file_overlay(File.new_for_path(chooser.get_file().get_path())); + } }); chooser.show(); } @@ -272,24 +255,22 @@ public class ConversationViewController : Object { stream_interactor.get_module(FileManager.IDENTITY).send_file.begin(file, conversation); } -// private bool forward_key_press_to_chat_input(EventKey event) { -// if (((Gtk.Window)view.get_toplevel()).get_focus() is TextView) { -// return false; -// } -// -// // 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; -// } -// if (view.chat_input.chat_text_view.text_view.key_press_event(event)) { -// return true; -// } -// return false; -// } + 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; + } + + // Don't forward / change focus on Control / Alt + if (keyval == Gdk.Key.Control_L || keyval == Gdk.Key.Control_R || + keyval == Gdk.Key.Alt_L || keyval == Gdk.Key.Alt_R) { + return false; + } + // Don't forward / change focus on Control + ... + if ((state & ModifierType.CONTROL_MASK) > 0) { + return false; + } + + return key_controller.forward(view.chat_input.chat_text_view.text_view); + } } } diff --git a/main/src/ui/file_send_overlay.vala b/main/src/ui/file_send_overlay.vala index ceb78818..11bd9a11 100644 --- a/main/src/ui/file_send_overlay.vala +++ b/main/src/ui/file_send_overlay.vala @@ -28,14 +28,11 @@ public class FileSendOverlay { info_label = (Label) builder.get_object("info_label"); close_button.clicked.connect(() => { - main_box.unparent(); - main_box.destroy(); + do_close(); }); send_button.clicked.connect(() => { send_file(); - this.close(); - main_box.unparent(); - main_box.destroy(); + do_close(); }); load_file_widget.begin(file, file_info); @@ -48,12 +45,14 @@ public class FileSendOverlay { } }); -// this.key_release_event.connect((event) => { -// if (event.keyval == Gdk.Key.Escape) { -// this.destroy(); -// } -// return false; -// }); + var key_events = new EventControllerKey(); + key_events.key_pressed.connect((keyval) => { + if (keyval == Gdk.Key.Escape) { + do_close(); + } + return false; + }); + this.main_box.add_controller(key_events); } private async void load_file_widget(File file, FileInfo file_info) { @@ -72,7 +71,7 @@ public class FileSendOverlay { Widget? widget = null; if (is_image) { - FileImageWidget image_widget = new FileImageWidget() { visible=true }; + FileImageWidget image_widget = new FileImageWidget(); try { yield image_widget.load_from_file(file, file_name); widget = image_widget; @@ -80,7 +79,7 @@ public class FileSendOverlay { } if (widget == null) { - FileDefaultWidget default_widget = new FileDefaultWidget() { visible=true }; + FileDefaultWidget default_widget = new FileDefaultWidget(); default_widget.name_label.label = file_name; default_widget.update_file_info(mime_type, FileTransfer.State.COMPLETE, (long)file_info.get_size()); widget = default_widget; @@ -96,6 +95,12 @@ public class FileSendOverlay { can_send = false; } + private void do_close() { + this.close(); + main_box.unparent(); + main_box.destroy(); + } + public Widget get_widget() { return main_box; } diff --git a/main/src/ui/global_search.vala b/main/src/ui/global_search.vala index bee409fe..5a02aa28 100644 --- a/main/src/ui/global_search.vala +++ b/main/src/ui/global_search.vala @@ -185,7 +185,7 @@ public class GlobalSearch { Gee.List before_message = stream_interactor.get_module(MessageStorage.IDENTITY).get_messages_before_message(item.conversation, item.message.time, item.message.id, 1); Gee.List after_message = stream_interactor.get_module(MessageStorage.IDENTITY).get_messages_after_message(item.conversation, item.message.time, item.message.id, 1); - Box context_box = new Box(Orientation.VERTICAL, 5) { visible=true }; + Box context_box = new Box(Orientation.VERTICAL, 5); if (before_message != null && before_message.size > 0) { context_box.append(get_context_message_widget(before_message.first())); } @@ -197,16 +197,16 @@ public class GlobalSearch { context_box.append(get_context_message_widget(after_message.first())); } - Label date_label = new Label(ConversationSummary.ConversationItemSkeleton.get_relative_time(item.time.to_local())) { xalign=0, visible=true }; - date_label.get_style_context().add_class("dim-label"); + Label date_label = new Label(ConversationSummary.ConversationItemSkeleton.get_relative_time(item.time.to_local())) { xalign=0 }; + date_label.add_css_class("dim-label"); string display_name = Util.get_conversation_display_name(stream_interactor, item.conversation); string title = item.message.type_ == Message.Type.GROUPCHAT ? _("In %s").printf(display_name) : _("With %s").printf(display_name); - Box header_box = new Box(Orientation.HORIZONTAL, 10) { margin_start=7, visible=true }; - header_box.append(new Label(@"$(Markup.escape_text(title))") { ellipsize=EllipsizeMode.END, xalign=0, use_markup=true, visible=true }); + Box header_box = new Box(Orientation.HORIZONTAL, 10) { margin_start=7 }; + header_box.append(new Label(@"$(Markup.escape_text(title))") { ellipsize=EllipsizeMode.END, xalign=0, use_markup=true }); header_box.append(date_label); - Box result_box = new Box(Orientation.VERTICAL, 7) { visible=true }; + Box result_box = new Box(Orientation.VERTICAL, 7); result_box.append(header_box); result_box.append(context_box); @@ -232,7 +232,7 @@ public class GlobalSearch { text = text.substring(0, 25) + " … " + text.substring(index - 50, 50) + text.substring(index, 100) + " … " + text.substring(text.length - 25, 25); } } - Label label = new Label("") { use_markup=true, xalign=0, selectable=true, wrap=true, wrap_mode=Pango.WrapMode.WORD_CHAR, vexpand=true, visible=true }; + Label label = new Label("") { use_markup=true, xalign=0, selectable=true, wrap=true, wrap_mode=Pango.WrapMode.WORD_CHAR, vexpand=true }; // Build regex containing all keywords string regex_str = "("; @@ -269,7 +269,7 @@ public class GlobalSearch { label.label = markup_text; grid.attach(label, 1, 1, 1, 1); - Button button = new Button() { has_frame=false, visible=true }; + Button button = new Button() { has_frame=false }; button.clicked.connect(() => { selected_item(item); }); @@ -280,20 +280,20 @@ public class GlobalSearch { private Grid get_context_message_widget(MessageItem item) { Grid grid = get_skeleton(item); grid.margin_start = 7; - Label label = new Label(item.message.body.replace("\n", "").replace("\r", "")) { ellipsize=EllipsizeMode.MIDDLE, xalign=0, visible=true }; + Label label = new Label(item.message.body.replace("\n", "").replace("\r", "")) { ellipsize=EllipsizeMode.MIDDLE, xalign=0 }; grid.attach(label, 1, 1, 1, 1); grid.opacity = 0.55; return grid; } private Grid get_skeleton(MessageItem item) { - AvatarImage image = new AvatarImage() { height=32, width=32, margin_end=7, valign=Align.START, visible=true, allow_gray = false }; + AvatarImage image = new AvatarImage() { height=32, width=32, margin_end=7, valign=Align.START, allow_gray = false }; image.set_conversation_participant(stream_interactor, item.conversation, item.jid); - Grid grid = new Grid() { row_homogeneous=false, visible=true }; + Grid grid = new Grid() { row_homogeneous=false }; grid.attach(image, 0, 0, 1, 2); string display_name = Util.get_participant_display_name(stream_interactor, item.conversation, item.jid); - Label name_label = new Label(display_name) { ellipsize=EllipsizeMode.END, xalign=0, visible=true }; + Label name_label = new Label(display_name) { ellipsize=EllipsizeMode.END, xalign=0 }; name_label.attributes = new AttrList(); name_label.attributes.insert(attr_weight_new(Weight.BOLD)); grid.attach(name_label, 1, 0, 1, 1); diff --git a/main/src/ui/main_window.vala b/main/src/ui/main_window.vala index a7e78b5d..1f1a7688 100644 --- a/main/src/ui/main_window.vala +++ b/main/src/ui/main_window.vala @@ -49,7 +49,7 @@ public class MainWindow : Gtk.Window { this.title = "Dino"; - this.get_style_context().add_class("dino-main"); + this.add_css_class("dino-main"); Gtk.Settings.get_default().notify["gtk-decoration-layout"].connect(set_window_buttons); ((Widget)this).realize.connect(set_window_buttons); @@ -77,7 +77,7 @@ public class MainWindow : Gtk.Window { search_frame.set_child(global_search.get_widget()); Image conversation_list_placeholder_image = (Image) builder.get_object("conversation_list_placeholder_image"); - conversation_list_placeholder_image.set_from_pixbuf(new Pixbuf.from_resource("/im/dino/Dino/icons/dino-conversation-list-placeholder-arrow.svg")); + conversation_list_placeholder_image.set_from_pixbuf(new Pixbuf.from_resource("/im/dino/Dino/icons/scalable/ui/dino-conversation-list-placeholder-arrow.svg")); } private void setup_headerbar() { diff --git a/main/src/ui/main_window_controller.vala b/main/src/ui/main_window_controller.vala index 7049aa40..38ebcc9c 100644 --- a/main/src/ui/main_window_controller.vala +++ b/main/src/ui/main_window_controller.vala @@ -111,13 +111,6 @@ public class MainWindowController : Object { stream_interactor.get_module(ConversationManager.IDENTITY).conversation_activated.connect(() => update_stack_state()); stream_interactor.get_module(ConversationManager.IDENTITY).conversation_deactivated.connect(() => update_stack_state()); update_stack_state(); - -// AccelGroup accel_group = new AccelGroup(); -// accel_group.connect(Gdk.Key.F, ModifierType.CONTROL_MASK, AccelFlags.VISIBLE, () => { -// window.search_revealer.reveal_child = true; -// return false; -// }); -// window.add_accel_group(accel_group); } public void select_conversation(Conversation? conversation, bool do_reset_search = true, bool default_initialize_conversation = true) { diff --git a/main/src/ui/manage_accounts/add_account_dialog.vala b/main/src/ui/manage_accounts/add_account_dialog.vala index d3dbf390..daff3abf 100644 --- a/main/src/ui/manage_accounts/add_account_dialog.vala +++ b/main/src/ui/manage_accounts/add_account_dialog.vala @@ -109,8 +109,8 @@ public class AddAccountDialog : Gtk.Dialog { login_button.clicked.connect(show_sign_in_jid); foreach (string server in server_list) { - ListBoxRow list_box_row = new ListBoxRow() { visible=true }; - list_box_row.set_child(new Label(server) { xalign=0, margin_start=7, margin_end=7, visible=true }); + ListBoxRow list_box_row = new ListBoxRow(); + list_box_row.set_child(new Label(server) { xalign=0, margin_start=7, margin_end=7 }); list_box_jids[list_box_row] = server; server_list_box.append(list_box_row); } @@ -338,8 +338,8 @@ public class AddAccountDialog : Gtk.Dialog { register_title.label = _("Register on %s").printf(server.to_string()); if (form.oob != null) { - form_box.append(new Label(_("The server requires to sign up through a website")){ visible=true } ); - form_box.append(new Label(@"$(form.oob)") { use_markup=true, visible=true }); + form_box.append(new Label(_("The server requires to sign up through a website"))); + form_box.append(new Label(@"$(form.oob)") { use_markup=true }); register_form_continue_label.label = _("Open website"); register_form_continue.visible = true; register_form_continue.grab_focus(); @@ -347,23 +347,23 @@ public class AddAccountDialog : Gtk.Dialog { if (form.instructions != null && form.instructions != "") { string markup_instructions = Util.parse_add_markup(form.instructions, null, true, false); form_box.append(new Label(markup_instructions) { use_markup=true, halign=Align.CENTER, xalign=0, margin_top=7, - wrap=true, wrap_mode=Pango.WrapMode.WORD_CHAR, visible=true }); + wrap=true, wrap_mode=Pango.WrapMode.WORD_CHAR }); } foreach (Xep.DataForms.DataForm.Field field in form.fields) { Widget? field_widget = Util.get_data_form_field_widget(field); if (field.label != null && field.label != "" && field_widget != null) { - form_box.append(new Label(field.label) { xalign=0, margin_top=7, visible=true }); + form_box.append(new Label(field.label) { xalign=0, margin_top=7 }); form_box.append(field_widget); } else if (field.type_ == Xep.DataForms.DataForm.Type.FIXED && field.get_value_string() != "") { string markup_fixed_field = Util.parse_add_markup(field.get_value_string(), null, true, false); form_box.append(new Label(markup_fixed_field) { use_markup=true, xalign=0, margin_top=7, - wrap=true, wrap_mode=Pango.WrapMode.WORD_CHAR, visible=true }); + wrap=true, wrap_mode=Pango.WrapMode.WORD_CHAR }); } } register_form_continue.visible = true; register_form_continue_label.label = _("Register"); } else { - form_box.append(new Label(_("Check %s for information on how to sign up").printf(@"$(server)")) { use_markup=true, visible=true }); + form_box.append(new Label(_("Check %s for information on how to sign up").printf(@"$(server)")) { use_markup=true }); register_form_continue.visible = false; } } @@ -423,21 +423,19 @@ public class AddAccountDialog : Gtk.Dialog { } private void animate_window_resize(Widget widget) { // TODO code duplication -// int def_height, curr_width, curr_height; -// get_size(out curr_width, out curr_height); -// widget.get_preferred_height(null, out def_height); -// def_height += 5; -// int difference = def_height - curr_height; -// Timer timer = new Timer(); -// Timeout.add((int) (stack.transition_duration / 30), -// () => { -// ulong microsec; -// timer.elapsed(out microsec); -// ulong millisec = microsec / 1000; -// double partial = double.min(1, (double) millisec / stack.transition_duration); -// resize(curr_width, (int) (curr_height + difference * partial)); -// return millisec < stack.transition_duration; -// }); + int curr_height = widget.get_size(Orientation.VERTICAL); + var natural_size = Requisition(); + stack.get_preferred_size(null, out natural_size); + int difference = natural_size.height + 5 - curr_height; + Timer timer = new Timer(); + Timeout.add((int) (stack.transition_duration / 30), () => { + ulong microsec; + timer.elapsed(out microsec); + ulong millisec = microsec / 1000; + double partial = double.min(1, (double) millisec / stack.transition_duration); + default_height = (int) (curr_height + difference * partial); + return millisec < stack.transition_duration; + }); } } diff --git a/main/src/ui/manage_accounts/dialog.vala b/main/src/ui/manage_accounts/dialog.vala index 88dc7485..efeff046 100644 --- a/main/src/ui/manage_accounts/dialog.vala +++ b/main/src/ui/manage_accounts/dialog.vala @@ -58,8 +58,8 @@ public class Dialog : Gtk.Dialog { Widget? widget = e.get_widget(Plugins.WidgetType.GTK4) as Widget; if (widget == null) continue; - Label label = new Label(e.name) { xalign=1, yalign=0, visible=true }; - label.get_style_context().add_class("dim-label"); + Label label = new Label(e.name) { xalign=1, yalign=0 }; + label.add_css_class("dim-label"); label.margin_top = e.label_top_padding == -1 ? default_top_padding : e.label_top_padding; settings_list.attach(label, 0, row_index); @@ -117,18 +117,21 @@ public class Dialog : Gtk.Dialog { msg.secondary_text = "You won't be able to access your conversation history anymore."; // TODO remove history! Button ok_button = msg.get_widget_for_response(ResponseType.OK) as Button; ok_button.label = _("Remove"); - ok_button.get_style_context().add_class("destructive-action"); - if (/*msg.run() == Gtk.ResponseType.OK*/ true) { - account_list.remove(account_item); - if (account_item.account.enabled) account_disabled(account_item.account); - account_item.account.remove(); - if (account_list.get_row_at_index(0) != null) { - account_list.select_row(account_list.get_row_at_index(0)); - } else { - main_stack.set_visible_child_name("no_accounts"); + ok_button.add_css_class("destructive-action"); + msg.response.connect((response) => { + if (response == ResponseType.OK) { + account_list.remove(account_item); + if (account_item.account.enabled) account_disabled(account_item.account); + account_item.account.remove(); + if (account_list.get_row_at_index(0) != null) { + account_list.select_row(account_list.get_row_at_index(0)); + } else { + main_stack.set_visible_child_name("no_accounts"); + } } - } - msg.close(); + msg.close(); + }); + msg.present(); } private void on_account_list_row_selected(ListBoxRow? row) { @@ -205,7 +208,7 @@ public class Dialog : Gtk.Dialog { ConnectionManager.ConnectionError? error = stream_interactor.connection_manager.get_error(account); if (error != null) { state_label.label = get_connection_error_description(error); - state_label.get_style_context().add_class("is_error"); + state_label.add_css_class("is_error"); } else { ConnectionManager.ConnectionState state = stream_interactor.connection_manager.get_state(account); switch (state) { @@ -216,7 +219,7 @@ public class Dialog : Gtk.Dialog { case ConnectionManager.ConnectionState.DISCONNECTED: state_label.label = _("Disconnected"); break; } - state_label.get_style_context().remove_class("is_error"); + state_label.remove_css_class("is_error"); } } diff --git a/main/src/ui/occupant_menu/list.vala b/main/src/ui/occupant_menu/list.vala index 20a98cf6..b9a4a74f 100644 --- a/main/src/ui/occupant_menu/list.vala +++ b/main/src/ui/occupant_menu/list.vala @@ -122,16 +122,16 @@ public class List : Box { if (aff == affiliation) count++; } - Label title_label = new Label("") { margin_start=10, xalign=0, visible=true }; + Label title_label = new Label("") { margin_start=10, xalign=0 }; title_label.set_markup(@"$(Markup.escape_text(aff_str))"); - Label count_label = new Label(@"$count") { xalign=0, margin_end=7, hexpand=true, visible=true }; - count_label.get_style_context().add_class("dim-label"); + Label count_label = new Label(@"$count") { xalign=0, margin_end=7, hexpand=true }; + count_label.add_css_class("dim-label"); - Grid grid = new Grid() { margin_top=top?5:15, column_spacing=5, hexpand=true, visible=true }; + Grid grid = new Grid() { margin_top=top?5:15, column_spacing=5, hexpand=true }; grid.attach(title_label, 0, 0, 1, 1); grid.attach(count_label, 1, 0, 1, 1); - grid.attach(new Separator(Orientation.HORIZONTAL) { hexpand=true, vexpand=true, visible=true }, 0, 1, 2, 1); + grid.attach(new Separator(Orientation.HORIZONTAL) { hexpand=true, vexpand=true }, 0, 1, 2, 1); return grid; } diff --git a/main/src/ui/occupant_menu/view.vala b/main/src/ui/occupant_menu/view.vala index 35aa95f4..08e1e9ed 100644 --- a/main/src/ui/occupant_menu/view.vala +++ b/main/src/ui/occupant_menu/view.vala @@ -10,10 +10,10 @@ public class View : Popover { private StreamInteractor stream_interactor; private Conversation conversation; - private Stack stack = new Stack() { vhomogeneous=false, visible=true }; - private Box list_box = new Box(Orientation.VERTICAL, 1) { visible=true }; + private Stack stack = new Stack() { vhomogeneous=false }; + private Box list_box = new Box(Orientation.VERTICAL, 1); private List? list = null; - private ListBox invite_list = new ListBox() { visible=true }; + private ListBox invite_list = new ListBox(); private Box? jid_menu = null; private Jid? selected_jid; @@ -25,6 +25,7 @@ public class View : Popover { this.show.connect(initialize_list); invite_list.append(new ListRow.label("+", _("Invite")).get_widget()); + invite_list.can_focus = false; list_box.append(invite_list); invite_list.row_activated.connect(on_invite_clicked); @@ -44,7 +45,7 @@ public class View : Popover { private void initialize_list() { if (list == null) { - list = new List(stream_interactor, conversation) { visible=true }; + list = new List(stream_interactor, conversation); list_box.prepend(list); list.list_box.row_activated.connect((row) => { @@ -68,17 +69,17 @@ public class View : Popover { Jid? real_jid = stream_interactor.get_module(MucManager.IDENTITY).get_real_jid(jid, conversation.account); if (real_jid != null) name += "\n%s".printf(Markup.escape_text(real_jid.bare_jid.to_string())); - Box header_box = new Box(Orientation.HORIZONTAL, 5) { visible=true }; - header_box.append(new Image.from_icon_name("pan-start-symbolic") { visible=true }); - header_box.append(new Label(name) { xalign=0, use_markup=true, hexpand=true, visible=true }); - Button header_button = new Button() { has_frame=false, visible=true }; + Box header_box = new Box(Orientation.HORIZONTAL, 5); + header_box.append(new Image.from_icon_name("pan-start-symbolic")); + header_box.append(new Label(name) { xalign=0, use_markup=true, hexpand=true }); + Button header_button = new Button() { has_frame=false }; header_button.child = header_box; - Box outer_box = new Box(Orientation.VERTICAL, 5) { visible=true }; + Box outer_box = new Box(Orientation.VERTICAL, 5); outer_box.append(header_button); header_button.clicked.connect(show_list); - Button private_button = new Button.with_label(_("Start private conversation")) { visible=true }; + Button private_button = new Button.with_label(_("Start private conversation")) ; outer_box.append(private_button); private_button.clicked.connect(private_conversation_button_clicked); @@ -86,19 +87,19 @@ public class View : Popover { Xmpp.Xep.Muc.Role? role = stream_interactor.get_module(MucManager.IDENTITY).get_role(own_jid, conversation.account); if (role == Xmpp.Xep.Muc.Role.MODERATOR && stream_interactor.get_module(MucManager.IDENTITY).kick_possible(conversation.account, jid)) { - Button kick_button = new Button.with_label(_("Kick")) { visible=true }; + Button kick_button = new Button.with_label(_("Kick")) ; outer_box.append(kick_button); kick_button.clicked.connect(kick_button_clicked); } if (stream_interactor.get_module(MucManager.IDENTITY).is_moderated_room(conversation.account, conversation.counterpart) && role == Xmpp.Xep.Muc.Role.MODERATOR){ if (stream_interactor.get_module(MucManager.IDENTITY).get_role(selected_jid, conversation.account) == Xmpp.Xep.Muc.Role.VISITOR) { - Button voice_button = new Button.with_label(_("Grant write permission")) { visible=true }; + Button voice_button = new Button.with_label(_("Grant write permission")) ; outer_box.append(voice_button); voice_button.clicked.connect(() => voice_button_clicked("participant")); } else if (stream_interactor.get_module(MucManager.IDENTITY).get_role(selected_jid, conversation.account) == Xmpp.Xep.Muc.Role.PARTICIPANT){ - Button voice_button = new Button.with_label(_("Revoke write permission")) { visible=true }; + Button voice_button = new Button.with_label(_("Revoke write permission")) ; outer_box.append(voice_button); voice_button.clicked.connect(() => voice_button_clicked("visitor")); diff --git a/main/src/ui/util/data_forms.vala b/main/src/ui/util/data_forms.vala index 53439149..af8789a7 100644 --- a/main/src/ui/util/data_forms.vala +++ b/main/src/ui/util/data_forms.vala @@ -11,7 +11,7 @@ public static Widget? get_data_form_field_widget(DataForms.DataForm.Field field) switch (field.type_) { case DataForms.DataForm.Type.BOOLEAN: DataForms.DataForm.BooleanField boolean_field = field as DataForms.DataForm.BooleanField; - Switch sw = new Switch() { active=boolean_field.value, halign=Align.START, valign=Align.CENTER, visible=true }; + Switch sw = new Switch() { active=boolean_field.value, halign=Align.START, valign=Align.CENTER }; sw.state_set.connect((state) => { boolean_field.value = state; return false; @@ -21,7 +21,7 @@ public static Widget? get_data_form_field_widget(DataForms.DataForm.Field field) return null; case DataForms.DataForm.Type.LIST_SINGLE: DataForms.DataForm.ListSingleField list_single_field = field as DataForms.DataForm.ListSingleField; - ComboBoxText combobox = new ComboBoxText() { valign=Align.CENTER, visible=true }; + ComboBoxText combobox = new ComboBoxText() { valign=Align.CENTER }; for (int i = 0; i < list_single_field.options.size; i++) { DataForms.DataForm.Option option = list_single_field.options[i]; combobox.append(option.value, option.label); @@ -35,7 +35,7 @@ public static Widget? get_data_form_field_widget(DataForms.DataForm.Field field) return null; case DataForms.DataForm.Type.TEXT_PRIVATE: DataForms.DataForm.TextPrivateField text_private_field = field as DataForms.DataForm.TextPrivateField; - Entry entry = new Entry() { text=text_private_field.value ?? "", valign=Align.CENTER, visible=true, visibility=false }; + Entry entry = new Entry() { text=text_private_field.value ?? "", valign=Align.CENTER, visibility=false }; var entry_key_events = new EventControllerKey(); entry_key_events.key_released.connect(() => { text_private_field.value = entry.text; @@ -44,7 +44,7 @@ public static Widget? get_data_form_field_widget(DataForms.DataForm.Field field) return entry; case DataForms.DataForm.Type.TEXT_SINGLE: DataForms.DataForm.TextSingleField text_single_field = field as DataForms.DataForm.TextSingleField; - Entry entry = new Entry() { text=text_single_field.value ?? "", valign=Align.CENTER, visible=true }; + Entry entry = new Entry() { text=text_single_field.value ?? "", valign=Align.CENTER }; var entry_key_events = new EventControllerKey(); entry_key_events.key_released.connect(() => { text_single_field.value = entry.text; diff --git a/main/src/ui/util/label_hybrid.vala b/main/src/ui/util/label_hybrid.vala index d880ba6f..53f0fbca 100644 --- a/main/src/ui/util/label_hybrid.vala +++ b/main/src/ui/util/label_hybrid.vala @@ -6,12 +6,12 @@ namespace Dino.Ui.Util { public class LabelHybrid : Widget { public Stack stack = new Stack(); - public Label label = new Label("") { visible=true, max_width_chars=1, ellipsize=Pango.EllipsizeMode.END }; - protected Button button = new Button() { has_frame=false, visible=true }; + public Label label = new Label("") { max_width_chars=1, ellipsize=Pango.EllipsizeMode.END }; + protected Button button = new Button() { has_frame=false }; internal virtual void init(Widget widget) { this.layout_manager = new BinLayout(); - stack.insert_after(this, null); + stack.set_parent(this); button.child = label; stack.add_named(button, "label"); stack.add_named(widget, "widget"); @@ -29,6 +29,10 @@ public class LabelHybrid : Widget { public void show_label() { stack.visible_child_name = "label"; } + + public override void dispose() { + stack.unparent(); + } } public class EntryLabelHybrid : LabelHybrid { @@ -58,7 +62,7 @@ public class EntryLabelHybrid : LabelHybrid { public Entry entry { get { if (entry_ == null) { - entry_ = new Entry() { visible=true }; + entry_ = new Entry(); init(entry_); } return entry_; @@ -71,10 +75,11 @@ public class EntryLabelHybrid : LabelHybrid { } internal override void init(Widget widget) { - Entry? e = widget as Entry; if (e == null) return; + Entry? e = widget as Entry; + if (e == null) return; entry = e; base.init(entry); - update_label(); + set_label_label(entry.text); var key_events = new EventControllerKey(); key_events.key_released.connect(on_key_released); @@ -106,10 +111,6 @@ public class EntryLabelHybrid : LabelHybrid { label.label = filler; } } - - private void update_label() { - text = text; - } } public class ComboBoxTextLabelHybrid : LabelHybrid { @@ -128,7 +129,7 @@ public class ComboBoxTextLabelHybrid : LabelHybrid { public ComboBoxText combobox { get { if (combobox_ == null) { - combobox_ = new ComboBoxText() { visible=true }; + combobox_ = new ComboBoxText(); init(combobox_); } return combobox_; diff --git a/main/src/ui/util/scaling_image.vala b/main/src/ui/util/scaling_image.vala index 3dd3221f..20ff6718 100644 --- a/main/src/ui/util/scaling_image.vala +++ b/main/src/ui/util/scaling_image.vala @@ -177,20 +177,6 @@ class ScalingImage : Widget { minimum_baseline = natural_baseline = -1; } -// public override void get_preferred_height_for_width(int width, out int minimum_height, out int natural_height) { -// double exact_width = width, exact_height = -1; -// calculate_size(ref exact_width, ref exact_height); -// natural_height = (int) Math.ceil(exact_height); -// minimum_height = natural_height; -// } -// -// public override void get_preferred_width_for_height(int height, out int minimum_width, out int natural_width) { -// double exact_width = -1, exact_height = height; -// calculate_size(ref exact_width, ref exact_height); -// natural_width = (int) Math.ceil(exact_width); -// minimum_width = natural_width; -// } - public override SizeRequestMode get_request_mode() { return SizeRequestMode.HEIGHT_FOR_WIDTH; } diff --git a/main/src/ui/util/sizing_bin.vala b/main/src/ui/util/sizing_bin.vala index 939022a1..c17cb3cc 100644 --- a/main/src/ui/util/sizing_bin.vala +++ b/main/src/ui/util/sizing_bin.vala @@ -33,5 +33,10 @@ public class SizingBin : Widget { natural = int.max(natural, minimum); } } + + public override void dispose() { + var child = this.get_first_child(); + if (child != null) child.unparent(); + } } } -- cgit v1.2.3-54-g00ecf