From 4be8c92a2c0e454ae217aea8f8eac69c99416214 Mon Sep 17 00:00:00 2001 From: fiaxh Date: Sun, 19 Aug 2018 23:27:02 +0100 Subject: In-Band Registration --- .../contact_details/muc_config_form_provider.vala | 50 +---- .../src/ui/manage_accounts/add_account_dialog.vala | 230 ++++++++++++++++++++- main/src/ui/util/data_forms.vala | 57 +++++ 3 files changed, 277 insertions(+), 60 deletions(-) create mode 100644 main/src/ui/util/data_forms.vala (limited to 'main/src/ui') diff --git a/main/src/ui/contact_details/muc_config_form_provider.vala b/main/src/ui/contact_details/muc_config_form_provider.vala index 072627bf..a088bd97 100644 --- a/main/src/ui/contact_details/muc_config_form_provider.vala +++ b/main/src/ui/contact_details/muc_config_form_provider.vala @@ -74,57 +74,9 @@ public class MucConfigFormProvider : Plugins.ContactDetailsProvider, Object { } } - Widget? widget = get_widget(field); + Widget? widget = Util.get_data_form_fild_widget(field); if (widget != null) contact_details.add(_("Room Configuration"), label, desc, widget); } - - private static Widget? get_widget(DataForms.DataForm.Field field) { - if (field.type_ == null) return null; - 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, valign=Align.CENTER, visible=true }; - sw.state_set.connect((state) => { - boolean_field.value = state; - return false; - }); - return sw; - case DataForms.DataForm.Type.JID_MULTI: - 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 }; - 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); - if (option.value == list_single_field.value) combobox.active = i; - } - combobox.changed.connect(() => { - list_single_field.value = combobox.get_active_id(); - }); - return combobox; - case DataForms.DataForm.Type.LIST_MULTI: - 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.key_release_event.connect(() => { - text_private_field.value = entry.text; - return false; - }); - 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.key_release_event.connect(() => { - text_single_field.value = entry.text; - return false; - }); - return entry; - default: - return null; - } - } } } diff --git a/main/src/ui/manage_accounts/add_account_dialog.vala b/main/src/ui/manage_accounts/add_account_dialog.vala index 5715db51..f9ab794e 100644 --- a/main/src/ui/manage_accounts/add_account_dialog.vala +++ b/main/src/ui/manage_accounts/add_account_dialog.vala @@ -11,29 +11,120 @@ public class AddAccountDialog : Gtk.Dialog { public signal void added(Account account); - [GtkChild] private Button cancel_button; - [GtkChild] private Button ok_button; - [GtkChild] private Entry alias_entry; + [GtkChild] private Stack stack; + + [GtkChild] private Revealer notification_revealer; + [GtkChild] private Label notification_label; + + // Sign in + [GtkChild] private Box sign_in_box; [GtkChild] private Entry jid_entry; + [GtkChild] private Entry alias_entry; [GtkChild] private Entry password_entry; + [GtkChild] private Button sign_in_continue; + [GtkChild] private Button serverlist_button; + + // Select Server + [GtkChild] private Box create_account_box; + [GtkChild] private Button login_button; + [GtkChild] private Stack select_server_continue_stack; + [GtkChild] private Button select_server_continue; + [GtkChild] private Label register_form_continue_label; + [GtkChild] private ListBox server_list_box; + [GtkChild] private Entry server_entry; + + // Register Form + [GtkChild] private Box register_box; + [GtkChild] private Label register_title; + [GtkChild] private Box form_box; + [GtkChild] private Button register_form_back; + [GtkChild] private Stack register_form_continue_stack; + [GtkChild] private Button register_form_continue; + + private static string[] server_list = new string[]{ + "5222.de", + "jabber.fr", + "movim.eu", + "yax.im" + }; + private HashMap list_box_jids = new HashMap(); + private Jid? server_jid = null; + private Xep.InBandRegistration.Form? form = null; public AddAccountDialog(StreamInteractor stream_interactor) { - Object(use_header_bar : 1); this.title = _("Add Account"); - cancel_button.clicked.connect(() => { close(); }); - ok_button.clicked.connect(on_ok_button_clicked); + // Sign in jid_entry.changed.connect(on_jid_entry_changed); jid_entry.focus_out_event.connect(on_jid_entry_focus_out_event); + sign_in_continue.clicked.connect(on_sign_in_continue_clicked); + serverlist_button.clicked.connect(show_select_server); + + // Select Server + server_entry.changed.connect(() => { + Jid? jid = Jid.parse(server_entry.text); + select_server_continue.sensitive = jid != null && jid.localpart == null && jid.resourcepart == null; + }); + select_server_continue.clicked.connect(on_select_server_continue); + login_button.clicked.connect(show_sign_in); + + foreach (string server in server_list) { + ListBoxRow list_box_row = new ListBoxRow() { visible=true }; + list_box_row.add(new Label(server) { xalign=0, margin=3, margin_start=7, margin_end=7, visible=true }); + list_box_jids[list_box_row] = server; + server_list_box.add(list_box_row); + } + + // Register Form + register_form_continue.clicked.connect(on_register_form_continue_clicked); + register_form_back.clicked.connect(show_select_server); + + show_sign_in(); + } + + private void show_sign_in() { + sign_in_box.visible = true; + stack.visible_child_name = "login"; + create_account_box.visible = false; + register_box.visible = false; + set_default(sign_in_continue); + animate_window_resize(sign_in_box); + } + + private void show_select_server() { + server_entry.text = ""; + server_entry.grab_focus(); + set_default(select_server_continue); + + server_list_box.row_selected.disconnect(on_server_list_row_selected); + server_list_box.unselect_all(); + server_list_box.row_selected.connect(on_server_list_row_selected); + + create_account_box.visible = true; + stack.visible_child_name = "server"; + sign_in_box.visible = false; + register_box.visible = false; + + animate_window_resize(create_account_box); + } + + private void show_register_form() { + register_box.visible = true; + stack.visible_child_name = "form"; + sign_in_box.visible = false; + create_account_box.visible = false; + + set_default(register_form_continue); + animate_window_resize(register_box); } private void on_jid_entry_changed() { Jid? jid = Jid.parse(jid_entry.text); if (jid != null && jid.localpart != null && jid.resourcepart == null) { - ok_button.set_sensitive(true); + sign_in_continue.set_sensitive(true); jid_entry.secondary_icon_name = null; } else { - ok_button.set_sensitive(false); + sign_in_continue.set_sensitive(false); } } @@ -41,7 +132,6 @@ public class AddAccountDialog : Gtk.Dialog { Jid? jid = Jid.parse(jid_entry.text); if (jid == null || jid.localpart == null || jid.resourcepart != null) { jid_entry.secondary_icon_name = "dialog-warning-symbolic"; - // TODO why doesn't the tooltip work jid_entry.set_icon_tooltip_text(EntryIconPosition.SECONDARY, _("JID should be of the form “user@example.com”")); } else { jid_entry.secondary_icon_name = null; @@ -49,13 +139,131 @@ public class AddAccountDialog : Gtk.Dialog { return false; } - private void on_ok_button_clicked() { + private void on_sign_in_continue_clicked() { Jid jid = new Jid(jid_entry.get_text()); string password = password_entry.get_text(); string alias = alias_entry.get_text(); + store_account(jid, password, alias); + close(); + } + + private void on_select_server_continue() { + server_jid = new Jid(server_entry.text); + request_show_register_form.begin(); + } + + private void on_server_list_row_selected(ListBox box, ListBoxRow? row) { + server_jid = new Jid(list_box_jids[row]); + request_show_register_form.begin(); + } + + private async void request_show_register_form() { + select_server_continue_stack.visible_child_name = "spinner"; + form = yield Register.get_registration_form(server_jid); + if (select_server_continue_stack == null) { + return; + } + select_server_continue_stack.visible_child_name = "label"; + if (form != null) { + set_register_form(server_jid, form); + show_register_form(); + } else { + display_notification(_("No response from server")); + } + } + + private void set_register_form(Jid server, Xep.InBandRegistration.Form form) { + form_box.foreach((widget) => { widget.destroy(); }); + register_title.label = _("Register on %s").printf(server.to_string()); + + if (form.oob != null) { + form_box.add(new Label(_("The server requires to sign up through a website")){ use_markup=true, visible=true } ); + form_box.add(new Label(@"$(form.oob)") { use_markup=true, visible=true }); + register_form_continue_label.label = _("Open Registration"); + register_form_continue.visible = true; + register_form_continue.grab_focus(); + } else if (form.fields.size > 0) { + int i = 0; + foreach (Xep.DataForms.DataForm.Field field in form.fields) { + if (field.label != null && field.label != "") { + form_box.add(new Label(field.label) { xalign=0, margin_top=7, visible=true }); + } + Widget field_widget = Util.get_data_form_fild_widget(field); + if (field_widget != null) { + form_box.add(field_widget); + } + i++; + } + register_form_continue.visible = true; + register_form_continue_label.label = _("Register"); + } else { + form_box.add(new Label(_("Check %s for information on how to sign up").printf(@"$(server)")) { use_markup=true, visible=true }); + register_form_continue.visible = false; + } + } + + private async void on_register_form_continue_clicked() { + notification_revealer.set_reveal_child(false); + // Button is opening a registration website + if (form.oob != null) { + try { + AppInfo.launch_default_for_uri(form.oob, null); + } catch (Error e) { } + show_sign_in(); + return; + } + + register_form_continue_stack.visible_child_name = "spinner"; + string? error = yield Register.submit_form(server_jid, form); + if (register_form_continue_stack == null) { + return; + } + register_form_continue_stack.visible_child_name = "label"; + if (error == null) { + string? username = null, password = null; + foreach (Xep.DataForms.DataForm.Field field in form.fields) { + switch (field.var) { + case "username": username = field.get_value_string(); break; + case "password": password = field.get_value_string(); break; + } + } + store_account(new Jid(username + "@" + server_jid.domainpart), password, ""); + close(); + } else { + display_notification(error); + } + } + + private void store_account(Jid jid, string password, string? alias) { Account account = new Account(jid, null, password, alias); added(account); - close(); + } + + private void display_notification(string text) { + notification_label.label = text; + notification_revealer.set_reveal_child(true); + Timeout.add_seconds(5, () => { + notification_revealer.set_reveal_child(false); + return false; + }); + } + + 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; + }); } } diff --git a/main/src/ui/util/data_forms.vala b/main/src/ui/util/data_forms.vala new file mode 100644 index 00000000..11308462 --- /dev/null +++ b/main/src/ui/util/data_forms.vala @@ -0,0 +1,57 @@ +using Gee; +using Gtk; + +using Dino.Entities; +using Xmpp.Xep; + +namespace Dino.Ui.Util { + +public static Widget? get_data_form_fild_widget(DataForms.DataForm.Field field) { + if (field.type_ == null) return null; + 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, valign=Align.CENTER, visible=true }; + sw.state_set.connect((state) => { + boolean_field.value = state; + return false; + }); + return sw; + case DataForms.DataForm.Type.JID_MULTI: + 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 }; + 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); + if (option.value == list_single_field.value) combobox.active = i; + } + combobox.changed.connect(() => { + list_single_field.value = combobox.get_active_id(); + }); + return combobox; + case DataForms.DataForm.Type.LIST_MULTI: + 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.key_release_event.connect(() => { + text_private_field.value = entry.text; + return false; + }); + 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.key_release_event.connect(() => { + text_single_field.value = entry.text; + return false; + }); + return entry; + default: + return null; + } +} + +} -- cgit v1.2.3-54-g00ecf