diff --git a/src/calls-account-overview.c b/src/calls-account-overview.c
new file mode 100644
index 0000000..5ebe7b2
--- /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 .
+ *
+ * Author: Evangelos Ribeiro Tzaras
+ *
+ * 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 0000000..236a221
--- /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 .
+ *
+ * Author: Evangelos Ribeiro Tzaras
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#pragma once
+
+#include
+
+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 0000000..1824c5c
--- /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 .
+ *
+ * Author: Evangelos Ribeiro Tzaras
+ *
+ * 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 0000000..1ab6971
--- /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 .
+ *
+ * Author: Evangelos Ribeiro Tzaras
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#pragma once
+
+#include "calls-account.h"
+#include "calls-account-provider.h"
+
+#include
+
+
+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 54ad861..fcddb54 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 b764547..8fff4e7 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 a058ff4..b5f3085 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 9a4e4ca..09a0cde 100644
--- a/src/calls.gresources.xml
+++ b/src/calls.gresources.xml
@@ -14,6 +14,8 @@
in-app-notification.ui
contacts-row.ui
contacts-box.ui
+ account-overview.ui
+ account-row.ui
style.css
diff --git a/src/meson.build b/src/meson.build
index 7a15fc9..290b6e2 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 0000000..5361fb3
--- /dev/null
+++ b/src/ui/account-overview.ui
@@ -0,0 +1,99 @@
+
+
+
+
+
+ True
+ 380
+ 660
+
+
+
+
+
+
+
+ True
+ True
+ True
+ _Add Account
+
+
+
+
+ False
+ 380
+ 660
+
+
+
+
diff --git a/src/ui/account-row.ui b/src/ui/account-row.ui
new file mode 100644
index 0000000..9be9fa6
--- /dev/null
+++ b/src/ui/account-row.ui
@@ -0,0 +1,41 @@
+
+
+
+
+
+ True
+ Title
+ Subtitle
+ True
+
+
+
+ True
+ True
+ 48
+
+
+
+
+
+ center
+ True
+ False
+
+
+
+
+
+
+ True
+
+
+ True
+ go-next-symbolic
+
+
+
+
+
+
+
diff --git a/src/ui/main-window.ui b/src/ui/main-window.ui
index ae598c0..597c492 100644
--- a/src/ui/main-window.ui
+++ b/src/ui/main-window.ui
@@ -30,7 +30,7 @@