gnome: add account settings

Refs #68670

Change-Id: I24684d1562a27180dcf684747e90d8c92cc07250
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 39cb6ba..8a18197 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -140,6 +140,14 @@
    src/backends/minimalhistorybackend.cpp
    src/models/gtkqsortfiltertreemodel.h
    src/models/gtkqsortfiltertreemodel.cpp
+   src/accountview.h
+   src/accountview.cpp
+   src/accountgeneraltab.h
+   src/accountgeneraltab.cpp
+   src/accountaudiotab.h
+   src/accountaudiotab.cpp
+   src/accountvideotab.h
+   src/accountvideotab.cpp
 )
 
 # compile glib resource files to c code
diff --git a/src/accountaudiotab.cpp b/src/accountaudiotab.cpp
new file mode 100644
index 0000000..cb3388e
--- /dev/null
+++ b/src/accountaudiotab.cpp
@@ -0,0 +1,233 @@
+/*
+ *  Copyright (C) 2015 Savoir-Faire Linux Inc.
+ *  Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
+ *
+ *  This program 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.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify this program, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ *  grants you additional permission to convey the resulting work.
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+
+#include "accountaudiotab.h"
+
+#include <gtk/gtk.h>
+#include <account.h>
+#include <audio/codecmodel.h>
+#include "models/gtkqsortfiltertreemodel.h"
+
+struct _AccountAudioTab
+{
+    GtkBox parent;
+};
+
+struct _AccountAudioTabClass
+{
+    GtkBoxClass parent_class;
+};
+
+typedef struct _AccountAudioTabPrivate AccountAudioTabPrivate;
+
+struct _AccountAudioTabPrivate
+{
+    Account   *account;
+    GtkWidget *treeview_codecs;
+    GtkWidget *button_moveup;
+    GtkWidget *button_movedown;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(AccountAudioTab, account_audio_tab, GTK_TYPE_BOX);
+
+#define ACCOUNT_AUDIO_TAB_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ACCOUNT_AUDIO_TAB_TYPE, AccountAudioTabPrivate))
+
+static void
+account_audio_tab_dispose(GObject *object)
+{
+    G_OBJECT_CLASS(account_audio_tab_parent_class)->dispose(object);
+}
+
+static void
+account_audio_tab_init(AccountAudioTab *view)
+{
+    gtk_widget_init_template(GTK_WIDGET(view));
+}
+
+static void
+account_audio_tab_class_init(AccountAudioTabClass *klass)
+{
+    G_OBJECT_CLASS(klass)->dispose = account_audio_tab_dispose;
+
+    gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
+                                                "/cx/ring/RingGnome/accountaudiotab.ui");
+
+    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountAudioTab, treeview_codecs);
+    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountAudioTab, button_moveup);
+    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountAudioTab, button_movedown);
+}
+
+static void
+codec_active_toggled(GtkCellRendererToggle *renderer, gchar *path, AccountAudioTab *view)
+{
+    g_return_if_fail(IS_ACCOUNT_AUDIO_TAB(view));
+    AccountAudioTabPrivate *priv = ACCOUNT_AUDIO_TAB_GET_PRIVATE(view);
+
+    /* we want to set it to the opposite of the current value */
+    gboolean toggle = !gtk_cell_renderer_toggle_get_active(renderer);
+
+    /* get iter which was clicked */
+    GtkTreePath *tree_path = gtk_tree_path_new_from_string(path);
+    GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(priv->treeview_codecs));
+    GtkTreeIter iter;
+    gtk_tree_model_get_iter(model, &iter, tree_path);
+
+    /* get qmodelindex from iter and set the model data */
+    QModelIndex idx = gtk_q_sort_filter_tree_model_get_source_idx(GTK_Q_SORT_FILTER_TREE_MODEL(model), &iter);
+    if (idx.isValid()) {
+        priv->account->codecModel()->audioCodecs()->setData(idx, QVariant(toggle), Qt::CheckStateRole);
+        priv->account->codecModel()->save();
+    }
+}
+
+static QModelIndex
+get_index_from_selection(GtkTreeSelection *selection)
+{
+    GtkTreeIter iter;
+    GtkTreeModel *model = NULL;
+
+    if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
+        return gtk_q_sort_filter_tree_model_get_source_idx(GTK_Q_SORT_FILTER_TREE_MODEL(model), &iter);
+    } else {
+        return QModelIndex();
+    }
+}
+
+static void
+move_selected_codec(AccountAudioTab *view, int position_diff)
+{
+    g_return_if_fail(IS_ACCOUNT_AUDIO_TAB(view));
+    AccountAudioTabPrivate *priv = ACCOUNT_AUDIO_TAB_GET_PRIVATE(view);
+
+    GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_codecs));
+    QModelIndex idx = get_index_from_selection(selection);
+
+    if(!idx.isValid())
+        return;
+
+    QMimeData* mime = priv->account->codecModel()->audioCodecs()->mimeData(QModelIndexList() << idx);
+    priv->account->codecModel()->audioCodecs()->dropMimeData(
+                                                    mime,
+                                                    Qt::MoveAction,
+                                                    idx.row() + position_diff,
+                                                    0,
+                                                    QModelIndex());
+    priv->account->saveCodecs();
+
+    /* now make sure to select the same codec which was moved
+     * TODO: UGLY! this should be somehow done in the qt modle bindings,
+     *       or via a selection model, not here
+     */
+    int new_row = idx.row() + position_diff;
+    int row_count = priv->account->codecModel()->audioCodecs()->rowCount(idx.parent());
+    if (new_row < 0)
+        new_row = row_count - 1;
+    else if (new_row >= row_count)
+        new_row = 0;
+
+    idx = idx.sibling(new_row, idx.column());
+    GtkTreeIter iter;
+    if (gtk_q_sort_filter_tree_model_source_index_to_iter(
+            GTK_Q_SORT_FILTER_TREE_MODEL(gtk_tree_view_get_model(GTK_TREE_VIEW(priv->treeview_codecs))),
+            idx,
+            &iter)) {
+        gtk_tree_selection_select_iter(selection, &iter);
+    }
+}
+
+static void
+move_codec_up(G_GNUC_UNUSED GtkButton *button, AccountAudioTab *view)
+{
+    move_selected_codec(view, -1);
+}
+
+static void
+move_codec_down(G_GNUC_UNUSED GtkButton *button, AccountAudioTab *view)
+{
+    move_selected_codec(view, +1);
+}
+
+static void
+build_tab_view(AccountAudioTab *view)
+{
+    g_return_if_fail(IS_ACCOUNT_AUDIO_TAB(view));
+    AccountAudioTabPrivate *priv = ACCOUNT_AUDIO_TAB_GET_PRIVATE(view);
+
+    /* codec model */
+    GtkQSortFilterTreeModel *codec_model;
+    GtkCellRenderer *renderer;
+    GtkTreeViewColumn *column;
+
+    codec_model = gtk_q_sort_filter_tree_model_new(
+        priv->account->codecModel()->audioCodecs(),
+        4,
+        Qt::CheckStateRole, G_TYPE_BOOLEAN,
+        CodecModel::Role::NAME, G_TYPE_STRING,
+        CodecModel::Role::BITRATE, G_TYPE_STRING,
+        CodecModel::Role::SAMPLERATE, G_TYPE_STRING);
+    gtk_tree_view_set_model(GTK_TREE_VIEW(priv->treeview_codecs), GTK_TREE_MODEL(codec_model));
+
+    renderer = gtk_cell_renderer_toggle_new();
+    column = gtk_tree_view_column_new_with_attributes("Enabled", renderer, "active", 0, NULL);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(priv->treeview_codecs), column);
+
+    g_signal_connect(renderer, "toggled", G_CALLBACK(codec_active_toggled), view);
+
+    renderer = gtk_cell_renderer_text_new();
+    column = gtk_tree_view_column_new_with_attributes("Name", renderer, "text", 1, NULL);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(priv->treeview_codecs), column);
+
+    renderer = gtk_cell_renderer_text_new();
+    column = gtk_tree_view_column_new_with_attributes("Bitrate", renderer, "text", 2, NULL);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(priv->treeview_codecs), column);
+
+    renderer = gtk_cell_renderer_text_new();
+    column = gtk_tree_view_column_new_with_attributes("Samplerate", renderer, "text", 3, NULL);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(priv->treeview_codecs), column);
+
+    /* connect move codecs up/down signals */
+    g_signal_connect(priv->button_moveup, "clicked", G_CALLBACK(move_codec_up), view);
+    g_signal_connect(priv->button_movedown, "clicked", G_CALLBACK(move_codec_down), view);
+}
+
+GtkWidget *
+account_audio_tab_new(Account *account)
+{
+    g_return_val_if_fail(account != NULL, NULL);
+
+    gpointer view = g_object_new(ACCOUNT_AUDIO_TAB_TYPE, NULL);
+
+    AccountAudioTabPrivate *priv = ACCOUNT_AUDIO_TAB_GET_PRIVATE(view);
+    priv->account = account;
+
+    build_tab_view(ACCOUNT_AUDIO_TAB(view));
+
+    return (GtkWidget *)view;
+}
diff --git a/src/accountaudiotab.h b/src/accountaudiotab.h
new file mode 100644
index 0000000..6040137
--- /dev/null
+++ b/src/accountaudiotab.h
@@ -0,0 +1,53 @@
+/*
+ *  Copyright (C) 2015 Savoir-Faire Linux Inc.
+ *  Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
+ *
+ *  This program 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.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify this program, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ *  grants you additional permission to convey the resulting work.
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+
+#ifndef _ACCOUNTAUDIOTAB_H
+#define _ACCOUNTAUDIOTAB_H
+
+#include <gtk/gtk.h>
+#include <account.h>
+
+G_BEGIN_DECLS
+
+#define ACCOUNT_AUDIO_TAB_TYPE            (account_audio_tab_get_type ())
+#define ACCOUNT_AUDIO_TAB(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), ACCOUNT_AUDIO_TAB_TYPE, AccountAudioTab))
+#define ACCOUNT_AUDIO_TAB_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), ACCOUNT_AUDIO_TAB_TYPE, AccountAudioTabClass))
+#define IS_ACCOUNT_AUDIO_TAB(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), ACCOUNT_AUDIO_TAB_TYPE))
+#define IS_ACCOUNT_AUDIO_TAB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), ACCOUNT_AUDIO_TAB_TYPE))
+
+typedef struct _AccountAudioTab      AccountAudioTab;
+typedef struct _AccountAudioTabClass AccountAudioTabClass;
+
+GType      account_audio_tab_get_type      (void) G_GNUC_CONST;
+GtkWidget *account_audio_tab_new           (Account *account);
+
+G_END_DECLS
+
+#endif /* _ACCOUNTAUDIOTAB_H */
\ No newline at end of file
diff --git a/src/accountgeneraltab.cpp b/src/accountgeneraltab.cpp
new file mode 100644
index 0000000..f24c233
--- /dev/null
+++ b/src/accountgeneraltab.cpp
@@ -0,0 +1,340 @@
+/*
+ *  Copyright (C) 2015 Savoir-Faire Linux Inc.
+ *  Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
+ *
+ *  This program 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.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify this program, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ *  grants you additional permission to convey the resulting work.
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+
+#include "accountgeneraltab.h"
+
+#include <gtk/gtk.h>
+#include <account.h>
+
+struct _AccountGeneralTab
+{
+    GtkBox parent;
+};
+
+struct _AccountGeneralTabClass
+{
+    GtkBoxClass parent_class;
+};
+
+typedef struct _AccountGeneralTabPrivate AccountGeneralTabPrivate;
+
+struct _AccountGeneralTabPrivate
+{
+    Account   *account;
+    GtkWidget *grid_account;
+    GtkWidget *grid_parameters;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(AccountGeneralTab, account_general_tab, GTK_TYPE_BOX);
+
+#define ACCOUNT_GENERAL_TAB_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ACCOUNT_GENERAL_TAB_TYPE, AccountGeneralTabPrivate))
+
+static void
+account_general_tab_dispose(GObject *object)
+{
+    G_OBJECT_CLASS(account_general_tab_parent_class)->dispose(object);
+}
+
+static void
+account_general_tab_init(AccountGeneralTab *view)
+{
+    gtk_widget_init_template(GTK_WIDGET(view));
+}
+
+static void
+account_general_tab_class_init(AccountGeneralTabClass *klass)
+{
+    G_OBJECT_CLASS(klass)->dispose = account_general_tab_dispose;
+
+    gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
+                                                "/cx/ring/RingGnome/accountgeneraltab.ui");
+
+    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountGeneralTab, grid_account);
+    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountGeneralTab, grid_parameters);
+}
+
+static void
+account_alias_changed(GtkEditable *entry, AccountGeneralTab *view)
+{
+    g_return_if_fail(IS_ACCOUNT_GENERAL_TAB(view));
+    AccountGeneralTabPrivate *priv = ACCOUNT_GENERAL_TAB_GET_PRIVATE(view);
+    priv->account->setAlias(QString(gtk_editable_get_chars(entry, 0, -1)));
+}
+
+static void
+account_hostname_changed(GtkEditable *entry, AccountGeneralTab *view)
+{
+    g_return_if_fail(IS_ACCOUNT_GENERAL_TAB(view));
+    AccountGeneralTabPrivate *priv = ACCOUNT_GENERAL_TAB_GET_PRIVATE(view);
+    priv->account->setHostname(QString(gtk_editable_get_chars(entry, 0, -1)));
+}
+
+static void
+account_username_changed(GtkEditable *entry, AccountGeneralTab *view)
+{
+    g_return_if_fail(IS_ACCOUNT_GENERAL_TAB(view));
+    AccountGeneralTabPrivate *priv = ACCOUNT_GENERAL_TAB_GET_PRIVATE(view);
+    priv->account->setUsername(QString(gtk_editable_get_chars(entry, 0, -1)));
+}
+
+static void
+account_password_changed(GtkEditable *entry, AccountGeneralTab *view)
+{
+    g_return_if_fail(IS_ACCOUNT_GENERAL_TAB(view));
+    AccountGeneralTabPrivate *priv = ACCOUNT_GENERAL_TAB_GET_PRIVATE(view);
+    priv->account->setPassword(QString(gtk_editable_get_chars(entry, 0, -1)));
+}
+
+static void
+show_password(GtkToggleButton *checkbutton, GtkEntry *entry)
+{
+    gtk_entry_set_visibility(GTK_ENTRY(entry), gtk_toggle_button_get_active(checkbutton));
+}
+
+static void
+account_proxy_changed(GtkEditable *entry, AccountGeneralTab *view)
+{
+    g_return_if_fail(IS_ACCOUNT_GENERAL_TAB(view));
+    AccountGeneralTabPrivate *priv = ACCOUNT_GENERAL_TAB_GET_PRIVATE(view);
+    priv->account->setProxy(QString(gtk_editable_get_chars(entry, 0, -1)));
+}
+
+static void
+account_mailbox_changed(GtkEditable *entry, AccountGeneralTab *view)
+{
+    g_return_if_fail(IS_ACCOUNT_GENERAL_TAB(view));
+    AccountGeneralTabPrivate *priv = ACCOUNT_GENERAL_TAB_GET_PRIVATE(view);
+    priv->account->setMailbox(QString(gtk_editable_get_chars(entry, 0, -1)));
+}
+
+static void
+auto_answer(GtkToggleButton *checkbutton, AccountGeneralTab *view)
+{
+    g_return_if_fail(IS_ACCOUNT_GENERAL_TAB(view));
+    AccountGeneralTabPrivate *priv = ACCOUNT_GENERAL_TAB_GET_PRIVATE(view);
+    priv->account->setAutoAnswer(gtk_toggle_button_get_active(checkbutton));
+}
+
+static void
+upnp_enabled(GtkToggleButton *checkbutton, AccountGeneralTab *view)
+{
+    g_return_if_fail(IS_ACCOUNT_GENERAL_TAB(view));
+    AccountGeneralTabPrivate *priv = ACCOUNT_GENERAL_TAB_GET_PRIVATE(view);
+    priv->account->setUpnpEnabled(gtk_toggle_button_get_active(checkbutton));
+}
+
+
+static void
+build_tab_view(AccountGeneralTab *view)
+{
+    g_return_if_fail(IS_ACCOUNT_GENERAL_TAB(view));
+    AccountGeneralTabPrivate *priv = ACCOUNT_GENERAL_TAB_GET_PRIVATE(view);
+
+    int grid_row = 0;
+    GtkWidget *label = NULL;
+    GtkWidget *entry = NULL;
+    GtkWidget *checkbutton = NULL;
+
+    /* build account grid */
+
+    /* check if its ip2ip account */
+    const QByteArray& alias = priv->account->alias().toLocal8Bit();
+
+    if (strcmp(alias.constData(), "IP2IP") == 0) {
+        label = gtk_label_new("IP2IP");
+        gtk_widget_set_halign(label, GTK_ALIGN_START);
+        gtk_grid_attach(GTK_GRID(priv->grid_account), label, 0, grid_row, 1, 1);
+        ++grid_row;
+    } else {
+        /* account alias */
+        label = gtk_label_new("Alias");
+        gtk_widget_set_halign(label, GTK_ALIGN_START);
+        gtk_grid_attach(GTK_GRID(priv->grid_account), label, 0, grid_row, 1, 1);
+        entry = gtk_entry_new();
+        gtk_entry_set_text(GTK_ENTRY(entry), alias.constData());
+        gtk_widget_set_halign(entry, GTK_ALIGN_START);
+        g_signal_connect(entry, "changed", G_CALLBACK(account_alias_changed), view);
+        gtk_grid_attach(GTK_GRID(priv->grid_account), entry, 1, grid_row, 1, 1);
+        ++grid_row;
+
+        /* account type */
+        label = gtk_label_new("Type");
+        gtk_widget_set_halign(label, GTK_ALIGN_START);
+        gtk_grid_attach(GTK_GRID(priv->grid_account), label, 0, grid_row, 1, 1);
+
+        label = gtk_label_new("");
+        gtk_widget_set_halign(label, GTK_ALIGN_START);
+        switch (priv->account->protocol()) {
+            case Account::Protocol::SIP:
+                gtk_label_set_text(GTK_LABEL(label), "SIP");
+                break;
+            case Account::Protocol::IAX:
+                gtk_label_set_text(GTK_LABEL(label), "IAX");
+                break;
+            case Account::Protocol::RING:
+                gtk_label_set_text(GTK_LABEL(label), "RING");
+                break;
+            case Account::Protocol::COUNT__:
+                break;
+        }
+
+        gtk_grid_attach(GTK_GRID(priv->grid_account), label, 1, grid_row, 1, 1);
+        ++grid_row;
+    }
+
+    if (priv->account->protocol() == Account::Protocol::RING) {
+        label = gtk_label_new("Hash");
+        gtk_widget_set_halign(label, GTK_ALIGN_START);
+        gtk_grid_attach(GTK_GRID(priv->grid_account), label, 0, grid_row, 1, 1);
+        entry = gtk_entry_new();
+        gtk_entry_set_text(GTK_ENTRY(entry), priv->account->username().toLocal8Bit().constData());
+        g_object_set(G_OBJECT(entry), "editable", FALSE, NULL);
+        g_object_set(G_OBJECT(entry), "max-width-chars", 50, NULL);
+        gtk_widget_override_font(entry, pango_font_description_from_string("monospace"));
+        gtk_entry_set_alignment(GTK_ENTRY(entry), 0.5);
+        gtk_grid_attach(GTK_GRID(priv->grid_account), entry, 1, grid_row, 1, 1);
+        ++grid_row;
+    }
+
+    gtk_widget_show_all(priv->grid_account);
+
+    /* build parameters grid */
+    grid_row = 0;
+    if (strcmp(alias.constData(), "IP2IP") != 0) {
+        if (priv->account->protocol() != Account::Protocol::RING) {
+            /* SIP and IAX have the same params */
+
+            /* host name */
+            label = gtk_label_new("Host name");
+            gtk_widget_set_halign(label, GTK_ALIGN_START);
+            gtk_grid_attach(GTK_GRID(priv->grid_parameters), label, 0, grid_row, 1, 1);
+            entry = gtk_entry_new();
+            gtk_entry_set_text(GTK_ENTRY(entry), priv->account->hostname().toLocal8Bit().constData());
+            g_signal_connect(entry, "changed", G_CALLBACK(account_hostname_changed), view);
+            gtk_grid_attach(GTK_GRID(priv->grid_parameters), entry, 1, grid_row, 1, 1);
+            ++grid_row;
+
+            /* user name */
+            label = gtk_label_new("User name");
+            gtk_widget_set_halign(label, GTK_ALIGN_START);
+            gtk_grid_attach(GTK_GRID(priv->grid_parameters), label, 0, grid_row, 1, 1);
+            entry = gtk_entry_new();
+            gtk_entry_set_text(GTK_ENTRY(entry), priv->account->username().toLocal8Bit().constData());
+            g_signal_connect(entry, "changed", G_CALLBACK(account_username_changed), view);
+            gtk_grid_attach(GTK_GRID(priv->grid_parameters), entry, 1, grid_row, 1, 1);
+            ++grid_row;
+
+            /* password */
+            label = gtk_label_new("Password");
+            gtk_widget_set_halign(label, GTK_ALIGN_START);
+            gtk_grid_attach(GTK_GRID(priv->grid_parameters), label, 0, grid_row, 1, 1);
+            entry = gtk_entry_new();
+            gtk_entry_set_input_purpose(GTK_ENTRY(entry), GTK_INPUT_PURPOSE_PASSWORD);
+            gtk_entry_set_icon_from_icon_name(GTK_ENTRY(entry), GTK_ENTRY_ICON_PRIMARY, "dialog-password");
+            gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
+            gtk_entry_set_text(GTK_ENTRY(entry), priv->account->username().toLocal8Bit().constData());
+            g_signal_connect(entry, "changed", G_CALLBACK(account_password_changed), view);
+            gtk_grid_attach(GTK_GRID(priv->grid_parameters), entry, 1, grid_row, 1, 1);
+            ++grid_row;
+
+            /* show password */
+            checkbutton = gtk_check_button_new_with_label("Show password");
+            gtk_grid_attach(GTK_GRID(priv->grid_parameters), checkbutton, 1, grid_row, 1, 1);
+            g_signal_connect(checkbutton, "toggled", G_CALLBACK(show_password), entry);
+            ++grid_row;
+
+            /* proxy */
+            label = gtk_label_new("Proxy");
+            gtk_widget_set_halign(label, GTK_ALIGN_START);
+            gtk_grid_attach(GTK_GRID(priv->grid_parameters), label, 0, grid_row, 1, 1);
+            entry = gtk_entry_new();
+            gtk_entry_set_text(GTK_ENTRY(entry), priv->account->proxy().toLocal8Bit().constData());
+            g_signal_connect(entry, "changed", G_CALLBACK(account_proxy_changed), view);
+            gtk_grid_attach(GTK_GRID(priv->grid_parameters), entry, 1, grid_row, 1, 1);
+            ++grid_row;
+
+            /* voicemail number */
+            label = gtk_label_new("Voicemail number");
+            gtk_widget_set_halign(label, GTK_ALIGN_START);
+            gtk_grid_attach(GTK_GRID(priv->grid_parameters), label, 0, grid_row, 1, 1);
+            entry = gtk_entry_new();
+            gtk_entry_set_text(GTK_ENTRY(entry), priv->account->mailbox().toLocal8Bit().constData());
+            g_signal_connect(entry, "changed", G_CALLBACK(account_mailbox_changed), view);
+            gtk_grid_attach(GTK_GRID(priv->grid_parameters), entry, 1, grid_row, 1, 1);
+            ++grid_row;
+        } else {
+            /* RING accoutn */
+
+            /* bootstrap */
+            label = gtk_label_new("Bootstrap");
+            gtk_widget_set_halign(label, GTK_ALIGN_START);
+            gtk_grid_attach(GTK_GRID(priv->grid_parameters), label, 0, grid_row, 1, 1);
+            entry = gtk_entry_new();
+            gtk_entry_set_text(GTK_ENTRY(entry), priv->account->hostname().toLocal8Bit().constData());
+            g_signal_connect(entry, "changed", G_CALLBACK(account_hostname_changed), view);
+            gtk_grid_attach(GTK_GRID(priv->grid_parameters), entry, 1, grid_row, 1, 1);
+            ++grid_row;
+        }
+    }
+
+    /* auto answer */
+    checkbutton = gtk_check_button_new_with_label("Auto-answer calls");
+    gtk_widget_set_halign(checkbutton, GTK_ALIGN_START);
+    gtk_grid_attach(GTK_GRID(priv->grid_parameters), checkbutton, 0, grid_row, 1, 1);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton), priv->account->isAutoAnswer());
+    g_signal_connect(checkbutton, "toggled", G_CALLBACK(auto_answer), view);
+    ++grid_row;
+
+    /* upnp */
+    checkbutton = gtk_check_button_new_with_label("UPnP enabled");
+    gtk_widget_set_halign(checkbutton, GTK_ALIGN_START);
+    gtk_grid_attach(GTK_GRID(priv->grid_parameters), checkbutton, 0, grid_row, 1, 1);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbutton), priv->account->isUpnpEnabled());
+    g_signal_connect(checkbutton, "toggled", G_CALLBACK(upnp_enabled), view);
+    ++grid_row;
+
+    gtk_widget_show_all(priv->grid_parameters);
+
+}
+
+GtkWidget *
+account_general_tab_new(Account *account)
+{
+    g_return_val_if_fail(account != NULL, NULL);
+
+    gpointer view = g_object_new(ACCOUNT_GENERAL_TAB_TYPE, NULL);
+
+    AccountGeneralTabPrivate *priv = ACCOUNT_GENERAL_TAB_GET_PRIVATE(view);
+    priv->account = account;
+
+    build_tab_view(ACCOUNT_GENERAL_TAB(view));
+
+    return (GtkWidget *)view;
+}
diff --git a/src/accountgeneraltab.h b/src/accountgeneraltab.h
new file mode 100644
index 0000000..c411315
--- /dev/null
+++ b/src/accountgeneraltab.h
@@ -0,0 +1,53 @@
+/*
+ *  Copyright (C) 2015 Savoir-Faire Linux Inc.
+ *  Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
+ *
+ *  This program 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.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify this program, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ *  grants you additional permission to convey the resulting work.
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+
+#ifndef _ACCOUNTGENERALTAB_H
+#define _ACCOUNTGENERALTAB_H
+
+#include <gtk/gtk.h>
+#include <account.h>
+
+G_BEGIN_DECLS
+
+#define ACCOUNT_GENERAL_TAB_TYPE            (account_general_tab_get_type ())
+#define ACCOUNT_GENERAL_TAB(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), ACCOUNT_GENERAL_TAB_TYPE, AccountGeneralTab))
+#define ACCOUNT_GENERAL_TAB_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), ACCOUNT_GENERAL_TAB_TYPE, AccountGeneralTabClass))
+#define IS_ACCOUNT_GENERAL_TAB(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), ACCOUNT_GENERAL_TAB_TYPE))
+#define IS_ACCOUNT_GENERAL_TAB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), ACCOUNT_GENERAL_TAB_TYPE))
+
+typedef struct _AccountGeneralTab      AccountGeneralTab;
+typedef struct _AccountGeneralTabClass AccountGeneralTabClass;
+
+GType      account_general_tab_get_type      (void) G_GNUC_CONST;
+GtkWidget *account_general_tab_new           (Account *account);
+
+G_END_DECLS
+
+#endif /* _ACCOUNTGENERALTAB_H */
\ No newline at end of file
diff --git a/src/accountvideotab.cpp b/src/accountvideotab.cpp
new file mode 100644
index 0000000..57dfe4c
--- /dev/null
+++ b/src/accountvideotab.cpp
@@ -0,0 +1,243 @@
+/*
+ *  Copyright (C) 2015 Savoir-Faire Linux Inc.
+ *  Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
+ *
+ *  This program 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.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify this program, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ *  grants you additional permission to convey the resulting work.
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+
+#include "accountvideotab.h"
+
+#include <gtk/gtk.h>
+#include <account.h>
+#include <audio/codecmodel.h>
+#include "models/gtkqsortfiltertreemodel.h"
+
+struct _AccountVideoTab
+{
+    GtkBox parent;
+};
+
+struct _AccountVideoTabClass
+{
+    GtkBoxClass parent_class;
+};
+
+typedef struct _AccountVideoTabPrivate AccountVideoTabPrivate;
+
+struct _AccountVideoTabPrivate
+{
+    Account   *account;
+    GtkWidget *treeview_codecs;
+    GtkWidget *checkbutton_enable;
+    GtkWidget *button_moveup;
+    GtkWidget *button_movedown;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(AccountVideoTab, account_video_tab, GTK_TYPE_BOX);
+
+#define ACCOUNT_VIDEO_TAB_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ACCOUNT_VIDEO_TAB_TYPE, AccountVideoTabPrivate))
+
+static void
+account_video_tab_dispose(GObject *object)
+{
+    G_OBJECT_CLASS(account_video_tab_parent_class)->dispose(object);
+}
+
+static void
+account_video_tab_init(AccountVideoTab *view)
+{
+    gtk_widget_init_template(GTK_WIDGET(view));
+}
+
+static void
+account_video_tab_class_init(AccountVideoTabClass *klass)
+{
+    G_OBJECT_CLASS(klass)->dispose = account_video_tab_dispose;
+
+    gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
+                                                "/cx/ring/RingGnome/accountvideotab.ui");
+
+    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountVideoTab, treeview_codecs);
+    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountVideoTab, checkbutton_enable);
+    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountVideoTab, button_moveup);
+    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountVideoTab, button_movedown);
+}
+
+static void
+video_enable(GtkToggleButton *checkbutton, AccountVideoTab *view)
+{
+    g_return_if_fail(IS_ACCOUNT_VIDEO_TAB(view));
+   AccountVideoTabPrivate *priv = ACCOUNT_VIDEO_TAB_GET_PRIVATE(view);
+    priv->account->setVideoEnabled(gtk_toggle_button_get_active(checkbutton));
+}
+
+static void
+codec_active_toggled(GtkCellRendererToggle *renderer, gchar *path, AccountVideoTab *view)
+{
+    g_return_if_fail(IS_ACCOUNT_VIDEO_TAB(view));
+    AccountVideoTabPrivate *priv = ACCOUNT_VIDEO_TAB_GET_PRIVATE(view);
+
+    /* we want to set it to the opposite of the current value */
+    gboolean toggle = !gtk_cell_renderer_toggle_get_active(renderer);
+
+    /* get iter which was clicked */
+    GtkTreePath *tree_path = gtk_tree_path_new_from_string(path);
+    GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(priv->treeview_codecs));
+    GtkTreeIter iter;
+    gtk_tree_model_get_iter(model, &iter, tree_path);
+
+    /* get qmodelindex from iter and set the model data */
+    QModelIndex idx = gtk_q_sort_filter_tree_model_get_source_idx(GTK_Q_SORT_FILTER_TREE_MODEL(model), &iter);
+    if (idx.isValid()) {
+        priv->account->codecModel()->videoCodecs()->setData(idx, QVariant(toggle), Qt::CheckStateRole);
+        priv->account->codecModel()->save();
+    }
+}
+
+static QModelIndex
+get_index_from_selection(GtkTreeSelection *selection)
+{
+    GtkTreeIter iter;
+    GtkTreeModel *model = NULL;
+
+    if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
+        return gtk_q_sort_filter_tree_model_get_source_idx(GTK_Q_SORT_FILTER_TREE_MODEL(model), &iter);
+    } else {
+        return QModelIndex();
+    }
+}
+
+static void
+move_selected_codec(AccountVideoTab *view, int position_diff)
+{
+    g_return_if_fail(IS_ACCOUNT_VIDEO_TAB(view));
+    AccountVideoTabPrivate *priv = ACCOUNT_VIDEO_TAB_GET_PRIVATE(view);
+
+    GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_codecs));
+    QModelIndex idx = get_index_from_selection(selection);
+
+    if(!idx.isValid())
+        return;
+
+    QMimeData* mime = priv->account->codecModel()->videoCodecs()->mimeData(QModelIndexList() << idx);
+    priv->account->codecModel()->videoCodecs()->dropMimeData(
+                                                    mime,
+                                                    Qt::MoveAction,
+                                                    idx.row() + position_diff,
+                                                    0,
+                                                    QModelIndex());
+    priv->account->saveCodecs();
+
+    /* now make sure to select the same codec which was moved
+     * TODO: UGLY! this should be somehow done in the qt modle bindings,
+     *       or via a selection model, not here
+     */
+    int new_row = idx.row() + position_diff;
+    int row_count = priv->account->codecModel()->videoCodecs()->rowCount(idx.parent());
+    if (new_row < 0)
+        new_row = row_count - 1;
+    else if (new_row >= row_count)
+        new_row = 0;
+
+    idx = idx.sibling(new_row, idx.column());
+    GtkTreeIter iter;
+    if (gtk_q_sort_filter_tree_model_source_index_to_iter(
+            GTK_Q_SORT_FILTER_TREE_MODEL(gtk_tree_view_get_model(GTK_TREE_VIEW(priv->treeview_codecs))),
+            idx,
+            &iter)) {
+        gtk_tree_selection_select_iter(selection, &iter);
+    }
+}
+
+static void
+move_codec_up(G_GNUC_UNUSED GtkButton *button, AccountVideoTab *view)
+{
+    move_selected_codec(view, -1);
+}
+
+static void
+move_codec_down(G_GNUC_UNUSED GtkButton *button, AccountVideoTab *view)
+{
+    move_selected_codec(view, +1);
+}
+
+static void
+build_tab_view(AccountVideoTab *view)
+{
+    g_return_if_fail(IS_ACCOUNT_VIDEO_TAB(view));
+    AccountVideoTabPrivate *priv = ACCOUNT_VIDEO_TAB_GET_PRIVATE(view);
+
+    /* codec model */
+    GtkQSortFilterTreeModel *codec_model;
+    GtkCellRenderer *renderer;
+    GtkTreeViewColumn *column;
+
+    codec_model = gtk_q_sort_filter_tree_model_new(
+        priv->account->codecModel()->videoCodecs(),
+        3,
+        Qt::CheckStateRole, G_TYPE_BOOLEAN,
+        CodecModel::Role::NAME, G_TYPE_STRING,
+        CodecModel::Role::BITRATE, G_TYPE_STRING);
+    gtk_tree_view_set_model(GTK_TREE_VIEW(priv->treeview_codecs), GTK_TREE_MODEL(codec_model));
+
+    renderer = gtk_cell_renderer_toggle_new();
+    column = gtk_tree_view_column_new_with_attributes("Enabled", renderer, "active", 0, NULL);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(priv->treeview_codecs), column);
+
+    g_signal_connect(renderer, "toggled", G_CALLBACK(codec_active_toggled), view);
+
+    renderer = gtk_cell_renderer_text_new();
+    column = gtk_tree_view_column_new_with_attributes("Name", renderer, "text", 1, NULL);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(priv->treeview_codecs), column);
+
+    renderer = gtk_cell_renderer_text_new();
+    column = gtk_tree_view_column_new_with_attributes("Bitrate", renderer, "text", 2, NULL);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(priv->treeview_codecs), column);
+
+    /* enable video checkbutton */
+    gtk_toggle_button_set_active(
+        GTK_TOGGLE_BUTTON(priv->checkbutton_enable), priv->account->isVideoEnabled());
+    g_signal_connect(priv->checkbutton_enable, "toggled", G_CALLBACK(video_enable), view);
+
+    /* connect move codecs up/down signals */
+    g_signal_connect(priv->button_moveup, "clicked", G_CALLBACK(move_codec_up), view);
+    g_signal_connect(priv->button_movedown, "clicked", G_CALLBACK(move_codec_down), view);
+}
+
+GtkWidget *
+account_video_tab_new(Account *account)
+{
+    g_return_val_if_fail(account != NULL, NULL);
+
+    gpointer view = g_object_new(ACCOUNT_VIDEO_TAB_TYPE, NULL);
+
+    AccountVideoTabPrivate *priv = ACCOUNT_VIDEO_TAB_GET_PRIVATE(view);
+    priv->account = account;
+
+    build_tab_view(ACCOUNT_VIDEO_TAB(view));
+
+    return (GtkWidget *)view;
+}
diff --git a/src/accountvideotab.h b/src/accountvideotab.h
new file mode 100644
index 0000000..83116a9
--- /dev/null
+++ b/src/accountvideotab.h
@@ -0,0 +1,53 @@
+/*
+ *  Copyright (C) 2015 Savoir-Faire Linux Inc.
+ *  Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
+ *
+ *  This program 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.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify this program, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ *  grants you additional permission to convey the resulting work.
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+
+#ifndef _ACCOUNTVIDEOTAB_H
+#define _ACCOUNTVIDEOTAB_H
+
+#include <gtk/gtk.h>
+#include <account.h>
+
+G_BEGIN_DECLS
+
+#define ACCOUNT_VIDEO_TAB_TYPE            (account_video_tab_get_type ())
+#define ACCOUNT_VIDEO_TAB(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), ACCOUNT_VIDEO_TAB_TYPE, AccountVideoTab))
+#define ACCOUNT_VIDEO_TAB_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), ACCOUNT_VIDEO_TAB_TYPE, AccountVideoTabClass))
+#define IS_ACCOUNT_VIDEO_TAB(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), ACCOUNT_VIDEO_TAB_TYPE))
+#define IS_ACCOUNT_VIDEO_TAB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), ACCOUNT_VIDEO_TAB_TYPE))
+
+typedef struct _AccountVideoTab      AccountVideoTab;
+typedef struct _AccountVideoTabClass AccountVideoTabClass;
+
+GType      account_video_tab_get_type      (void) G_GNUC_CONST;
+GtkWidget *account_video_tab_new           (Account *account);
+
+G_END_DECLS
+
+#endif /* _ACCOUNTVIDEOTAB_H */
\ No newline at end of file
diff --git a/src/accountview.cpp b/src/accountview.cpp
new file mode 100644
index 0000000..5219261
--- /dev/null
+++ b/src/accountview.cpp
@@ -0,0 +1,335 @@
+/*
+ *  Copyright (C) 2015 Savoir-Faire Linux Inc.
+ *  Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
+ *
+ *  This program 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.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify this program, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ *  grants you additional permission to convey the resulting work.
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+
+#include "accountview.h"
+
+#include <gtk/gtk.h>
+#include <accountmodel.h>
+#include <audio/codecmodel.h>
+#include "models/gtkqtreemodel.h"
+#include "accountgeneraltab.h"
+#include "accountaudiotab.h"
+#include "accountvideotab.h"
+
+struct _AccountView
+{
+    GtkBox parent;
+};
+
+struct _AccountViewClass
+{
+    GtkBoxClass parent_class;
+};
+
+typedef struct _AccountViewPrivate AccountViewPrivate;
+
+struct _AccountViewPrivate
+{
+    GtkWidget *treeview_account_list;
+    GtkWidget *stack_account;
+    GtkWidget *current_account_notebook;
+
+    gint current_page; /* keeps track of current notebook page displayed */
+
+    QMetaObject::Connection account_changed;
+    QMetaObject::Connection codecs_changed;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE(AccountView, account_view, GTK_TYPE_BOX);
+
+#define ACCOUNT_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ACCOUNT_VIEW_TYPE, AccountViewPrivate))
+
+static void
+account_view_dispose(GObject *object)
+{
+    AccountView *view = ACCOUNT_VIEW(object);
+    AccountViewPrivate *priv = ACCOUNT_VIEW_GET_PRIVATE(view);
+
+    QObject::disconnect(priv->account_changed);
+    QObject::disconnect(priv->codecs_changed);
+
+    G_OBJECT_CLASS(account_view_parent_class)->dispose(object);
+}
+
+static QModelIndex
+get_index_from_selection(GtkTreeSelection *selection)
+{
+    GtkTreeIter iter;
+    GtkTreeModel *model = NULL;
+
+    if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
+        return gtk_q_tree_model_get_source_idx(GTK_Q_TREE_MODEL(model), &iter);
+    } else {
+        return QModelIndex();
+    }
+}
+
+static void
+cancel_account_changes(G_GNUC_UNUSED GtkButton *button, AccountView *view)
+{
+    g_debug("cancel changes");
+
+    g_return_if_fail(IS_ACCOUNT_VIEW(view));
+    AccountViewPrivate *priv = ACCOUNT_VIEW_GET_PRIVATE(view);
+
+    GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_account_list));
+    QModelIndex account_idx = get_index_from_selection(selection);
+    g_return_if_fail(account_idx.isValid());
+
+
+    /* reload the current account view unselectin and re-selecting it */
+    GtkTreeIter iter;
+    gtk_q_tree_model_source_index_to_iter(
+        GTK_Q_TREE_MODEL(gtk_tree_view_get_model(GTK_TREE_VIEW(priv->treeview_account_list))),
+        account_idx,
+        &iter);
+
+    QObject::disconnect(priv->account_changed);
+    QObject::disconnect(priv->codecs_changed);
+    gtk_tree_selection_unselect_all(selection);
+
+    /* reload account */
+    Account *account = AccountModel::instance()->getAccountByModelIndex(account_idx);
+    account->performAction(Account::EditAction::CANCEL);
+    /* TODO: clear the codecModel changes once this method is added */
+    // account->codecModel()->cancel();
+
+    /* re-select same item */
+    gtk_tree_selection_select_iter(selection, &iter);
+}
+
+static void
+apply_account_changes(G_GNUC_UNUSED GtkButton *button, Account *account)
+{
+    account->performAction(Account::EditAction::SAVE);
+    /* TODO: save the codecModel changes once the method to clear them is added */
+    // account->codecModel()->save();
+}
+
+static void
+account_selection_changed(GtkTreeSelection *selection, AccountView *view)
+{
+    g_return_if_fail(IS_ACCOUNT_VIEW(view));
+    AccountViewPrivate *priv = ACCOUNT_VIEW_GET_PRIVATE(view);
+
+    GtkWidget *old_account_view = gtk_stack_get_visible_child(GTK_STACK(priv->stack_account));
+
+    /* keep track of the last tab displayed */
+    if (priv->current_account_notebook)
+        priv->current_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(priv->current_account_notebook));
+
+    if (priv->current_page < 0)
+        priv->current_page = 0;
+
+    QModelIndex account_idx = get_index_from_selection(selection);
+    if (!account_idx.isValid()) {
+        /* it nothing is slected, simply display something empty */
+        GtkWidget *empty_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+        gtk_widget_show(empty_box);
+        gtk_stack_add_named(GTK_STACK(priv->stack_account), empty_box, "placeholder");
+        gtk_stack_set_visible_child(GTK_STACK(priv->stack_account), empty_box);
+        priv->current_account_notebook = NULL;
+    } else {
+        Account *account = AccountModel::instance()->getAccountByModelIndex(account_idx);
+
+        /* build new account view */
+        GtkWidget *hbox_account = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
+
+        /* create account notebook */
+        priv->current_account_notebook = gtk_notebook_new();
+        gtk_box_pack_start(GTK_BOX(hbox_account), priv->current_account_notebook, TRUE, TRUE, 0);
+
+        /* customize account view based on account */
+        GtkWidget *general_tab = account_general_tab_new(account);
+        gtk_notebook_append_page(GTK_NOTEBOOK(priv->current_account_notebook),
+                                 general_tab,
+                                 gtk_label_new("General"));
+        GtkWidget *audio_tab = account_audio_tab_new(account);
+        gtk_notebook_append_page(GTK_NOTEBOOK(priv->current_account_notebook),
+                                 audio_tab,
+                                 gtk_label_new("Audio"));
+        GtkWidget *video_tab = account_video_tab_new(account);
+        gtk_notebook_append_page(GTK_NOTEBOOK(priv->current_account_notebook),
+                                 video_tab,
+                                 gtk_label_new("Video"));
+
+        /* set the tab displayed to the same as the prev account selected */
+        gtk_notebook_set_current_page(GTK_NOTEBOOK(priv->current_account_notebook), priv->current_page);
+
+        /* button box with cancel and apply buttons */
+        GtkWidget *account_button_box = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
+        GtkWidget *account_change_cancel = gtk_button_new_with_label("Cancel");
+        GtkWidget *account_change_apply = gtk_button_new_with_label("Apply");
+
+        if (account->editState() != Account::EditState::MODIFIED) {
+            gtk_widget_set_sensitive(account_change_cancel, FALSE);
+            gtk_widget_set_sensitive(account_change_apply, FALSE);
+        }
+
+        gtk_box_pack_end(GTK_BOX(account_button_box), account_change_cancel, FALSE, FALSE, 0);
+        gtk_box_pack_end(GTK_BOX(account_button_box), account_change_apply, FALSE, FALSE, 0);
+        gtk_widget_set_halign(account_button_box, GTK_ALIGN_END);
+        gtk_box_set_spacing(GTK_BOX(account_button_box), 10);
+        gtk_box_pack_start(GTK_BOX(hbox_account), account_button_box, FALSE, FALSE, 0);
+
+        /* connect signals to buttons */
+        QObject::disconnect(priv->account_changed);
+        priv->account_changed = QObject::connect(
+            account,
+            &Account::changed,
+            [=](Account* a) {
+                if (a->editState() == Account::EditState::MODIFIED) {
+                    /* account has been modified, enable buttons */
+                    gtk_widget_set_sensitive(account_change_cancel, TRUE);
+                    gtk_widget_set_sensitive(account_change_apply, TRUE);
+                } else {
+                    gtk_widget_set_sensitive(account_change_cancel, FALSE);
+                    gtk_widget_set_sensitive(account_change_apply, FALSE);
+                }
+            }
+        );
+
+        /* add the following signal once the 'cancel' method is added to the contactModel */
+        // QObject::disconnect(priv->codecs_changed);
+        // priv->codecs_changed = QObject::connect(
+        //     account->codecModel(),
+        //     &CodecModel::dataChanged,
+        //     [=]() {
+        //         /* data changed in codec model, this probably happened because
+        //          * codecs were (de)selected */
+        //         gtk_widget_set_sensitive(account_change_cancel, TRUE);
+        //         gtk_widget_set_sensitive(account_change_apply, TRUE);
+        //     }
+        // );
+
+        g_signal_connect(account_change_cancel, "clicked", G_CALLBACK(cancel_account_changes), view);
+        g_signal_connect(account_change_apply, "clicked", G_CALLBACK(apply_account_changes), account);
+
+        gtk_widget_show_all(hbox_account);
+
+        /* set the new account view as visible */
+        char *account_view_name = g_strdup_printf("%p_account", account);
+        gtk_stack_add_named(GTK_STACK(priv->stack_account), hbox_account, account_view_name);
+        gtk_stack_set_visible_child(GTK_STACK(priv->stack_account), hbox_account);
+        g_free(account_view_name);
+    }
+
+    /* remove the old account view */
+    if (old_account_view)
+        gtk_container_remove(GTK_CONTAINER(priv->stack_account), old_account_view);
+}
+
+static void
+account_active_toggled(GtkCellRendererToggle *renderer, gchar *path, AccountView *view)
+{
+    g_return_if_fail(IS_ACCOUNT_VIEW(view));
+    AccountViewPrivate *priv = ACCOUNT_VIEW_GET_PRIVATE(view);
+
+    /* we want to set it to the opposite of the current value */
+    gboolean toggle = !gtk_cell_renderer_toggle_get_active(renderer);
+
+    /* get iter which was clicked */
+    GtkTreePath *tree_path = gtk_tree_path_new_from_string(path);
+    GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(priv->treeview_account_list));
+    GtkTreeIter iter;
+    gtk_tree_model_get_iter(model, &iter, tree_path);
+
+    /* get qmodelindex from iter and set the model data */
+    QModelIndex idx = gtk_q_tree_model_get_source_idx(GTK_Q_TREE_MODEL(model), &iter);
+    if (idx.isValid()) {
+        /* check if it is the IP2IP account, as we don't want to be able to disable it */
+        QVariant alias = idx.data(static_cast<int>(Account::Role::Alias));
+        if (strcmp(alias.value<QString>().toLocal8Bit().constData(), "IP2IP") != 0)
+            AccountModel::instance()->setData(idx, QVariant(toggle), Qt::CheckStateRole);
+    }
+}
+
+static void
+account_view_init(AccountView *view)
+{
+    gtk_widget_init_template(GTK_WIDGET(view));
+
+    AccountViewPrivate *priv = ACCOUNT_VIEW_GET_PRIVATE(view);
+
+    /* account model */
+    GtkQTreeModel *account_model;
+    GtkCellRenderer *renderer;
+    GtkTreeViewColumn *column;
+
+    account_model = gtk_q_tree_model_new(AccountModel::instance(), 4,
+        Account::Role::Enabled, G_TYPE_BOOLEAN,
+        Account::Role::Alias, G_TYPE_STRING,
+        Account::Role::Proto, G_TYPE_INT,
+        Account::Role::RegistrationState, G_TYPE_STRING);
+    gtk_tree_view_set_model(GTK_TREE_VIEW(priv->treeview_account_list), GTK_TREE_MODEL(account_model));
+
+    renderer = gtk_cell_renderer_toggle_new();
+    column = gtk_tree_view_column_new_with_attributes("Enabled", renderer, "active", 0, NULL);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(priv->treeview_account_list), column);
+
+    g_signal_connect(renderer, "toggled", G_CALLBACK(account_active_toggled), view);
+
+    renderer = gtk_cell_renderer_text_new();
+    column = gtk_tree_view_column_new_with_attributes("Alias", renderer, "text", 1, NULL);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(priv->treeview_account_list), column);
+
+    renderer = gtk_cell_renderer_text_new();
+    column = gtk_tree_view_column_new_with_attributes("Status", renderer, "text", 3, NULL);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(priv->treeview_account_list), column);
+
+    /* connect to selection signal */
+    GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_account_list));
+    g_signal_connect(selection, "changed", G_CALLBACK(account_selection_changed), view);
+
+    /* add an empty box to the account stack initially, otherwise there will
+     * be no cool animation when the first account is selected */
+    GtkWidget *empty_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+    gtk_widget_show(empty_box);
+    gtk_stack_add_named(GTK_STACK(priv->stack_account), empty_box, "placeholder");
+    gtk_stack_set_visible_child(GTK_STACK(priv->stack_account), empty_box);
+}
+
+static void
+account_view_class_init(AccountViewClass *klass)
+{
+    G_OBJECT_CLASS(klass)->dispose = account_view_dispose;
+
+    gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
+                                                "/cx/ring/RingGnome/accountview.ui");
+
+    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountView, treeview_account_list);
+    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountView, stack_account);
+}
+
+GtkWidget *
+account_view_new(void)
+{
+    return (GtkWidget *)g_object_new(ACCOUNT_VIEW_TYPE, NULL);
+}
diff --git a/src/accountview.h b/src/accountview.h
new file mode 100644
index 0000000..2931f50
--- /dev/null
+++ b/src/accountview.h
@@ -0,0 +1,52 @@
+/*
+ *  Copyright (C) 2015 Savoir-Faire Linux Inc.
+ *  Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
+ *
+ *  This program 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.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify this program, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ *  grants you additional permission to convey the resulting work.
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+
+#ifndef _ACCOUNTVIEW_H
+#define _ACCOUNTVIEW_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define ACCOUNT_VIEW_TYPE            (account_view_get_type ())
+#define ACCOUNT_VIEW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), ACCOUNT_VIEW_TYPE, AccountView))
+#define ACCOUNT_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), ACCOUNT_VIEW_TYPE, AccountViewClass))
+#define IS_ACCOUNT_VIEW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), ACCOUNT_VIEW_TYPE))
+#define IS_ACCOUNT_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), ACCOUNT_VIEW_TYPE))
+
+typedef struct _AccountView      AccountView;
+typedef struct _AccountViewClass AccountViewClass;
+
+GType      account_view_get_type      (void) G_GNUC_CONST;
+GtkWidget *account_view_new           (void);
+
+G_END_DECLS
+
+#endif /* _ACCOUNTVIEW_H */
\ No newline at end of file
diff --git a/src/ringmainwindow.cpp b/src/ringmainwindow.cpp
index 102e68d..0454119 100644
--- a/src/ringmainwindow.cpp
+++ b/src/ringmainwindow.cpp
@@ -42,8 +42,10 @@
 #include <contactmethod.h>
 #include <QtCore/QSortFilterProxyModel>
 #include "models/gtkqsortfiltertreemodel.h"
+#include "accountview.h"
 
 #define DEFAULT_VIEW_NAME "placeholder"
+#define ACCOUNT_VIEW_NAME "account"
 #define VIEW_CONTACTS "contacts"
 #define VIEW_HISTORY "history"
 #define VIEW_PRESENCE "presence"
@@ -72,6 +74,7 @@
     GtkWidget *search_entry;
     GtkWidget *stack_main_view;
     GtkWidget *button_placecall;
+    GtkWidget *account_view;
 };
 
 G_DEFINE_TYPE_WITH_PRIVATE(RingMainWindow, ring_main_window, GTK_TYPE_APPLICATION_WINDOW);
@@ -229,6 +232,18 @@
 }
 
 static void
+show_account_view(G_GNUC_UNUSED GSimpleAction *action, G_GNUC_UNUSED GVariant *param, gpointer win)
+{
+    g_debug("show account view");
+    RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(RING_MAIN_WINDOW(win));
+
+    /* clear call selection so we can re-select any ongoing calls */
+    CallModel::instance()->selectionModel()->clearCurrentIndex();
+
+    gtk_stack_set_visible_child_name(GTK_STACK(priv->stack_main_view), ACCOUNT_VIEW_NAME);
+}
+
+static void
 search_entry_placecall(G_GNUC_UNUSED GtkWidget *entry, gpointer win)
 {
     RingMainWindowPrivate *priv = RING_MAIN_WINDOW_GET_PRIVATE(RING_MAIN_WINDOW(win));
@@ -544,6 +559,10 @@
                 CallModel::instance()->getIndex(call), QItemSelectionModel::ClearAndSelect);
         }
     );
+
+    /* init the account view */
+    priv->account_view = account_view_new();
+    gtk_stack_add_named(GTK_STACK(priv->stack_main_view), priv->account_view, ACCOUNT_VIEW_NAME);
 }
 
 static void
@@ -572,8 +591,21 @@
     gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, button_placecall);
 }
 
+static const GActionEntry ring_actions[] =
+{
+    { "accountview", show_account_view, NULL, NULL, NULL, {0} },
+    /* TODO: add preferences view */
+    // { "accountview", show_preferences_view, NULL, NULL, NULL, {0} },
+};
+
 GtkWidget *
 ring_main_window_new (GtkApplication *app)
 {
-    return (GtkWidget *)g_object_new(RING_MAIN_WINDOW_TYPE, "application", app, NULL);
+    gpointer win = g_object_new(RING_MAIN_WINDOW_TYPE, "application", app, NULL);
+
+    /* map actions */
+    g_action_map_add_action_entries(
+        G_ACTION_MAP(app), ring_actions, G_N_ELEMENTS(ring_actions), win);
+
+    return (GtkWidget *)win;
 }
diff --git a/ui/accountaudiotab.ui b/ui/accountaudiotab.ui
new file mode 100644
index 0000000..df99a48
--- /dev/null
+++ b/ui/accountaudiotab.ui
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="3.10"/>
+  <template class="AccountAudioTab" parent="GtkBox">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="orientation">vertical</property>
+    <child>
+      <object class="GtkBox" id="vbox_main">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">10</property>
+        <property name="border_width">10</property>
+        <child>
+          <object class="GtkFrame" id="frame_codecs">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label_xalign">0</property>
+            <property name="shadow_type">none</property>
+            <child>
+              <object class="GtkBox" id="hbox_codecs">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="orientation">horizontal</property>
+                <property name="margin_left">10</property>
+                <property name="margin_start">10</property>
+                <property name="spacing">10</property>
+                <child>
+                  <object class="GtkScrolledWindow" id="scrolledwindow_codecs">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="shadow_type">in</property>
+                    <property name="min-content-height">225</property>
+                    <property name="hscrollbar_policy">never</property>
+                    <child>
+                      <object class="GtkTreeView" id="treeview_codecs">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButtonBox" id="vbox_codec_buttons">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="orientation">vertical</property>
+                    <property name="spacing">10</property>
+                    <property name="valign">GTK_ALIGN_START</property>
+                    <child>
+                      <object class="GtkButton" id="button_moveup">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">Up</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_movedown">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">Down</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child type="label">
+              <object class="GtkLabel" id="label_codecs">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">&lt;b&gt;Codecs&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+  </template>
+</interface>
diff --git a/ui/accountgeneraltab.ui b/ui/accountgeneraltab.ui
new file mode 100644
index 0000000..9466022
--- /dev/null
+++ b/ui/accountgeneraltab.ui
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="3.10"/>
+  <template class="AccountGeneralTab" parent="GtkBox">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="orientation">vertical</property>
+    <child>
+      <object class="GtkBox" id="vbox_main">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">10</property>
+        <property name="border_width">10</property>
+        <child>
+          <object class="GtkFrame" id="frame_account">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label_xalign">0</property>
+            <property name="shadow_type">none</property>
+            <child>
+              <object class="GtkAlignment" id="alignment_account">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="left_padding">10</property>
+                <property name="top_padding">10</property>
+                <child>
+                  <object class="GtkGrid" id="grid_account">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="row_spacing">10</property>
+                    <property name="column_spacing">10</property>
+                    <!-- code generated account properties go here, base on account type -->
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child type="label">
+              <object class="GtkLabel" id="label_account">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">&lt;b&gt;Account&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkFrame" id="frame_parameters">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label_xalign">0</property>
+            <property name="shadow_type">none</property>
+            <child>
+              <object class="GtkAlignment" id="alignment_parameters">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="left_padding">10</property>
+                <property name="top_padding">10</property>
+                <child>
+                  <object class="GtkGrid" id="grid_parameters">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="row_spacing">10</property>
+                    <property name="column_spacing">10</property>
+                    <!-- code generated account properties go here, base on account type -->
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child type="label">
+              <object class="GtkLabel" id="label_parameters">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">&lt;b&gt;Parameters&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+  </template>
+</interface>
diff --git a/ui/accountvideotab.ui b/ui/accountvideotab.ui
new file mode 100644
index 0000000..bb9759d
--- /dev/null
+++ b/ui/accountvideotab.ui
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="3.10"/>
+  <template class="AccountVideoTab" parent="GtkBox">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="orientation">vertical</property>
+    <child>
+      <object class="GtkBox" id="vbox_main">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">10</property>
+        <property name="border_width">10</property>
+        <child>
+          <object class="GtkFrame" id="frame_codecs">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label_xalign">0</property>
+            <property name="shadow_type">none</property>
+            <child>
+              <object class="GtkBox" id="hbox_codecs">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="orientation">horizontal</property>
+                <property name="margin_left">10</property>
+                <property name="margin_start">10</property>
+                <property name="spacing">10</property>
+                <child>
+                  <object class="GtkScrolledWindow" id="scrolledwindow_codecs">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="shadow_type">in</property>
+                    <property name="min-content-height">225</property>
+                    <property name="hscrollbar_policy">never</property>
+                    <child>
+                      <object class="GtkTreeView" id="treeview_codecs">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButtonBox" id="vbox_codec_buttons">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="orientation">vertical</property>
+                    <property name="spacing">10</property>
+                    <property name="valign">GTK_ALIGN_START</property>
+                    <child>
+                      <object class="GtkButton" id="button_moveup">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">Up</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="button_movedown">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">Down</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child type="label">
+              <object class="GtkLabel" id="label_codecs">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">&lt;b&gt;Codecs&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="checkbutton_enable">
+            <property name="label" translatable="yes">Enable Video</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="xalign">0</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+  </template>
+</interface>
diff --git a/ui/accountview.ui b/ui/accountview.ui
new file mode 100644
index 0000000..8969226
--- /dev/null
+++ b/ui/accountview.ui
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="3.10"/>
+  <template class="AccountView" parent="GtkBox">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="orientation">vertical</property>
+    <child>
+      <object class="GtkBox" id="hbox_main">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="spacing">5</property>
+        <!-- account list on left side of the box -->
+        <child>
+          <object class="GtkBox" id="vbox_account_list">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="orientation">vertical</property>
+            <child>
+              <object class="GtkScrolledWindow" id="scrolledwindow_account_list">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="shadow_type">in</property>
+                <property name="vscrollbar_policy">never</property>
+                <property name="hscrollbar_policy">never</property>
+                <child>
+                  <object class="GtkTreeView" id="treeview_account_list">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <!-- end of account list on left side of box -->
+        <!-- individual account view -->
+        <child>
+          <object class="GtkStack" id="stack_account">
+            <property name="visible">True</property>
+            <property name="transition-type">GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT</property>
+            <property name="transition-duration">300</property>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+          </packing>
+        </child>
+        <!-- end individual account view -->
+      </object>
+      <packing>
+        <property name="expand">True</property>
+        <property name="fill">True</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+  </template>
+</interface>
diff --git a/ui/ringgearsmenu.ui b/ui/ringgearsmenu.ui
index c6e3e88..2704e16 100644
--- a/ui/ringgearsmenu.ui
+++ b/ui/ringgearsmenu.ui
@@ -9,7 +9,7 @@
       </item>
       <item>
         <attribute name="label" translatable="yes">_Account Settings</attribute>
-        <attribute name="action">app.accountsettings</attribute>
+        <attribute name="action">app.accountview</attribute>
       </item>
     </section>
     <section>
diff --git a/ui/ui.gresource.xml b/ui/ui.gresource.xml
index 42328e0..74141c6 100644
--- a/ui/ui.gresource.xml
+++ b/ui/ui.gresource.xml
@@ -5,5 +5,9 @@
 	<file preprocess="xml-stripblanks">ringgearsmenu.ui</file>
 	<file preprocess="xml-stripblanks">incomingcallview.ui</file>
 	<file preprocess="xml-stripblanks">currentcallview.ui</file>
+	<file preprocess="xml-stripblanks">accountview.ui</file>
+	<file preprocess="xml-stripblanks">accountgeneraltab.ui</file>
+	<file preprocess="xml-stripblanks">accountaudiotab.ui</file>
+	<file preprocess="xml-stripblanks">accountvideotab.ui</file>
   </gresource>
 </gresources>
\ No newline at end of file