[calls] Introduce CallsAccountOverview: A UI to allow managing VoIP accounts



commit fc7156fe75cae6875704d31104cb25f980d310cb
Author: Evangelos Ribeiro Tzaras <evangelos tzaras puri sm>
Date:   Tue May 11 18:18:35 2021 +0200

    Introduce CallsAccountOverview: A UI to allow managing VoIP accounts
    
    CallsAccountOverview allows user to view, add and edit VoIP accounts
    (currently SIP only).
    
    Each CallsAccount is represented by a CallsAccountRow.
    
    account-row: Staying alive

 src/calls-account-overview.c | 191 ++++++++++++++++++++++++++++++
 src/calls-account-overview.h |  37 ++++++
 src/calls-account-row.c      | 269 +++++++++++++++++++++++++++++++++++++++++++
 src/calls-account-row.h      |  46 ++++++++
 src/calls-application.c      |  11 ++
 src/calls-main-window.c      |  17 +++
 src/calls-main-window.h      |   9 +-
 src/calls.gresources.xml     |   2 +
 src/meson.build              |   2 +
 src/ui/account-overview.ui   |  99 ++++++++++++++++
 src/ui/account-row.ui        |  41 +++++++
 src/ui/main-window.ui        |  17 +--
 12 files changed, 729 insertions(+), 12 deletions(-)
---
diff --git a/src/calls-account-overview.c b/src/calls-account-overview.c
new file mode 100644
index 00000000..5ebe7b2d
--- /dev/null
+++ b/src/calls-account-overview.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2021 Purism SPC
+ *
+ * This file is part of Calls.
+ *
+ * Calls is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Calls is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Calls.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Evangelos Ribeiro Tzaras <evangelos tzaras puri sm>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#define G_LOG_DOMAIN "CallsAccountOverview"
+
+#include "calls-account.h"
+#include "calls-account-overview.h"
+#include "calls-account-row.h"
+#include "calls-account-provider.h"
+
+
+/**
+ * Section:calls-account-overview
+ * short_description: A #HdyWindow to manage VoIP accounts
+ * @Title: CallsAccountOverview
+ *
+ * This is a #HdyWindow derived window to display and manage the
+ * VoIP accounts. Each available #CallsAccount from any #CallsAccountProvider
+ * will be listed as a #CallsAccountRow.
+ */
+
+typedef enum {
+  SHOW_INTRO = 0,
+  SHOW_OVERVIEW,
+} CallsAccountOverviewState;
+
+
+struct _CallsAccountOverview {
+  HdyWindow                  parent;
+
+  /* UI widgets */
+  GtkStack                  *stack;
+  GtkWidget                 *intro;
+  GtkWidget                 *overview;
+  GtkWidget                 *add_btn;
+  GtkWidget                 *add_row;
+
+  /* The window where we add the account providers widget */
+  GtkWindow                 *account_window;
+  GtkWidget                 *current_account_widget;
+
+  /* misc */
+  CallsAccountOverviewState  state;
+  GList                     *providers;
+};
+
+G_DEFINE_TYPE (CallsAccountOverview, calls_account_overview, HDY_TYPE_WINDOW)
+
+
+static void
+update_visibility (CallsAccountOverview *self)
+{
+  g_assert (CALLS_IS_ACCOUNT_OVERVIEW (self));
+
+  switch (self->state) {
+  case SHOW_INTRO:
+    gtk_stack_set_visible_child (self->stack, self->intro);
+    break;
+
+  case SHOW_OVERVIEW:
+    gtk_stack_set_visible_child (self->stack, self->overview);
+    break;
+
+  default:
+    g_warn_if_reached ();
+  }
+}
+
+
+static void
+update_state (CallsAccountOverview *self)
+{
+  guint n_origins = 0;
+
+  g_assert (CALLS_IS_ACCOUNT_OVERVIEW (self));
+
+  for (GList *node = self->providers; node != NULL; node = node->next) {
+    CallsProvider *provider = CALLS_PROVIDER (node->data);
+    GListModel *model = calls_provider_get_origins (provider);
+
+    n_origins += g_list_model_get_n_items (model);
+  }
+
+  if (n_origins > 0)
+    self->state = SHOW_OVERVIEW;
+  else
+    self->state = SHOW_INTRO;
+
+  update_visibility (self);
+}
+
+
+static void
+attach_account_widget (CallsAccountOverview *self,
+                       GtkWidget            *widget)
+{
+  g_assert (CALLS_IS_ACCOUNT_OVERVIEW (self));
+  g_assert (!widget || GTK_IS_WIDGET (widget));
+
+  if (widget == self->current_account_widget)
+    return;
+
+  if (self->current_account_widget)
+    gtk_container_remove (GTK_CONTAINER (self->account_window),
+                          self->current_account_widget);
+
+  self->current_account_widget = widget;
+  if (widget)
+    gtk_container_add (GTK_CONTAINER (self->account_window), widget);
+}
+
+
+static void
+on_add_account_clicked (CallsAccountOverview *self)
+{
+  CallsAccountProvider *provider;
+  GtkWidget *widget;
+
+  /* For now we only have a single AccountProvider */
+  provider = CALLS_ACCOUNT_PROVIDER (self->providers->data);
+
+  widget = calls_account_provider_get_account_widget (provider);
+  attach_account_widget (self, widget);
+
+  calls_account_provider_add_new_account (provider);
+
+  gtk_window_present (self->account_window);
+}
+
+
+static void
+calls_account_overview_class_init (CallsAccountOverviewClass *klass)
+{
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/Calls/ui/account-overview.ui");
+
+  gtk_widget_class_bind_template_child (widget_class, CallsAccountOverview, add_btn);
+  gtk_widget_class_bind_template_child (widget_class, CallsAccountOverview, add_row);
+
+  gtk_widget_class_bind_template_child (widget_class, CallsAccountOverview, stack);
+  gtk_widget_class_bind_template_child (widget_class, CallsAccountOverview, intro);
+  gtk_widget_class_bind_template_child (widget_class, CallsAccountOverview, overview);
+
+  gtk_widget_class_bind_template_child (widget_class, CallsAccountOverview, account_window);
+
+  gtk_widget_class_bind_template_callback (widget_class, on_add_account_clicked);
+}
+
+
+static void
+calls_account_overview_init (CallsAccountOverview *self)
+{
+  gtk_widget_init_template (GTK_WIDGET (self));
+
+  gtk_list_box_insert (GTK_LIST_BOX (self->overview),
+                       GTK_WIDGET (self->add_row),
+                       -1);
+  gtk_window_set_transient_for (self->account_window, GTK_WINDOW (self));
+
+  update_state (self);
+}
+
+
+CallsAccountOverview *
+calls_account_overview_new (void)
+{
+  return g_object_new (CALLS_TYPE_ACCOUNT_OVERVIEW,
+                       NULL);
+}
diff --git a/src/calls-account-overview.h b/src/calls-account-overview.h
new file mode 100644
index 00000000..236a2218
--- /dev/null
+++ b/src/calls-account-overview.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 Purism SPC
+ *
+ * This file is part of Calls.
+ *
+ * Calls is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Calls is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Calls.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Evangelos Ribeiro Tzaras <evangelos tzaras puri sm>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#pragma once
+
+#include <handy.h>
+
+G_BEGIN_DECLS
+
+#define CALLS_TYPE_ACCOUNT_OVERVIEW (calls_account_overview_get_type ())
+
+G_DECLARE_FINAL_TYPE (CallsAccountOverview, calls_account_overview, CALLS, ACCOUNT_OVERVIEW, HdyWindow)
+
+CallsAccountOverview  *calls_account_overview_new                   (void);
+
+G_END_DECLS
diff --git a/src/calls-account-row.c b/src/calls-account-row.c
new file mode 100644
index 00000000..1824c5c7
--- /dev/null
+++ b/src/calls-account-row.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2021 Purism SPC
+ *
+ * This file is part of Calls.
+ *
+ * Calls is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Calls is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Calls.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Evangelos Ribeiro Tzaras <evangelos tzaras puri sm>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#define G_LOG_DOMAIN "CallsAccountRow"
+
+#include "calls-account-row.h"
+#include "calls-account-provider.h"
+
+
+/**
+ * Section:calls-account-row
+ * short_description: A #HdyActionRow for use in #CallsAccountOverview
+ * @Title: CallsAccountRow
+ *
+ * This is a #HdyActionRow derived widget representing a #CallsAccount
+ * for VoIP accounts (currently only SIP).
+ */
+
+
+enum {
+  PROP_0,
+  PROP_PROVIDER,
+  PROP_ACCOUNT,
+  PROP_ONLINE,
+  PROP_LAST_PROP
+};
+static GParamSpec *props[PROP_LAST_PROP];
+
+enum {
+  EDIT_CLICKED,
+  N_SIGNALS
+};
+static guint signals[N_SIGNALS];
+
+struct _CallsAccountRow {
+  HdyActionRow          parent;
+
+  CallsAccountProvider *provider;
+  CallsAccount         *account;
+  gboolean              online;
+
+  /* UI elements */
+  HdyAvatar            *avatar;
+  GtkSwitch            *online_switch;
+  GtkButton            *edit_btn;
+};
+
+G_DEFINE_TYPE (CallsAccountRow, calls_account_row, HDY_TYPE_ACTION_ROW)
+
+
+static void
+on_account_state_changed (CallsAccountRow *self)
+{
+  CallsAccountState state = calls_account_get_state (self->account);
+
+  gtk_switch_set_active (self->online_switch, state == CALLS_ACCOUNT_ONLINE);
+}
+
+static void
+on_edit_clicked (CallsAccountRow *self)
+{
+  /** CallsAccountOverview connects to this signal to show
+   *  the window containing the account providers widget.
+   *  See calls_account_provider_get_account_widget()
+   */
+  g_signal_emit (self, signals[EDIT_CLICKED], 0, self->provider, self->account);
+}
+
+
+static void
+on_online_switched (CallsAccountRow *self)
+{
+  gboolean online;
+
+  g_assert (CALLS_IS_ACCOUNT_ROW (self));
+
+  online = gtk_switch_get_active (self->online_switch);
+  calls_account_go_online (self->account, online);
+}
+
+
+static void
+calls_account_row_set_property (GObject      *object,
+                                guint         property_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+  CallsAccountRow *self = CALLS_ACCOUNT_ROW (object);
+
+  switch (property_id) {
+  case PROP_PROVIDER:
+    self->provider = g_value_get_object (value);
+    break;
+
+  case PROP_ACCOUNT:
+    self->account = g_value_get_object (value);
+    g_object_bind_property (self->account, "name",
+                            self, "title",
+                            G_BINDING_SYNC_CREATE);
+    g_object_bind_property (self->account, "address",
+                            self, "subtitle",
+                            G_BINDING_SYNC_CREATE);
+
+    g_signal_connect_object (self->account, "notify::account-state",
+                             G_CALLBACK (on_account_state_changed), self,
+                             G_CONNECT_SWAPPED);
+    on_account_state_changed (self);
+    break;
+
+  case PROP_ONLINE:
+    calls_account_row_set_online (self, g_value_get_boolean (value));
+    break;
+
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    break;
+  }
+}
+
+
+static void
+calls_account_row_get_property (GObject      *object,
+                                guint         property_id,
+                                GValue       *value,
+                                GParamSpec   *pspec)
+{
+  CallsAccountRow *self = CALLS_ACCOUNT_ROW (object);
+
+  switch (property_id) {
+  case PROP_ACCOUNT:
+    g_value_set_object (value, calls_account_row_get_account (self));
+    break;
+
+  case PROP_ONLINE:
+    g_value_set_boolean (value, calls_account_row_get_online (self));
+    break;
+
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    break;
+  }
+}
+
+
+static void
+calls_account_row_class_init (CallsAccountRowClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->set_property = calls_account_row_set_property;
+  object_class->get_property = calls_account_row_get_property;
+
+  signals[EDIT_CLICKED] =
+    g_signal_new ("edit-clicked",
+                  CALLS_TYPE_ACCOUNT_ROW,
+                  G_SIGNAL_RUN_FIRST,
+                  0,
+                  NULL, NULL, NULL,
+                  G_TYPE_NONE,
+                  2,
+                  CALLS_TYPE_ACCOUNT_PROVIDER,
+                  CALLS_TYPE_ACCOUNT);
+
+  props[PROP_PROVIDER] =
+    g_param_spec_object ("provider",
+                         "Provider",
+                         "The provider of the account this row represents",
+                         CALLS_TYPE_ACCOUNT_PROVIDER,
+                         G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_STATIC_STRINGS);
+
+  props[PROP_ACCOUNT] =
+    g_param_spec_object ("account",
+                         "Account",
+                         "The account this row represents",
+                         CALLS_TYPE_ACCOUNT,
+                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+  props[PROP_ONLINE] =
+    g_param_spec_boolean ("online",
+                          "online",
+                          "The state of the online switch",
+                          FALSE,
+                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (object_class, PROP_LAST_PROP, props);
+
+  gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/Calls/ui/account-row.ui");
+  gtk_widget_class_bind_template_child (widget_class, CallsAccountRow, avatar);
+  gtk_widget_class_bind_template_child (widget_class, CallsAccountRow, online_switch);
+  gtk_widget_class_bind_template_child (widget_class, CallsAccountRow, edit_btn);
+
+ gtk_widget_class_bind_template_callback (widget_class, on_edit_clicked);
+ gtk_widget_class_bind_template_callback (widget_class, on_online_switched);
+}
+
+
+static void
+calls_account_row_init (CallsAccountRow *self)
+{
+  gtk_widget_init_template (GTK_WIDGET (self));
+}
+
+
+CallsAccountRow *
+calls_account_row_new (CallsAccountProvider *provider,
+                       CallsAccount         *account)
+{
+  g_return_val_if_fail (CALLS_IS_ACCOUNT (account), NULL);
+
+  return g_object_new (CALLS_TYPE_ACCOUNT_ROW,
+                       "provider", provider,
+                       "account", account,
+                       NULL);
+}
+
+
+gboolean
+calls_account_row_get_online (CallsAccountRow *self)
+{
+  g_return_val_if_fail (CALLS_IS_ACCOUNT_ROW (self), FALSE);
+
+  return gtk_switch_get_active (self->online_switch);
+}
+
+
+void
+calls_account_row_set_online (CallsAccountRow *self,
+                              gboolean         online)
+{
+  g_return_if_fail (CALLS_IS_ACCOUNT_ROW (self));
+
+  if (online == gtk_switch_get_active (self->online_switch))
+    return;
+
+  gtk_switch_set_active (self->online_switch, online);
+}
+
+
+CallsAccount *
+calls_account_row_get_account (CallsAccountRow *self)
+{
+  g_return_val_if_fail (CALLS_IS_ACCOUNT_ROW (self), NULL);
+
+  return self->account;
+}
diff --git a/src/calls-account-row.h b/src/calls-account-row.h
new file mode 100644
index 00000000..1ab69718
--- /dev/null
+++ b/src/calls-account-row.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 Purism SPC
+ *
+ * This file is part of Calls.
+ *
+ * Calls is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Calls is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Calls.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Evangelos Ribeiro Tzaras <evangelos tzaras puri sm>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#pragma once
+
+#include "calls-account.h"
+#include "calls-account-provider.h"
+
+#include <handy.h>
+
+
+G_BEGIN_DECLS
+
+#define CALLS_TYPE_ACCOUNT_ROW (calls_account_row_get_type ())
+
+G_DECLARE_FINAL_TYPE (CallsAccountRow, calls_account_row, CALLS, ACCOUNT_ROW, HdyActionRow)
+
+CallsAccountRow      *calls_account_row_new              (CallsAccountProvider *provider,
+                                                          CallsAccount         *account);
+gboolean              calls_account_row_get_online       (CallsAccountRow      *self);
+void                  calls_account_row_set_online       (CallsAccountRow      *self,
+                                                          gboolean              online);
+CallsAccount         *calls_account_row_get_account      (CallsAccountRow      *self);
+
+G_END_DECLS
diff --git a/src/calls-application.c b/src/calls-application.c
index 54ad8617..fcddb549 100644
--- a/src/calls-application.c
+++ b/src/calls-application.c
@@ -350,6 +350,15 @@ copy_number (GSimpleAction *action,
   g_debug ("Copied `%s' to clipboard", number);
 }
 
+static void
+show_accounts (GSimpleAction *action,
+               GVariant      *parameter,
+               gpointer       user_data)
+{
+  CallsApplication *app = CALLS_APPLICATION (g_application_get_default ());
+  calls_main_window_show_accounts_overview (app->main_window);
+}
+
 static void
 manager_state_changed_cb (GApplication *application)
 {
@@ -366,6 +375,8 @@ static const GActionEntry actions[] =
   { "set-daemon", set_daemon_action, NULL },
   { "dial", dial_action, "s" },
   { "copy-number", copy_number, "s"},
+  /* TODO About dialog { "about", show_about, NULL}, */
+  { "accounts", show_accounts, NULL},
 };
 
 
diff --git a/src/calls-main-window.c b/src/calls-main-window.c
index b764547a..8fff4e79 100644
--- a/src/calls-main-window.c
+++ b/src/calls-main-window.c
@@ -23,6 +23,7 @@
  */
 
 #include "calls-main-window.h"
+#include "calls-account-overview.h"
 #include "calls-origin.h"
 #include "calls-ussd.h"
 #include "calls-call-selector-item.h"
@@ -54,6 +55,7 @@ struct _CallsMainWindow
   GtkRevealer *permanent_error_revealer;
   GtkLabel *permanent_error_label;
 
+  CallsAccountOverview *account_overview;
   CallsNewCallBox *new_call;
 
   GtkDialog  *ussd_dialog;
@@ -426,6 +428,7 @@ dispose (GObject *object)
   CallsMainWindow *self = CALLS_MAIN_WINDOW (object);
 
   g_clear_object (&self->record_store);
+  g_clear_object (&self->account_overview);
 
   G_OBJECT_CLASS (calls_main_window_parent_class)->dispose (object);
 }
@@ -531,3 +534,17 @@ calls_main_window_dial (CallsMainWindow *self,
       calls_new_call_box_dial (self->new_call, target);
     }
 }
+
+void
+calls_main_window_show_accounts_overview (CallsMainWindow *self)
+{
+  g_return_if_fail (CALLS_IS_MAIN_WINDOW (self));
+
+  if (self->account_overview == NULL) {
+    self->account_overview = calls_account_overview_new ();
+    gtk_window_set_transient_for (GTK_WINDOW (self->account_overview),
+                                  GTK_WINDOW (self));
+  }
+
+  gtk_window_present (GTK_WINDOW (self->account_overview));
+}
diff --git a/src/calls-main-window.h b/src/calls-main-window.h
index a058ff48..b5f3085c 100644
--- a/src/calls-main-window.h
+++ b/src/calls-main-window.h
@@ -33,10 +33,11 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (CallsMainWindow, calls_main_window, CALLS, MAIN_WINDOW, HdyApplicationWindow);
 
-CallsMainWindow *calls_main_window_new  (GtkApplication  *application,
-                                         GListModel      *record_store);
-void             calls_main_window_dial (CallsMainWindow *self,
-                                         const gchar     *target);
+CallsMainWindow       *calls_main_window_new                      (GtkApplication  *application,
+                                                                   GListModel      *record_store);
+void                   calls_main_window_dial                     (CallsMainWindow *self,
+                                                                   const gchar     *target);
+void                   calls_main_window_show_accounts_overview   (CallsMainWindow *self);
 
 G_END_DECLS
 
diff --git a/src/calls.gresources.xml b/src/calls.gresources.xml
index 9a4e4ca1..09a0cde2 100644
--- a/src/calls.gresources.xml
+++ b/src/calls.gresources.xml
@@ -14,6 +14,8 @@
     <file preprocess="xml-stripblanks">in-app-notification.ui</file>
     <file preprocess="xml-stripblanks">contacts-row.ui</file>
     <file preprocess="xml-stripblanks">contacts-box.ui</file>
+    <file preprocess="xml-stripblanks">account-overview.ui</file>
+    <file preprocess="xml-stripblanks">account-row.ui</file>
   </gresource>
   <gresource prefix="/org/gnome/Calls/">
     <file>style.css</file>
diff --git a/src/meson.build b/src/meson.build
index 7a15fc90..290b6e2f 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -108,6 +108,8 @@ calls_sources = files(['calls-message-source.c', 'calls-message-source.h',
                        'calls-contacts-row.c', 'calls-contacts-row.h',
                        'calls-account.c', 'calls-account.h',
                        'calls-account-provider.c', 'calls-account-provider.h',
+                       'calls-account-overview.c', 'calls-account-overview.h',
+                       'calls-account-row.c', 'calls-account-row.h',
                        'calls-settings.c', 'calls-settings.h',
                       ]) + calls_generated_sources
 
diff --git a/src/ui/account-overview.ui b/src/ui/account-overview.ui
new file mode 100644
index 00000000..5361fb36
--- /dev/null
+++ b/src/ui/account-overview.ui
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="3.24"/>
+  <requires lib="libhandy" version="1.0"/>
+  <template class="CallsAccountOverview" parent="HdyWindow">
+    <property name="visible">True</property>
+    <property name="default-width">380</property>
+    <property name="default-height">660</property>
+    <signal name="delete-event" handler="gtk_widget_hide_on_delete"/>
+    <child>
+      <object class="GtkBox">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="HdyHeaderBar">
+            <property name="title" translatable="yes">VoIP Accounts</property>
+            <property name="show-close-button">True</property>
+            <property name="visible">True</property>
+            <child>
+              <object class="GtkSpinner" id="spinner">
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="pack_type">end</property>
+              </packing>
+            </child>
+
+          </object>
+        </child>
+
+        <child>
+          <object class="GtkStack" id="stack">
+            <property name="visible">True</property>
+            <property name="vexpand">True</property>
+            <property name="transition-type">crossfade</property>
+
+            <!-- First child type: No accounts present: Show a blurb and a Add button -->
+            <child>
+              <object class="HdyStatusPage" id="intro">
+                <property name="visible">True</property>
+                <property name="title" translatable="yes">Add VoIP Accounts</property>
+                <property name="icon-name">system-users-symbolic</property>
+                <property name="description" translatable="yes">You can add VoIP account here. It will allow 
you to place and receive VoIP calls using the SIP protocol. This feature is still relatively new and not yet 
feature complete (i.e. no encrypted media).</property>
+                <child>
+                  <object class="GtkButton" id="add_btn">
+                    <property name="visible">True</property>
+                    <property name="margin">6</property>
+                    <property name="halign">center</property>
+                    <property name="use-underline">True</property>
+                    <property name="label" translatable="yes">_Add Account</property>
+                    <signal name="clicked" handler="on_add_account_clicked" swapped="yes"/>
+                    <style>
+                      <class name="suggested-action"/>
+                    </style>
+                  </object>
+                </child>
+
+              </object>
+              <packing>
+                <property name="name">intro-page</property>
+              </packing>
+            </child>
+
+            <!-- Second child type: Some accounts present: Show a Listbox to manage accounts -->
+            <child>
+              <object class="GtkListBox" id="overview">
+                <property name="visible">True</property>
+                <property name="selection-mode">none</property>
+                <!-- placeholder -->
+                <child type="placeholder"/>
+              </object>
+              <packing>
+                <property name="name">overview-page</property>
+              </packing>
+            </child>
+
+          </object>
+        </child>
+
+      </object>
+    </child>
+  </template>
+
+  <object class="HdyActionRow" id="add_row">
+    <property name="visible">True</property>
+    <property name="use-underline">True</property>
+    <property name="activatable">True</property>
+    <property name="title" translatable="yes">_Add Account</property>
+    <signal name="activated" handler="on_add_account_clicked" swapped="yes"/>
+  </object>
+
+  <object class="HdyWindow" id="account_window">
+    <property name="visible">False</property>
+    <property name="default-width">380</property>
+    <property name="default-height">660</property>
+    <signal name="delete-event" handler="gtk_widget_hide_on_delete"/>
+  </object>
+
+  </interface>
diff --git a/src/ui/account-row.ui b/src/ui/account-row.ui
new file mode 100644
index 00000000..9be9fa6d
--- /dev/null
+++ b/src/ui/account-row.ui
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="3.20"/>
+  <requires lib="libhandy" version="1.0"/>
+  <template class="CallsAccountRow" parent="HdyActionRow">
+    <property name="visible">True</property>
+    <property name="title">Title</property>
+    <property name="subtitle">Subtitle</property>
+    <property name="activatable">True</property>
+
+    <child type="prefix">
+      <object class="HdyAvatar" id="avatar">
+        <property name="visible">True</property>
+        <property name="show-initials">True</property>
+        <property name="size">48</property>
+      </object>
+    </child>
+
+    <child>
+      <object class="GtkSwitch" id="online_switch">
+        <property name="valign">center</property>
+        <property name="visible">True</property>
+        <property name="active">False</property>
+        <signal name="notify::active" handler="on_online_switched" swapped="yes"/>
+      </object>
+    </child>
+
+    <child>
+      <object class="GtkButton" id="edit_btn">
+        <property name="visible">True</property>
+        <child>
+          <object class="GtkImage">
+            <property name="visible">True</property>
+            <property name="icon_name">go-next-symbolic</property>
+          </object>
+        </child>
+        <signal name="clicked" handler="on_edit_clicked" swapped="yes"/>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/ui/main-window.ui b/src/ui/main-window.ui
index ae598c09..597c4920 100644
--- a/src/ui/main-window.ui
+++ b/src/ui/main-window.ui
@@ -30,7 +30,7 @@
             </child>
             <child>
               <object class="GtkMenuButton">
-                <property name="visible">False</property>
+                <property name="visible">True</property>
                 <property name="can_focus">False</property>
                 <property name="popover">menu_popover</property>
                 <child>
@@ -225,8 +225,8 @@
         <child>
           <object class="GtkModelButton">
             <property name="visible">True</property>
-            <property name="text" translatable="yes">VoIP Accounts</property>
-            <!--<property name="action-name">app.voip-accounts</property>-->
+            <property name="text" translatable="yes">_VoIP Accounts</property>
+            <property name="action-name">app.accounts</property>
           </object>
         </child>
         <child>
@@ -237,20 +237,21 @@
         </child>
         <child>
           <object class="GtkModelButton">
-            <property name="visible">True</property>
-            <property name="text" translatable="yes">Keyboard shortcuts</property>
+            <property name="visible">False</property>
+            <property name="text" translatable="yes">_Keyboard shortcuts</property>
           </object>
         </child>
         <child>
           <object class="GtkModelButton">
-            <property name="visible">True</property>
-            <property name="text" translatable="yes">Help</property>
+            <property name="visible">False</property>
+            <property name="text" translatable="yes">_Help</property>
           </object>
         </child>
         <child>
           <object class="GtkModelButton">
             <property name="visible">True</property>
-            <property name="text" translatable="yes">About Calls</property>
+            <property name="text" translatable="yes">_About Calls</property>
+            <property name="action-name">app.about</property>
           </object>
         </child>
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]