diff --git a/Ring/Ring.xcodeproj/project.pbxproj b/Ring/Ring.xcodeproj/project.pbxproj
index 2db63a59b1639d029f9a6ddcd24c8ba27accb106..a48b35acf1d49b0357c1c47c7dbef2567653a877 100644
--- a/Ring/Ring.xcodeproj/project.pbxproj
+++ b/Ring/Ring.xcodeproj/project.pbxproj
@@ -11,12 +11,16 @@
 		02419BD01DC3E75700DF0734 /* libboost_system.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 02419BCE1DC3E75700DF0734 /* libboost_system.a */; };
 		02419BD21DC3E76A00DF0734 /* libcryptopp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 02419BD11DC3E76A00DF0734 /* libcryptopp.a */; };
 		02AED8191DD4C4B100F740BA /* librestbed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 02AED8181DD4C4B100F740BA /* librestbed.a */; };
+		02B22DFC1DF755BB000358C9 /* AccountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02B22DFA1DF755BB000358C9 /* AccountModel.swift */; };
+		02B22DFD1DF755BB000358C9 /* AccountViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02B22DFB1DF755BB000358C9 /* AccountViewModel.swift */; };
+		02B22DFF1DF755DB000358C9 /* AccountsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02B22DFE1DF755DB000358C9 /* AccountsService.swift */; };
+		02B22E011DF755E5000358C9 /* MainTabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02B22E001DF755E5000358C9 /* MainTabBarViewController.swift */; };
+		02B22E031DF755F7000358C9 /* WalkthroughStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 02B22E021DF755F7000358C9 /* WalkthroughStoryboard.storyboard */; };
+		02B22E051DF75605000358C9 /* NotificationNames.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02B22E041DF75605000358C9 /* NotificationNames.swift */; };
+		02E1A0251DDE4ABA00D75B59 /* BoolStringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 043866371D2304A700E06CE2 /* BoolStringExtension.swift */; };
 		043866211D218B1100E06CE2 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 043866201D218B1100E06CE2 /* AudioToolbox.framework */; };
-		043866241D22C3BC00E06CE2 /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = 043866231D22C3BC00E06CE2 /* Account.swift */; };
-		043866261D22C42F00E06CE2 /* AccountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 043866251D22C42F00E06CE2 /* AccountModel.swift */; };
 		043866331D22CE8C00E06CE2 /* MeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 043866321D22CE8C00E06CE2 /* MeViewController.swift */; };
 		043866361D22D06500E06CE2 /* AccountTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 043866351D22D06500E06CE2 /* AccountTableViewCell.swift */; };
-		043866381D2304A700E06CE2 /* BoolStringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 043866371D2304A700E06CE2 /* BoolStringExtension.swift */; };
 		0438663B1D2313B700E06CE2 /* AccountDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0438663A1D2313B700E06CE2 /* AccountDetailsViewController.swift */; };
 		043999F71D1C2D9D00E99CD9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 043999F61D1C2D9D00E99CD9 /* AppDelegate.swift */; };
 		043999FA1D1C2D9D00E99CD9 /* Ring.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 043999F81D1C2D9D00E99CD9 /* Ring.xcdatamodeld */; };
@@ -104,12 +108,16 @@
 		02419BCE1DC3E75700DF0734 /* libboost_system.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libboost_system.a; path = ../fat/lib/libboost_system.a; sourceTree = "<group>"; };
 		02419BD11DC3E76A00DF0734 /* libcryptopp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcryptopp.a; path = ../fat/lib/libcryptopp.a; sourceTree = "<group>"; };
 		02AED8181DD4C4B100F740BA /* librestbed.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = librestbed.a; path = ../DEPS/x86_64/lib/librestbed.a; sourceTree = "<group>"; };
+		02B22DFA1DF755BB000358C9 /* AccountModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AccountModel.swift; path = Account/AccountModel.swift; sourceTree = "<group>"; };
+		02B22DFB1DF755BB000358C9 /* AccountViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AccountViewModel.swift; path = Account/AccountViewModel.swift; sourceTree = "<group>"; };
+		02B22DFE1DF755DB000358C9 /* AccountsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AccountsService.swift; path = Services/AccountsService.swift; sourceTree = "<group>"; };
+		02B22E001DF755E5000358C9 /* MainTabBarViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MainTabBarViewController.swift; path = MainTabBar/MainTabBarViewController.swift; sourceTree = "<group>"; };
+		02B22E021DF755F7000358C9 /* WalkthroughStoryboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = WalkthroughStoryboard.storyboard; path = Walkthrough/WalkthroughStoryboard.storyboard; sourceTree = "<group>"; };
+		02B22E041DF75605000358C9 /* NotificationNames.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NotificationNames.swift; path = Extensions/NotificationNames.swift; sourceTree = "<group>"; };
 		043866201D218B1100E06CE2 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
-		043866231D22C3BC00E06CE2 /* Account.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Account.swift; sourceTree = "<group>"; };
-		043866251D22C42F00E06CE2 /* AccountModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountModel.swift; sourceTree = "<group>"; };
 		043866321D22CE8C00E06CE2 /* MeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeViewController.swift; sourceTree = "<group>"; };
 		043866351D22D06500E06CE2 /* AccountTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountTableViewCell.swift; sourceTree = "<group>"; };
-		043866371D2304A700E06CE2 /* BoolStringExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoolStringExtension.swift; sourceTree = "<group>"; };
+		043866371D2304A700E06CE2 /* BoolStringExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BoolStringExtension.swift; path = Extensions/BoolStringExtension.swift; sourceTree = "<group>"; };
 		0438663A1D2313B700E06CE2 /* AccountDetailsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountDetailsViewController.swift; sourceTree = "<group>"; };
 		043999F31D1C2D9D00E99CD9 /* Ring.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Ring.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		043999F61D1C2D9D00E99CD9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@@ -277,19 +285,36 @@
 		02DE64671DDD15FC007D20EC /* Storyboards */ = {
 			isa = PBXGroup;
 			children = (
+				02B22E021DF755F7000358C9 /* WalkthroughStoryboard.storyboard */,
 				043999FF1D1C2D9D00E99CD9 /* Main.storyboard */,
 				04399A041D1C2D9D00E99CD9 /* LaunchScreen.storyboard */,
 			);
 			name = Storyboards;
 			sourceTree = "<group>";
 		};
-		043866221D22C38400E06CE2 /* Models */ = {
+		02E1A0261DDE4C2E00D75B59 /* Services */ = {
 			isa = PBXGroup;
 			children = (
-				043866231D22C3BC00E06CE2 /* Account.swift */,
-				043866251D22C42F00E06CE2 /* AccountModel.swift */,
+				02B22DFE1DF755DB000358C9 /* AccountsService.swift */,
 			);
-			name = Models;
+			name = Services;
+			sourceTree = "<group>";
+		};
+		02E1A0271DDE4C3900D75B59 /* Account */ = {
+			isa = PBXGroup;
+			children = (
+				02B22DFA1DF755BB000358C9 /* AccountModel.swift */,
+				02B22DFB1DF755BB000358C9 /* AccountViewModel.swift */,
+			);
+			name = Account;
+			sourceTree = "<group>";
+		};
+		02F9B1C21DDDFF0E00FE123D /* MainTabBar */ = {
+			isa = PBXGroup;
+			children = (
+				02B22E001DF755E5000358C9 /* MainTabBarViewController.swift */,
+			);
+			name = MainTabBar;
 			sourceTree = "<group>";
 		};
 		0438662D1D22C87500E06CE2 /* ViewController */ = {
@@ -312,6 +337,7 @@
 		043866391D2307C000E06CE2 /* Extensions */ = {
 			isa = PBXGroup;
 			children = (
+				02B22E041DF75605000358C9 /* NotificationNames.swift */,
 				043866371D2304A700E06CE2 /* BoolStringExtension.swift */,
 			);
 			name = Extensions;
@@ -343,16 +369,18 @@
 		043999F51D1C2D9D00E99CD9 /* Ring */ = {
 			isa = PBXGroup;
 			children = (
+				02E1A0271DDE4C3900D75B59 /* Account */,
+				02E1A0261DDE4C2E00D75B59 /* Services */,
+				02F9B1C21DDDFF0E00FE123D /* MainTabBar */,
 				02DE64671DDD15FC007D20EC /* Storyboards */,
 				043866341D22D04E00E06CE2 /* UI */,
 				0438662D1D22C87500E06CE2 /* ViewController */,
-				043866221D22C38400E06CE2 /* Models */,
+				043866391D2307C000E06CE2 /* Extensions */,
 				04399AAF1D1C305600E99CD9 /* DRingAdaptator */,
 				043999F61D1C2D9D00E99CD9 /* AppDelegate.swift */,
 				04399A021D1C2D9D00E99CD9 /* Assets.xcassets */,
 				04399A071D1C2D9D00E99CD9 /* Info.plist */,
 				043999F81D1C2D9D00E99CD9 /* Ring.xcdatamodeld */,
-				043866391D2307C000E06CE2 /* Extensions */,
 			);
 			path = Ring;
 			sourceTree = "<group>";
@@ -568,6 +596,7 @@
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				02B22E031DF755F7000358C9 /* WalkthroughStoryboard.storyboard in Resources */,
 				04399A061D1C2D9D00E99CD9 /* LaunchScreen.storyboard in Resources */,
 				04399A031D1C2D9D00E99CD9 /* Assets.xcassets in Resources */,
 				04399A011D1C2D9D00E99CD9 /* Main.storyboard in Resources */,
@@ -595,17 +624,20 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				02E1A0251DDE4ABA00D75B59 /* BoolStringExtension.swift in Sources */,
 				04399AAC1D1C304300E99CD9 /* ConfigurationManagerAdaptator.mm in Sources */,
+				02B22E011DF755E5000358C9 /* MainTabBarViewController.swift in Sources */,
 				043999F71D1C2D9D00E99CD9 /* AppDelegate.swift in Sources */,
-				043866381D2304A700E06CE2 /* BoolStringExtension.swift in Sources */,
+				02B22DFC1DF755BB000358C9 /* AccountModel.swift in Sources */,
 				043866331D22CE8C00E06CE2 /* MeViewController.swift in Sources */,
-				043866261D22C42F00E06CE2 /* AccountModel.swift in Sources */,
 				04399AAE1D1C304300E99CD9 /* Utils.mm in Sources */,
+				02B22DFD1DF755BB000358C9 /* AccountViewModel.swift in Sources */,
 				043999FA1D1C2D9D00E99CD9 /* Ring.xcdatamodeld in Sources */,
 				0438663B1D2313B700E06CE2 /* AccountDetailsViewController.swift in Sources */,
 				043866361D22D06500E06CE2 /* AccountTableViewCell.swift in Sources */,
+				02B22E051DF75605000358C9 /* NotificationNames.swift in Sources */,
 				04399AAD1D1C304300E99CD9 /* DRingAdaptator.mm in Sources */,
-				043866241D22C3BC00E06CE2 /* Account.swift in Sources */,
+				02B22DFF1DF755DB000358C9 /* AccountsService.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff --git a/Ring/Ring/Account.swift b/Ring/Ring/Account.swift
deleted file mode 100644
index 4922e4ff0452c01e382fde621becdc336a966e20..0000000000000000000000000000000000000000
--- a/Ring/Ring/Account.swift
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- *  Copyright (C) 2016 Savoir-faire Linux Inc.
- *
- *  Author: Edric Ladent-Milaret <edric.ladent-milaret@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.
- */
-
-import Foundation
-
-enum AccountType: String {
-    case SIP = "SIP"
-    case RING = "RING"
-}
-
-struct Account {
-
-    // MARK: - Properties
-    let id: String
-
-    // FIXME: This should be private
-    var details: Dictionary<String, String>
-
-    var alias: String? {
-        get {
-            return details["Account.alias"]
-        }
-        set {
-            details["Account.alias"] = newValue
-        }
-    }
-
-    var videoEnabled: Bool {
-        get {
-            return (details["Account.videoEnabled"]?.toBool())!
-        }
-        set {
-            details["Account.videoEnabled"] = newValue.toString()
-        }
-    }
-    var username: String? {
-        get {
-            return details["Account.username"]
-        }
-        set {
-            details["Account.username"] = newValue
-        }
-    }
-
-    var autoAnswer: Bool {
-        get {
-            return (details["Account.autoAnswer"]?.toBool())!
-        }
-        set {
-            details["Account.autoAnswer"] = newValue.toString()
-        }
-    }
-
-    var turnEnabled: Bool {
-        get {
-            return (details["TURN.enable"]?.toBool())!
-        }
-        set {
-            details["TURN.enable"] = newValue.toString()
-        }
-    }
-
-    var turnUsername: String? {
-        get {
-            return details["TURN.username"]
-        }
-        set {
-            details["TURN.username"] = newValue
-        }
-    }
-
-    var turnServer: String? {
-        get {
-            return details["TURN.server"]
-        }
-        set {
-            details["TURN.server"] = newValue
-        }
-    }
-
-    var turnPassword: String? {
-        get {
-            return details["TURN.password"]
-        }
-        set {
-            details["TURN.password"] = newValue
-        }
-    }
-
-    var isEnabled: Bool {
-        get {
-            return (details["Account.enable"]?.toBool())!
-        }
-        set {
-            details["Account.enable"] = newValue.toString()
-            (ConfigurationManagerAdaptator.sharedManager() as AnyObject).setAccountActive(self.id, active: newValue)
-        }
-    }
-
-    var upnpEnabled: Bool {
-        get {
-            return (details["Account.upnpEnabled"]?.toBool())!
-        }
-        set {
-            details["Account.upnpEnabled"] = newValue.toString()
-        }
-    }
-
-    var accountHostname: String? {
-        get {
-            return details["Account.hostname"]
-        }
-        set {
-            details["Account.hostname"] = newValue
-        }
-    }
-
-    var accountType: AccountType {
-        get {
-            return AccountType(rawValue: details["Account.type"]!)!
-        }
-        set {
-            details["Account.type"] = newValue.rawValue
-        }
-    }
-
-    var displayName: String? {
-        get {
-            return details["Account.displayName"]
-        }
-        set {
-            details["Account.displayName"] = newValue
-        }
-    }
-
-    // MARK: - Init
-    init(accID: String) {
-        id = accID
-        details = (ConfigurationManagerAdaptator.sharedManager() as AnyObject).getAccountDetails(id) as! Dictionary<String, String>
-    }
-
-    func save() {
-        (ConfigurationManagerAdaptator.sharedManager() as AnyObject).setAccountDetails(id, details: details)
-    }
-}
diff --git a/Ring/Ring/Account/AccountModel.swift b/Ring/Ring/Account/AccountModel.swift
new file mode 100644
index 0000000000000000000000000000000000000000..a4839e05222d6ebc8252cab3c58127d65656a6d6
--- /dev/null
+++ b/Ring/Ring/Account/AccountModel.swift
@@ -0,0 +1,127 @@
+/*
+ *  Copyright (C) 2016 Savoir-faire Linux Inc.
+ *
+ *  Author: Edric Ladent-Milaret <edric.ladent-milaret@savoirfairelinux.com>
+ *  Author: Romain Bertozzi <romain.bertozzi@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.
+ */
+
+import Foundation
+
+enum AccountType: String {
+    case SIP = "SIP"
+    case RING = "RING"
+}
+
+struct AccountModel {
+
+    // MARK: - Keys
+    fileprivate let accountAliasKey = "Account.alias"
+    fileprivate let accountVideoEnabledKey = "Account.videoEnabled"
+    fileprivate let accountUsernameKey = "Account.username"
+    fileprivate let accountAutoAnswerKey = "Account.autoAnswer"
+    fileprivate let accountTurnEnabledKey = "TURN.enable"
+    fileprivate let accountTurnUsernameKey = "TURN.username"
+    fileprivate let accountTurnServerKey = "TURN.server"
+    fileprivate let accountTurnPasswordKey = "TURN.password"
+    fileprivate let accountEnabledKey = "Account.enable"
+    fileprivate let accountUpnpEnabledKey = "Account.upnpEnabled"
+    fileprivate let accountHostnameKey = "Account.hostname"
+    fileprivate let accountTypeKey = "Account.type"
+    fileprivate let accountDisplayNameKey = "Account.displayName"
+
+    // MARK: - Properties
+    let id: String
+
+    fileprivate var details: Dictionary<String, String>
+
+    var alias: String? {
+        get {return details[accountAliasKey]}
+        set {details[accountAliasKey] = newValue}
+    }
+
+    var videoEnabled: Bool {
+        get {return (details[accountVideoEnabledKey]?.toBool())!}
+        set {details[accountVideoEnabledKey] = newValue.toString()}
+    }
+    var username: String? {
+        get {return details[accountUsernameKey]}
+        set {details[accountUsernameKey] = newValue}
+    }
+
+    var autoAnswer: Bool {
+        get {return (details[accountAutoAnswerKey]?.toBool())!}
+        set {details[accountAutoAnswerKey] = newValue.toString()}
+    }
+
+    var turnEnabled: Bool {
+        get {return (details[accountTurnEnabledKey]?.toBool())!}
+        set {details[accountTurnEnabledKey] = newValue.toString()}
+    }
+
+    var turnUsername: String? {
+        get {return details[accountTurnUsernameKey]}
+        set {details[accountTurnUsernameKey] = newValue}
+    }
+
+    var turnServer: String? {
+        get {return details[accountTurnServerKey]}
+        set {details[accountTurnServerKey] = newValue}
+    }
+
+    var turnPassword: String? {
+        get {return details[accountTurnPasswordKey]}
+        set {details[accountTurnPasswordKey] = newValue}
+    }
+
+    var isEnabled: Bool {
+        get {return (details[accountEnabledKey]?.toBool())!}
+        set {
+            details[accountEnabledKey] = newValue.toString()
+            (ConfigurationManagerAdaptator.sharedManager() as AnyObject).setAccountActive(self.id, active: newValue)
+        }
+    }
+
+    var upnpEnabled: Bool {
+        get {return (details[accountUpnpEnabledKey]?.toBool())!}
+        set {details[accountUpnpEnabledKey] = newValue.toString()}
+    }
+
+    var accountHostname: String? {
+        get {return details[accountHostnameKey]}
+        set {details[accountHostnameKey] = newValue}
+    }
+
+    var accountType: AccountType {
+        get {return AccountType(rawValue: details[accountTypeKey]!)!}
+        set {details[accountTypeKey] = newValue.rawValue}
+    }
+
+    var displayName: String? {
+        get {return details[accountDisplayNameKey]}
+        set {details[accountDisplayNameKey] = newValue}
+    }
+
+    // MARK: - Init
+    init(accountID: String) {
+        id = accountID
+        details = (ConfigurationManagerAdaptator.sharedManager() as AnyObject).getAccountDetails(id) as! Dictionary<String, String>
+    }
+
+    func save() {
+        (ConfigurationManagerAdaptator.sharedManager() as AnyObject).setAccountDetails(id, details: details)
+    }
+}
diff --git a/Ring/Ring/Account/AccountViewModel.swift b/Ring/Ring/Account/AccountViewModel.swift
new file mode 100644
index 0000000000000000000000000000000000000000..f3a8b6bb4fbd391aa25d78d0d1935ff8fc0486db
--- /dev/null
+++ b/Ring/Ring/Account/AccountViewModel.swift
@@ -0,0 +1,29 @@
+/*
+ *  Copyright (C) 2016 Savoir-faire Linux Inc.
+ *
+ *  Author: Romain Bertozzi <romain.bertozzi@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.
+ */
+
+import UIKit
+
+struct AccountViewModel {
+    fileprivate var account: AccountModel
+
+    init (withAccount account: AccountModel) {
+        self.account = account
+    }
+}
diff --git a/Ring/Ring/AccountDetailsViewController.swift b/Ring/Ring/AccountDetailsViewController.swift
index 59f8a03a3488ccada965e83a3724329aebfa624b..a5dbc4a223e4b49997f795a3d499884a719a9db6 100644
--- a/Ring/Ring/AccountDetailsViewController.swift
+++ b/Ring/Ring/AccountDetailsViewController.swift
@@ -23,16 +23,13 @@ import UIKit
 class AccountDetailsViewController: UIViewController {
 
     // MARK: - Properties
-    var account: Account!
+    var account: AccountModel!
 
     @IBOutlet weak var detailsLabel: UILabel!
 
     // MARK: - UIViewController
     override func viewDidLoad() {
         super.viewDidLoad()
-
-        // FIXME: This is just a placeholder
-        detailsLabel.text = account.details.description
     }
 
     override func didReceiveMemoryWarning() {
diff --git a/Ring/Ring/AccountModel.swift b/Ring/Ring/AccountModel.swift
deleted file mode 100644
index 535b8fcb59cdde3b70f5dfbc7438969b99a9414e..0000000000000000000000000000000000000000
--- a/Ring/Ring/AccountModel.swift
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- *  Copyright (C) 2016 Savoir-faire Linux Inc.
- *
- *  Author: Edric Ladent-Milaret <edric.ladent-milaret@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.
- */
-
-import Foundation
-
-class AccountModel {
-
-    // MARK: - Properties
-    let confAdapt = ConfigurationManagerAdaptator.sharedManager() as AnyObject
-    var accountList: Array<Account> = []
-
-    // MARK: - Singleton
-    static let sharedInstance = AccountModel()
-
-    fileprivate init() {
-        NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "AccountsChanged"), object: nil, queue: nil, using: { _ in
-            self.reload()
-        })
-    }
-
-    // MARK: - Methods
-    func reload() {
-        accountList.removeAll()
-        for acc in confAdapt.getAccountList() {
-            let accID = acc as! String
-            accountList.append(Account(accID: accID))
-        }
-    }
-
-    func addAccount() {
-        // TODO: This need work for all account type
-        let details:NSMutableDictionary? = confAdapt.getAccountTemplate("RING")
-        if details == nil {
-            print("Error retrieving Ring account template, can not continue");
-            return;
-        }
-        details!.setValue("iOS", forKey: "Account.alias")
-        details!.setValue("iOS", forKey: "Account.displayName")
-        let convertedDetails = details as NSDictionary? as? [AnyHashable: Any] ?? [:]
-        let addResult:String! = confAdapt.addAccount(convertedDetails)
-        print(addResult);
-    }
-
-    func removeAccount(_ row: Int) {
-        if row < accountList.count {
-            confAdapt.removeAccount(accountList[row].id)
-        }
-    }
-
-}
diff --git a/Ring/Ring/AccountTableViewCell.swift b/Ring/Ring/AccountTableViewCell.swift
index e56a930aed6fbd627ed772391de42404232c669e..c1f6c45e82a75bb2d061f05eb8d64ee8e242c1cc 100644
--- a/Ring/Ring/AccountTableViewCell.swift
+++ b/Ring/Ring/AccountTableViewCell.swift
@@ -27,7 +27,7 @@ class AccountTableViewCell: UITableViewCell {
     @IBOutlet weak var accountNameLabel: UILabel!
     @IBOutlet weak var accountTypeLabel: UILabel!
 
-    var account: Account!
+    var account: AccountModel!
 
     // MARK: - UITableViewCell
     override func awakeFromNib() {
diff --git a/Ring/Ring/AppDelegate.swift b/Ring/Ring/AppDelegate.swift
index fd15792655e5e28ae7cd9ddcd15d956b5110a8d1..bcd814576baac96285c36c7632d510d4ea2381dd 100644
--- a/Ring/Ring/AppDelegate.swift
+++ b/Ring/Ring/AppDelegate.swift
@@ -31,7 +31,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
         if (dRingAdapt.initDaemon() == true) {
             if (dRingAdapt.startDaemon() == true) {
                 Timer.scheduledTimer(timeInterval: 0.05, target: self, selector: #selector(AppDelegate.pollFunction), userInfo: nil, repeats: true)
-                AccountModel.sharedInstance.reload()
+                AccountsService.sharedInstance.reload()
             }
         }
         return true
diff --git a/Ring/Ring/Base.lproj/Main.storyboard b/Ring/Ring/Base.lproj/Main.storyboard
index b1befa3d2b5a931295dbe33762bec82b3be2b753..86038420c245d7e7b2f0e3e3057b2df0b5db1421 100644
--- a/Ring/Ring/Base.lproj/Main.storyboard
+++ b/Ring/Ring/Base.lproj/Main.storyboard
@@ -50,7 +50,7 @@
                                         <rect key="frame" x="0.0" y="28" width="320" height="44"/>
                                         <autoresizingMask key="autoresizingMask"/>
                                         <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="i1O-Yc-WGd" id="Bz1-A3-Z3f">
-                                            <rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
+                                            <rect key="frame" x="0.0" y="0.0" width="320" height="43.5"/>
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
                                                 <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="bm0-lC-K2F">
@@ -96,7 +96,7 @@
                                         <rect key="frame" x="0.0" y="72" width="320" height="44"/>
                                         <autoresizingMask key="autoresizingMask"/>
                                         <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Ok2-8L-eMm" id="m64-AI-t2h">
-                                            <rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
+                                            <rect key="frame" x="0.0" y="0.0" width="320" height="43.5"/>
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
                                                 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Add Account" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kZv-uf-BsD" userLabel="Account Name Label">
@@ -251,7 +251,7 @@
         <!--Ring-->
         <scene sceneID="oqo-zJ-m0o">
             <objects>
-                <tabBarController title="Ring" id="qdG-Sd-QaE" sceneMemberID="viewController">
+                <tabBarController title="Ring" id="qdG-Sd-QaE" customClass="MainTabBarViewController" sceneMemberID="viewController">
                     <tabBar key="tabBar" contentMode="scaleToFill" id="zN5-xb-CQh">
                         <rect key="frame" x="0.0" y="0.0" width="320" height="49"/>
                         <autoresizingMask key="autoresizingMask"/>
diff --git a/Ring/Ring/BoolStringExtension.swift b/Ring/Ring/Extensions/BoolStringExtension.swift
similarity index 99%
rename from Ring/Ring/BoolStringExtension.swift
rename to Ring/Ring/Extensions/BoolStringExtension.swift
index 90b3f4ed7544edf340919d1e0e9bf9ae48627637..ce59513bd96bad3b91a5a187b0ebd9ad15820cd1 100644
--- a/Ring/Ring/BoolStringExtension.swift
+++ b/Ring/Ring/Extensions/BoolStringExtension.swift
@@ -40,4 +40,4 @@ extension Bool {
         }
         return "false"
     }
-}
\ No newline at end of file
+}
diff --git a/Ring/Ring/Extensions/NotificationNames.swift b/Ring/Ring/Extensions/NotificationNames.swift
new file mode 100644
index 0000000000000000000000000000000000000000..85d545241d53b4ef663d290a497322d0116da459
--- /dev/null
+++ b/Ring/Ring/Extensions/NotificationNames.swift
@@ -0,0 +1,25 @@
+/*
+ *  Copyright (C) 2016 Savoir-faire Linux Inc.
+ *
+ *  Author: Romain Bertozzi <romain.bertozzi@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.
+ */
+
+import UIKit
+
+extension Notification.Name {
+    static let accountsChanged = Notification.Name("AccountsChanged")
+}
diff --git a/Ring/Ring/MainTabBar/MainTabBarViewController.swift b/Ring/Ring/MainTabBar/MainTabBarViewController.swift
new file mode 100644
index 0000000000000000000000000000000000000000..5e4fe14943b04cb053a1725008e4c1a9fd0fd6d1
--- /dev/null
+++ b/Ring/Ring/MainTabBar/MainTabBarViewController.swift
@@ -0,0 +1,36 @@
+/*
+ *  Copyright (C) 2016 Savoir-faire Linux Inc.
+ *
+ *  Author: Romain Bertozzi <romain.bertozzi@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.
+ */
+
+import UIKit
+
+class MainTabBarViewController: UITabBarController {
+    override func viewDidAppear(_ animated: Bool) {
+        super.viewDidAppear(animated)
+        if !AccountsService.sharedInstance.hasAccounts() {
+            self.presentWalkthrough()
+        }
+    }
+
+    fileprivate func presentWalkthrough() {
+        let storyboard = UIStoryboard(name: "WalkthroughStoryboard", bundle: nil)
+        let viewController = storyboard.instantiateInitialViewController()!
+        self.present(viewController, animated: false, completion: nil)
+    }
+}
diff --git a/Ring/Ring/MeViewController.swift b/Ring/Ring/MeViewController.swift
index 80a19bac06f3c16e16994a56fd7086f37d66e993..a47f82c5234a9179f1efe24b48443e9b1c28b68b 100644
--- a/Ring/Ring/MeViewController.swift
+++ b/Ring/Ring/MeViewController.swift
@@ -23,7 +23,7 @@ import UIKit
 class MeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
 
     // MARK: - Properties
-    let accountModel = AccountModel.sharedInstance
+    let accountService = AccountsService.sharedInstance
     @IBOutlet weak var accountTableView: UITableView!
     @IBOutlet weak var nameLabel: UILabel!
     @IBOutlet weak var qrImageView: UIImageView!
@@ -32,8 +32,8 @@ class MeViewController: UIViewController, UITableViewDelegate, UITableViewDataSo
     override func viewDidLoad() {
         super.viewDidLoad()
 
-        if accountModel.accountList.count > 0 {
-            let acc = accountModel.accountList[0]
+        if accountService.accounts.count > 0 {
+            let acc = accountService.accounts[0]
             nameLabel.text = acc.displayName
             if let username = acc.username {
                 createQRFromString(username);
@@ -68,14 +68,14 @@ class MeViewController: UIViewController, UITableViewDelegate, UITableViewDataSo
     }
 
     func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
-        return accountModel.accountList.count + 1
+        return accountService.accounts.count + 1
     }
 
     func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
 
-        if indexPath.row < accountModel.accountList.count {
+        if indexPath.row < accountService.accounts.count {
             let cell = tableView.dequeueReusableCell(withIdentifier: "accountTableCell", for: indexPath) as! AccountTableViewCell
-            let account = accountModel.accountList[indexPath.row]
+            let account = accountService.accounts[indexPath.row]
 
             cell.account = account
             cell.accountNameLabel.text = account.alias
@@ -91,14 +91,14 @@ class MeViewController: UIViewController, UITableViewDelegate, UITableViewDataSo
     }
 
     func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
-        if indexPath.row == accountModel.accountList.count {
-            accountModel.addAccount()
+        if indexPath.row == accountService.accounts.count {
+            accountService.addAccount()
             accountTableView.reloadData()
         }
     }
 
     func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
-        if indexPath.row == accountModel.accountList.count {
+        if indexPath.row == accountService.accounts.count {
             return false
         }
         return true
@@ -106,14 +106,14 @@ class MeViewController: UIViewController, UITableViewDelegate, UITableViewDataSo
 
     func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
         if (editingStyle == UITableViewCellEditingStyle.delete) {
-            accountModel.removeAccount(indexPath.row)
+            accountService.removeAccount(indexPath.row)
             accountTableView.reloadData()
         }
     }
 
     // MARK: - Actions
     @IBAction func addAccountClicked(_ sender: AnyObject) {
-        let index = IndexPath(row: accountModel.accountList.count, section: 0)
+        let index = IndexPath(row: accountService.accounts.count, section: 0)
         accountTableView.selectRow(at: index, animated: false, scrollPosition: UITableViewScrollPosition.none)
         tableView(accountTableView, didSelectRowAt: index)
     }
diff --git a/Ring/Ring/Services/AccountsService.swift b/Ring/Ring/Services/AccountsService.swift
new file mode 100644
index 0000000000000000000000000000000000000000..d149f3b03d49df692f9d83a603026fb8e146fa91
--- /dev/null
+++ b/Ring/Ring/Services/AccountsService.swift
@@ -0,0 +1,92 @@
+/*
+ *  Copyright (C) 2016 Savoir-faire Linux Inc.
+ *
+ *  Authors: Edric Ladent-Milaret <edric.ladent-milaret@savoirfairelinux.com>
+ *           Romain Bertozzi <romain.bertozzi@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.
+ */
+
+class AccountsService {
+    // MARK: - Properties
+    fileprivate let confAdapter = ConfigurationManagerAdaptator.sharedManager() as AnyObject
+
+    /// Fileprivate Accounts list.
+    ///
+    /// Can be used for all the operations, but won't be accessed from outside this file.
+    ///
+    /// - SeeAlso: `accounts`
+    fileprivate var accountList: Array<AccountModel>
+
+    /// Accounts list public interface
+    ///
+    /// Can be used to access by constant the list of accounts.
+    fileprivate(set) var accounts: Array<AccountModel> {
+        set {
+            accountList = newValue
+        }
+        get {
+            let lAccounts = accountList
+            return lAccounts
+        }
+    }
+
+    // MARK: - Singleton
+    static let sharedInstance = AccountsService()
+
+    fileprivate init() {
+        accountList = []
+
+        NotificationCenter.default.addObserver(forName: .accountsChanged,
+                                               object: nil,
+                                               queue: nil,
+                                               using: { _ in
+                                                self.reload()
+        })
+    }
+
+    // MARK: - Methods
+    func hasAccounts() -> Bool {
+        return accountList.count > 0
+    }
+
+    func reload() {
+        accountList.removeAll()
+        for account in confAdapter.getAccountList() {
+            let accountID = account as! String
+            accountList.append(AccountModel(accountID: accountID))
+        }
+    }
+
+    func addAccount() {
+        // TODO: This need work for all account type
+        let details:NSMutableDictionary? = confAdapter.getAccountTemplate("RING")
+        if details == nil {
+            print("Error retrieving Ring account template, can not continue");
+            return;
+        }
+        details!.setValue("iOS", forKey: "Account.alias")
+        details!.setValue("iOS", forKey: "Account.displayName")
+        let convertedDetails = details as NSDictionary? as? [AnyHashable: Any] ?? [:]
+        let addResult:String! = confAdapter.addAccount(convertedDetails)
+        print(addResult);
+    }
+
+    func removeAccount(_ row: Int) {
+        if row < accountList.count {
+            confAdapter.removeAccount(accountList[row].id)
+        }
+    }
+}
diff --git a/Ring/Ring/Walkthrough/WalkthroughStoryboard.storyboard b/Ring/Ring/Walkthrough/WalkthroughStoryboard.storyboard
new file mode 100644
index 0000000000000000000000000000000000000000..f2a4bd2dfb811d19080c21467257f204ad3f1e21
--- /dev/null
+++ b/Ring/Ring/Walkthrough/WalkthroughStoryboard.storyboard
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11542" systemVersion="15G1108" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="GnB-zf-djy">
+    <device id="retina4_7" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11524"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--Navigation Controller-->
+        <scene sceneID="azk-5X-z35">
+            <objects>
+                <navigationController storyboardIdentifier="WalkthroughStoryboard" navigationBarHidden="YES" id="GnB-zf-djy" sceneMemberID="viewController">
+                    <navigationBar key="navigationBar" contentMode="scaleToFill" id="Pgv-sV-7YL">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                    </navigationBar>
+                    <connections>
+                        <segue destination="zOM-us-BHp" kind="relationship" relationship="rootViewController" id="Cs0-7s-oVR"/>
+                    </connections>
+                </navigationController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="c5B-LX-9rY" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="-566" y="143"/>
+        </scene>
+        <!--View Controller-->
+        <scene sceneID="BPo-UM-NNL">
+            <objects>
+                <viewController id="zOM-us-BHp" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="Lps-eE-m7k"/>
+                        <viewControllerLayoutGuide type="bottom" id="OgW-31-HCB"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="GmX-eQ-kCs">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                    </view>
+                    <navigationItem key="navigationItem" id="LPh-IM-uvN"/>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="PWI-c5-979" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="249" y="143"/>
+        </scene>
+    </scenes>
+</document>