diff options
Diffstat (limited to 'libdino/src/ui/add_conversation/conference')
4 files changed, 511 insertions, 0 deletions
diff --git a/libdino/src/ui/add_conversation/conference/add_groupchat_dialog.vala b/libdino/src/ui/add_conversation/conference/add_groupchat_dialog.vala new file mode 100644 index 00000000..8cc5ac72 --- /dev/null +++ b/libdino/src/ui/add_conversation/conference/add_groupchat_dialog.vala @@ -0,0 +1,91 @@ +using Gee; +using Gtk; + +using Dino.Entities; + +namespace Dino.Ui.AddConversation.Conference { + +[GtkTemplate (ui = "/org/dino-im/add_conversation/add_groupchat_dialog.ui")] +protected class AddGroupchatDialog : Gtk.Dialog { + + [GtkChild] private Stack accounts_stack; + [GtkChild] private ComboBoxText accounts_comboboxtext; + [GtkChild] private Label account_label; + [GtkChild] private Button ok_button; + [GtkChild] private Button cancel_button; + [GtkChild] private Entry jid_entry; + [GtkChild] private Entry alias_entry; + [GtkChild] private Entry nick_entry; + [GtkChild] private CheckButton autojoin_checkbutton; + + private StreamInteractor stream_interactor; + private Xmpp.Xep.Bookmarks.Conference? edit_confrence = null; + private bool alias_entry_changed = false; + + public AddGroupchatDialog(StreamInteractor stream_interactor) { + 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 + accounts_stack.set_visible_child_name("combobox"); + foreach (Account account in stream_interactor.get_accounts()) { + accounts_comboboxtext.append_text(account.bare_jid.to_string()); + } + accounts_comboboxtext.set_active(0); + + cancel_button.clicked.connect(() => { close(); }); + ok_button.clicked.connect(on_ok_button_clicked); + jid_entry.key_release_event.connect(on_jid_key_release); + nick_entry.key_release_event.connect(check_ok); + } + + public AddGroupchatDialog.for_conference(StreamInteractor stream_interactor, Account account, Xmpp.Xep.Bookmarks.Conference conference) { + this(stream_interactor); + edit_confrence = conference; + ok_button.label = "Save"; + ok_button.sensitive = true; + accounts_stack.set_visible_child_name("label"); + account_label.label = account.bare_jid.to_string(); + jid_entry.text = conference.jid; + nick_entry.text = conference.nick; + autojoin_checkbutton.active = conference.autojoin; + alias_entry.text = conference.name; + } + + private bool on_jid_key_release() { + check_ok(); + if (!alias_entry_changed) { + Jid? parsed_jid = Jid.parse(jid_entry.text); + alias_entry.text = parsed_jid != null && parsed_jid.localpart != null ? parsed_jid.localpart : jid_entry.text; + } + return false; + } + + private bool check_ok() { + Jid? parsed_jid = Jid.parse(jid_entry.text); + ok_button.sensitive = parsed_jid != null && parsed_jid.localpart != null && parsed_jid.resourcepart == null && + nick_entry.text != "" && alias_entry.text != null; + return false; + } + + private void on_ok_button_clicked() { + Account? account = null; + foreach (Account account2 in stream_interactor.get_accounts()) { + if (accounts_comboboxtext.get_active_text() == account2.bare_jid.to_string()) { + account = account2; + } + } + Xmpp.Xep.Bookmarks.Conference conference = new Xmpp.Xep.Bookmarks.Conference(jid_entry.text); + conference.nick = nick_entry.text; + conference.name = alias_entry.text; + conference.autojoin = autojoin_checkbutton.active; + if (edit_confrence == null) { + MucManager.get_instance(stream_interactor).add_bookmark(account, conference); + } else { + MucManager.get_instance(stream_interactor).replace_bookmark(account, edit_confrence, conference); + } + close(); + } +} + +}
\ No newline at end of file diff --git a/libdino/src/ui/add_conversation/conference/conference_details_fragment.vala b/libdino/src/ui/add_conversation/conference/conference_details_fragment.vala new file mode 100644 index 00000000..d42c79bd --- /dev/null +++ b/libdino/src/ui/add_conversation/conference/conference_details_fragment.vala @@ -0,0 +1,147 @@ +using Gdk; +using Gtk; + +using Dino.Entities; + +namespace Dino.Ui.AddConversation.Conference { + +[GtkTemplate (ui = "/org/dino-im/add_conversation/conference_details_fragment.ui")] +protected class ConferenceDetailsFragment : Box { + + public bool done { + get { + Jid? parsed_jid = Jid.parse(jid); + return parsed_jid != null && parsed_jid.localpart != null && + parsed_jid.resourcepart == null && nick != ""; + } + private set {} + } + + public Account account { + owned get { + foreach (Account account in stream_interactor.get_accounts()) { + if (accounts_comboboxtext.get_active_text() == account.bare_jid.to_string()) { + return account; + } + } + return null; + } + set { + accounts_label.label = value.bare_jid.to_string(); + accounts_comboboxtext.set_active_id(value.bare_jid.to_string()); + } + } + public string jid { + get { return jid_entry.text; } + set { + jid_label.label = value; + jid_entry.text = value; + } + } + public string nick { + get { return nick_entry.text; } + set { + nick_label.label = value; + nick_entry.text = value; + } + } + public string password { + get { return password_entry.text == "" ? null : password_entry.text; } + set { + password_label.label = value; + password_entry.text = value; + } + } + + [GtkChild] private Stack accounts_stack; + [GtkChild] private Button accounts_button; + [GtkChild] private Label accounts_label; + [GtkChild] private ComboBoxText accounts_comboboxtext; + + [GtkChild] private Stack jid_stack; + [GtkChild] private Button jid_button; + [GtkChild] private Label jid_label; + [GtkChild] private Entry jid_entry; + + [GtkChild] private Stack nick_stack; + [GtkChild] private Button nick_button; + [GtkChild] private Label nick_label; + [GtkChild] private Entry nick_entry; + + [GtkChild] private Stack password_stack; + [GtkChild] private Button password_button; + [GtkChild] private Label password_label; + [GtkChild] private Entry password_entry; + + private StreamInteractor stream_interactor; + + public ConferenceDetailsFragment(StreamInteractor stream_interactor) { + this.stream_interactor = stream_interactor; + + accounts_stack.set_visible_child_name("label"); + jid_stack.set_visible_child_name("label"); + nick_stack.set_visible_child_name("label"); + password_stack.set_visible_child_name("label"); + + accounts_button.clicked.connect(() => { set_active_stack(accounts_stack); }); + jid_button.clicked.connect(() => { set_active_stack(jid_stack); }); + nick_button.clicked.connect(() => { set_active_stack(nick_stack); }); + password_button.clicked.connect(() => { set_active_stack(password_stack); }); + + accounts_comboboxtext.changed.connect(() => {accounts_label.label = accounts_comboboxtext.get_active_text(); }); + jid_entry.key_release_event.connect(on_jid_key_release_event); + nick_entry.key_release_event.connect(on_nick_key_release_event); + password_entry.key_release_event.connect(on_password_key_release_event); + + jid_entry.key_release_event.connect(() => { done = true; return false; }); // just for notifying + nick_entry.key_release_event.connect(() => { done = true; return false; }); + + foreach (Account account in stream_interactor.get_accounts()) { + accounts_comboboxtext.append_text(account.bare_jid.to_string()); + } + accounts_comboboxtext.set_active(0); + } + + public void set_editable() { + accounts_stack.set_visible_child_name("entry"); + nick_stack.set_visible_child_name("entry"); + password_stack.set_visible_child_name("entry"); + } + + public void clear() { + jid = ""; + nick = ""; + password = ""; + } + + private bool on_jid_key_release_event(EventKey event) { + jid_label.label = jid_entry.text; + if (event.keyval == Key.Return) jid_stack.set_visible_child_name("label"); + return false; + } + + private bool on_nick_key_release_event(EventKey event) { + nick_label.label = nick_entry.text; + if (event.keyval == Key.Return) nick_stack.set_visible_child_name("label"); + return false; + } + + private bool on_password_key_release_event(EventKey event) { + string filler = ""; + for (int i = 0; i < password_entry.text.length; i++) filler += password_entry.get_invisible_char().to_string(); + password_label.label = filler; + if (event.keyval == Key.Return) password_stack.set_visible_child_name("label"); + return false; + } + + private void set_active_stack(Stack stack) { + stack.set_visible_child_name("entry"); + if (stack != accounts_stack) accounts_stack.set_visible_child_name("label"); + if (stack != jid_stack) jid_stack.set_visible_child_name("label"); + if (stack != nick_stack) nick_stack.set_visible_child_name("label"); + if (stack != password_stack) password_stack.set_visible_child_name("label"); + } + +} + +}
\ No newline at end of file diff --git a/libdino/src/ui/add_conversation/conference/conference_list.vala b/libdino/src/ui/add_conversation/conference/conference_list.vala new file mode 100644 index 00000000..17f08ff3 --- /dev/null +++ b/libdino/src/ui/add_conversation/conference/conference_list.vala @@ -0,0 +1,107 @@ +using Gee; +using Gtk; + +using Xmpp; +using Dino.Entities; + +namespace Dino.Ui.AddConversation.Conference { + +protected class ConferenceList : FilterableList { + + public signal void conversation_selected(Conversation? conversation); + + private StreamInteractor stream_interactor; + private HashMap<Account, ArrayList<Xep.Bookmarks.Conference>> lists = new HashMap<Account, ArrayList<Xep.Bookmarks.Conference>>(); + + public ConferenceList(StreamInteractor stream_interactor) { + this.stream_interactor = stream_interactor; + + set_filter_func(filter); + set_header_func(header); + set_sort_func(sort); + + MucManager.get_instance(stream_interactor).bookmarks_updated.connect((account, conferences) => { + Idle.add(() => { + lists[account] = conferences; + refresh_conferences(); + return false; + }); + }); + + foreach (Account account in stream_interactor.get_accounts()) { + MucManager.get_instance(stream_interactor).get_bookmarks(account, new BookmarksListener(this, stream_interactor, account)); + } + } + + public void refresh_conferences() { + @foreach((widget) => { remove(widget); }); + foreach (Account account in lists.keys) { + foreach (Xep.Bookmarks.Conference conference in lists[account]) { + add(new ConferenceListRow(stream_interactor, conference, account)); + } + } + } + + private class BookmarksListener : Xep.Bookmarks.ConferencesRetrieveResponseListener, Object { + ConferenceList outer; + Account account; + public BookmarksListener(ConferenceList outer, StreamInteractor stream_interactor, Account account) { + this.outer = outer; + this.account = account; + } + + public void on_result(Core.XmppStream stream, ArrayList<Xep.Bookmarks.Conference> conferences) { + outer.lists[account] = conferences; + Idle.add(() => { outer.refresh_conferences(); return false; }); + } + } + + private void header(ListBoxRow row, ListBoxRow? before_row) { + if (row.get_header() == null && before_row != null) { + row.set_header(new Separator(Orientation.HORIZONTAL)); + } + } + + private bool filter(ListBoxRow r) { + if (r.get_type().is_a(typeof(ListRow))) { + ListRow row = r as ListRow; + if (filter_values != null) { + foreach (string filter in filter_values) { + if (!(row.name_label.label.down().contains(filter.down()) || + row.jid.to_string().down().contains(filter.down()))) { + return false; + } + } + } + } + return true; + } + + public override int sort(ListBoxRow row1, ListBoxRow row2) { + ListRow c1 = (row1 as ListRow); + ListRow c2 = (row2 as ListRow); + return c1.name_label.label.collate(c2.name_label.label); + } +} + +internal class ConferenceListRow : ListRow { + + public Xep.Bookmarks.Conference bookmark; + + public ConferenceListRow(StreamInteractor stream_interactor, Xep.Bookmarks.Conference bookmark, Account account) { + this.jid = new Jid(bookmark.jid); + this.account = account; + this.bookmark = bookmark; + + if (bookmark.name != "" && bookmark.name != bookmark.jid) { + name_label.label = bookmark.name; + via_label.label = bookmark.jid; + } else { + name_label.label = bookmark.jid; + via_label.visible = false; + } + image.set_from_pixbuf((new AvatarGenerator(35, 35)).set_stateless(true).draw_jid(stream_interactor, jid, account)); + } +} + +}
\ No newline at end of file diff --git a/libdino/src/ui/add_conversation/conference/dialog.vala b/libdino/src/ui/add_conversation/conference/dialog.vala new file mode 100644 index 00000000..ff548699 --- /dev/null +++ b/libdino/src/ui/add_conversation/conference/dialog.vala @@ -0,0 +1,166 @@ +using Gee; +using Gtk; + +using Dino.Entities; + +namespace Dino.Ui.AddConversation.Conference { + +public class Dialog : Gtk.Dialog { + + public signal void conversation_opened(Conversation conversation); + + private Stack stack = new Stack(); + private Button cancel_button; + private Button ok_button; + private Label cancel_label = new Label("Cancel") {visible=true}; + private Image cancel_image = new Image.from_icon_name("go-previous-symbolic", IconSize.MENU) {visible=true}; + + private SelectJidFragment select_fragment; + private ConferenceDetailsFragment details_fragment; + private ConferenceList conference_list; + + private StreamInteractor stream_interactor; + + public Dialog(StreamInteractor stream_interactor) { + Object(use_header_bar : 1); + this.title = "Join Conference"; + this.modal = true; + this.stream_interactor = stream_interactor; + + stack.visible = true; + stack.vhomogeneous = false; + get_content_area().add(stack); + + setup_headerbar(); + setup_jid_add_view(); + setup_conference_details_view(); + show_jid_add_view(); + } + + private void show_jid_add_view() { + cancel_button.remove(cancel_image); + cancel_button.add(cancel_label); + cancel_button.clicked.disconnect(show_jid_add_view); + cancel_button.clicked.connect(close); + ok_button.label = "Next"; + ok_button.sensitive = select_fragment.done; + ok_button.clicked.disconnect(on_ok_button_clicked); + ok_button.clicked.connect(on_next_button_clicked); + details_fragment.notify["done"].disconnect(set_ok_sensitive_from_details); + select_fragment.notify["done"].connect(set_ok_sensitive_from_select); + stack.transition_type = StackTransitionType.SLIDE_RIGHT; + stack.set_visible_child_name("select"); + } + + private void show_conference_details_view() { + cancel_button.remove(cancel_label); + cancel_button.add(cancel_image); + cancel_button.clicked.disconnect(close); + cancel_button.clicked.connect(show_jid_add_view); + ok_button.label = "Join"; + ok_button.sensitive = details_fragment.done; + ok_button.clicked.disconnect(on_next_button_clicked); + ok_button.clicked.connect(on_ok_button_clicked); + select_fragment.notify["done"].disconnect(set_ok_sensitive_from_select); + details_fragment.notify["done"].connect(set_ok_sensitive_from_details); + stack.transition_type = StackTransitionType.SLIDE_LEFT; + stack.set_visible_child_name("details"); + animate_window_resize(); + } + + private void setup_headerbar() { + HeaderBar header_bar = get_header_bar() as HeaderBar; + header_bar.show_close_button = false; + + cancel_button = new Button(); + header_bar.pack_start(cancel_button); + cancel_button.visible = true; + + ok_button = new Button(); + header_bar.pack_end(ok_button); + ok_button.get_style_context().add_class("suggested-action"); + ok_button.visible = true; + ok_button.can_focus = true; + ok_button.can_default = true; + ok_button.has_default = true; + } + + private void setup_jid_add_view() { + conference_list = new ConferenceList(stream_interactor); + conference_list.row_activated.connect(() => { ok_button.clicked(); }); + select_fragment = new SelectJidFragment(stream_interactor, conference_list); + select_fragment.add_jid.connect((row) => { + AddGroupchatDialog dialog = new AddGroupchatDialog(stream_interactor); + dialog.set_transient_for(this); + dialog.show(); + }); + select_fragment.edit_jid.connect((row) => { + ConferenceListRow conference_row = row as ConferenceListRow; + AddGroupchatDialog dialog = new AddGroupchatDialog.for_conference(stream_interactor, conference_row.account, conference_row.bookmark); + dialog.set_transient_for(this); + dialog.show(); + }); + select_fragment.remove_jid.connect((row) => { + ConferenceListRow conference_row = row as ConferenceListRow; + MucManager.get_instance(stream_interactor).remove_bookmark(conference_row.account, conference_row.bookmark); + }); + stack.add_named(select_fragment, "select"); + } + + private void setup_conference_details_view() { + details_fragment = new ConferenceDetailsFragment(stream_interactor); + stack.add_named(details_fragment, "details"); + } + + private void set_ok_sensitive_from_select() { + ok_button.sensitive = select_fragment.done; + } + + private void set_ok_sensitive_from_details() { + ok_button.sensitive = select_fragment.done; + } + + private void on_next_button_clicked() { + details_fragment.clear(); + ListRow? row = conference_list.get_selected_row() as ListRow; + ConferenceListRow? conference_row = conference_list.get_selected_row() as ConferenceListRow; + if (conference_row != null) { + details_fragment.jid = conference_row.bookmark.jid; + details_fragment.nick = conference_row.bookmark.nick; + if (conference_row.bookmark.password != null) details_fragment.password = conference_row.bookmark.password; + ok_button.grab_focus(); + } else if (row != null) { + details_fragment.jid = row.jid.to_string(); + details_fragment.set_editable(); + } + show_conference_details_view(); + } + + private void on_ok_button_clicked() { + MucManager.get_instance(stream_interactor).join(details_fragment.account, new Jid(details_fragment.jid), details_fragment.nick, details_fragment.password); + close(); + } + + private void close() { + base.close(); + } + + private void animate_window_resize() { + int def_height, curr_width, curr_height; + get_size(out curr_width, out curr_height); + stack.get_preferred_height(null, out def_height); + 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; + }); + } +} + +}
\ No newline at end of file |