diff --git a/src/sakia/gui/certification.py b/src/sakia/gui/certification.py
deleted file mode 100644
index b50d9d5e110d141b6ca7eb2931f0e17d5a29cad4..0000000000000000000000000000000000000000
--- a/src/sakia/gui/certification.py
+++ /dev/null
@@ -1,264 +0,0 @@
-"""
-Created on 24 dec. 2014
-
-@author: inso
-"""
-import asyncio
-import logging
-from duniterpy.api import errors
-from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QApplication, QMessageBox
-from PyQt5.QtCore import Qt, QObject, QLocale, QDateTime
-
-from .widgets import toast
-from .widgets.dialogs import QAsyncMessageBox
-from .member import MemberDialog
-from ..tools.decorators import asyncify, once_at_a_time
-from ..tools.exceptions import NoPeerAvailable
-from ..presentation.certification_uic import Ui_CertificationDialog
-
-
-class CertificationDialog(QObject):
-    """
-    A dialog to certify individuals
-    """
-
-    def __init__(self, app, account, password_asker, widget, ui):
-        """
-        Constructor if a certification dialog
-
-        :param sakia.core.Application app:
-        :param sakia.core.Account account:
-        :param sakia.gui.password_asker.PasswordAsker password_asker:
-        :param PyQt5.QtWidgets widget: the widget of the dialog
-        :param sakia.gen_resources.certification_uic.Ui_CertificationDialog view: the view of the certification dialog
-        :return:
-        """
-        super().__init__()
-        self.widget = widget
-        self.ui = ui
-        self.ui.setupUi(self.widget)
-        self.app = app
-        self.account = account
-        self.password_asker = password_asker
-        self.community = self.account.communities[0]
-
-        self.ui.radio_contact.toggled.connect(lambda c, radio="contact": self.recipient_mode_changed(radio))
-        self.ui.radio_pubkey.toggled.connect(lambda c, radio="pubkey": self.recipient_mode_changed(radio))
-        self.ui.radio_search.toggled.connect(lambda c, radio="search": self.recipient_mode_changed(radio))
-        self.ui.button_box.accepted.connect(self.accept)
-        self.ui.button_box.rejected.connect(self.widget.reject)
-
-        for community in self.account.communities:
-            self.ui.combo_community.addItem(community.currency)
-
-        for contact_name in sorted([c['name'] for c in account.contacts], key=str.lower):
-            self.ui.combo_contact.addItem(contact_name)
-
-        if len(account.contacts) == 0:
-            self.ui.radio_pubkey.setChecked(True)
-            self.ui.radio_contact.setEnabled(False)
-
-        self.ui.member_widget = MemberDialog.as_widget(self.ui.groupBox, self.app, self.account, self.community, None)
-        self.ui.horizontalLayout_5.addWidget(self.ui.member_widget.widget)
-
-        self.ui.search_user.button_reset.hide()
-        self.ui.search_user.init(self.app)
-        self.ui.search_user.change_account(self.account)
-        self.ui.search_user.change_community(self.community)
-        self.ui.combo_contact.currentIndexChanged.connect(self.refresh_member)
-        self.ui.edit_pubkey.textChanged.connect(self.refresh_member)
-        self.ui.search_user.identity_selected.connect(self.refresh_member)
-        self.ui.radio_contact.toggled.connect(self.refresh_member)
-        self.ui.radio_search.toggled.connect(self.refresh_member)
-        self.ui.radio_pubkey.toggled.connect(self.refresh_member)
-        self.ui.combo_community.currentIndexChanged.connect(self.change_current_community)
-
-    @classmethod
-    def open_dialog(cls, app, account, community, password_asker):
-        """
-        Certify and identity
-        :param sakia.core.Application app: the application
-        :param sakia.core.Account account: the account certifying the identity
-        :param sakia.core.Community community: the community
-        :param sakia.gui.password_asker.PasswordAsker password_asker: the password asker
-        :return:
-        """
-        dialog = cls(app, account, password_asker, QDialog(), Ui_CertificationDialog())
-        if community:
-            dialog.ui.combo_community.setCurrentText(community.name)
-        dialog.refresh()
-        return dialog.exec()
-
-    @classmethod
-    async def certify_identity(cls, app, account, password_asker, community, identity):
-        """
-        Certify and identity
-        :param sakia.core.Application app: the application
-        :param sakia.core.Account account: the account certifying the identity
-        :param sakia.gui.password_asker.PasswordAsker password_asker: the password asker
-        :param sakia.core.Community community: the community
-        :param sakia.core.registry.Identity identity: the identity certified
-        :return:
-        """
-        dialog = cls(app, account, password_asker, QDialog(), Ui_CertificationDialog())
-        dialog.ui.combo_community.setCurrentText(community.name)
-        dialog.ui.edit_pubkey.setText(identity.pubkey)
-        dialog.ui.radio_pubkey.setChecked(True)
-        dialog.refresh()
-        return await dialog.async_exec()
-
-    @asyncify
-    async def accept(self):
-        """
-        Validate the dialog
-        """
-        pubkey = self.selected_pubkey()
-        if pubkey:
-            password = await self.password_asker.async_exec()
-            if password == "":
-                self.ui.button_box.setEnabled(True)
-                return
-            QApplication.setOverrideCursor(Qt.WaitCursor)
-            result = await self.account.certify(password, self.community, pubkey)
-            if result[0]:
-                if self.app.preferences['notifications']:
-                    toast.display(self.tr("Certification"),
-                                  self.tr("Success sending certification"))
-                else:
-                    await QAsyncMessageBox.information(self.widget, self.tr("Certification"),
-                                                 self.tr("Success sending certification"))
-                QApplication.restoreOverrideCursor()
-                self.widget.accept()
-            else:
-                if self.app.preferences['notifications']:
-                    toast.display(self.tr("Certification"), self.tr("Could not broadcast certification : {0}"
-                                                                    .format(result[1])))
-                else:
-                    await QAsyncMessageBox.critical(self.widget, self.tr("Certification"),
-                                              self.tr("Could not broadcast certification : {0}"
-                                                                    .format(result[1])))
-                QApplication.restoreOverrideCursor()
-                self.ui.button_box.setEnabled(True)
-
-    def change_current_community(self, index):
-        self.community = self.account.communities[index]
-        self.ui.search_user.change_community(self.community)
-        self.ui.member_widget.change_community(self.community)
-        if self.widget.isVisible():
-            self.refresh()
-
-    def selected_pubkey(self):
-        """
-        Get selected pubkey in the widgets of the window
-        :return: the current pubkey
-        :rtype: str
-        """
-        pubkey = None
-        if self.ui.radio_contact.isChecked():
-            for contact in self.account.contacts:
-                if contact['name'] == self.ui.combo_contact.currentText():
-                    pubkey = contact['pubkey']
-                    break
-        elif self.ui.radio_search.isChecked():
-            if self.ui.search_user.current_identity():
-                pubkey = self.ui.search_user.current_identity().pubkey
-        else:
-            pubkey = self.ui.edit_pubkey.text()
-        return pubkey
-
-    @asyncify
-    async def refresh_member(self, checked=False):
-        """
-        Refresh the member widget
-        """
-        current_pubkey = self.selected_pubkey()
-        if current_pubkey:
-            identity = await self.app.identities_registry.future_find(current_pubkey, self.community)
-        else:
-            identity = None
-        self.ui.member_widget.identity = identity
-        self.ui.member_widget.refresh()
-
-    @once_at_a_time
-    @asyncify
-    async def refresh(self):
-        account_identity = await self.account.identity(self.community)
-        is_member = await account_identity.is_member(self.community)
-        try:
-            block_0 = await self.community.get_block(0)
-        except errors.DuniterError as e:
-            if e.ucode == errors.BLOCK_NOT_FOUND:
-                block_0 = None
-        except NoPeerAvailable as e:
-            logging.debug(str(e))
-            block_0 = None
-
-        params = await self.community.parameters()
-        certifications = await account_identity.unique_valid_certified_by(self.app.identities_registry, self.community)
-        nb_certifications = len([c for c in certifications if c['block_number']])
-        nb_cert_pending = len([c for c in certifications if not c['block_number']])
-        remaining_time = await account_identity.cert_issuance_delay(self.app.identities_registry, self.community)
-        cert_text = self.tr("Certifications sent : {nb_certifications}/{stock}").format(
-            nb_certifications=nb_certifications,
-            stock=params['sigStock'])
-        if nb_cert_pending > 0:
-            cert_text += " (+{nb_cert_pending} certifications pending)".format(nb_cert_pending=nb_cert_pending)
-        if remaining_time > 0:
-            cert_text += "\n"
-            days, remainder = divmod(remaining_time, 3600*24)
-            hours, remainder = divmod(remainder, 3600)
-            minutes, seconds = divmod(remainder, 60)
-            if days > 0:
-                remaining_localized = self.tr("{days} days").format(days=days)
-            else:
-                remaining_localized = self.tr("{hours} hours and {min} min.").format(hours=hours,
-                                                                                min=minutes)
-            cert_text += self.tr("Remaining time before next certification validation : {0}".format(remaining_localized))
-        self.ui.label_cert_stock.setText(cert_text)
-
-        if is_member or not block_0:
-            if nb_certifications < params['sigStock'] or params['sigStock'] == 0:
-                self.ui.button_box.button(QDialogButtonBox.Ok).setEnabled(True)
-                if remaining_time > 0:
-                    self.ui.button_box.button(QDialogButtonBox.Ok).setText(self.tr("&Ok") +
-                                                                           self.tr(" (Not validated before ")
-                                                                            + remaining_localized + ")")
-                else:
-                    self.ui.button_box.button(QDialogButtonBox.Ok).setText(self.tr("&Ok"))
-            else:
-                self.ui.button_box.button(QDialogButtonBox.Ok).setEnabled(False)
-                self.ui.button_box.button(QDialogButtonBox.Ok).setText(self.tr("No more certifications"))
-        else:
-            self.ui.button_box.button(QDialogButtonBox.Ok).setEnabled(False)
-            self.ui.button_box.button(QDialogButtonBox.Ok).setText(self.tr("Not a member"))
-
-    def showEvent(self, event):
-        super().showEvent(event)
-        self.first_certification_check()
-
-    def first_certification_check(self):
-        if self.account.notifications['warning_certifying_first_time']:
-            self.account.notifications['warning_certifying_first_time'] = False
-            QMessageBox.warning(self, "Certifying individuals", """Please follow the following guidelines :
-1.) Don't certify an account if you believe the issuers identity might be faked.
-2.) Don't certify an account if you believe the issuer already has another certified account.
-3.) Don't certify an account if you believe the issuer purposely or carelessly violates rule 1 or 2 (the issuer certifies faked or double accounts
-""")
-
-    def recipient_mode_changed(self, radio):
-        """
-        :param str radio:
-        """
-        self.ui.edit_pubkey.setEnabled(radio == "pubkey")
-        self.ui.combo_contact.setEnabled(radio == "contact")
-        self.ui.search_user.setEnabled(radio == "search")
-
-    def async_exec(self):
-        future = asyncio.Future()
-        self.widget.finished.connect(lambda r: future.set_result(r))
-        self.widget.open()
-        self.refresh()
-        return future
-
-    def exec(self):
-        self.widget.exec()
diff --git a/src/sakia/gui/search_user/__init__.py b/src/sakia/gui/certification/__init__.py
similarity index 100%
rename from src/sakia/gui/search_user/__init__.py
rename to src/sakia/gui/certification/__init__.py
diff --git a/res/ui/certification.ui b/src/sakia/gui/certification/certification.ui
similarity index 94%
rename from res/ui/certification.ui
rename to src/sakia/gui/certification/certification.ui
index cd0c6b75abc4b98e6f27c6b98ac265d1f71e99fd..b45c093068b4febb01ff1c0c71c1793e26a3217e 100644
--- a/res/ui/certification.ui
+++ b/src/sakia/gui/certification/certification.ui
@@ -55,16 +55,16 @@
      </property>
      <layout class="QHBoxLayout" name="horizontalLayout_5">
       <item>
-       <layout class="QVBoxLayout" name="verticalLayout_3">
+       <layout class="QVBoxLayout" name="layout_target_choice">
         <property name="topMargin">
          <number>6</number>
         </property>
         <item>
-         <layout class="QHBoxLayout" name="horizontalLayout_2">
+         <layout class="QHBoxLayout" name="layout_mode_contact">
           <item>
            <widget class="QRadioButton" name="radio_contact">
             <property name="sizePolicy">
-             <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+             <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
               <horstretch>0</horstretch>
               <verstretch>0</verstretch>
              </sizepolicy>
@@ -109,7 +109,7 @@
          </layout>
         </item>
         <item>
-         <layout class="QHBoxLayout" name="horizontalLayout">
+         <layout class="QHBoxLayout" name="layout_mode_pubkey">
           <item>
            <widget class="QRadioButton" name="radio_pubkey">
             <property name="text">
@@ -161,14 +161,14 @@
          </layout>
         </item>
         <item>
-         <layout class="QHBoxLayout" name="horizontalLayout_3">
+         <layout class="QHBoxLayout" name="layout_mode_search">
           <property name="topMargin">
            <number>6</number>
           </property>
           <item>
            <widget class="QRadioButton" name="radio_search">
             <property name="sizePolicy">
-             <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+             <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
               <horstretch>0</horstretch>
               <verstretch>0</verstretch>
              </sizepolicy>
diff --git a/src/sakia/gui/certification/controller.py b/src/sakia/gui/certification/controller.py
new file mode 100644
index 0000000000000000000000000000000000000000..eee867cb04de40643dfdb064e3d2976a8903383f
--- /dev/null
+++ b/src/sakia/gui/certification/controller.py
@@ -0,0 +1,178 @@
+from ..component.controller import ComponentController
+from .view import CertificationView
+from .model import CertificationModel
+from ..search_user.controller import SearchUserController
+from PyQt5.QtWidgets import QApplication
+from PyQt5.QtCore import Qt
+from ...tools.decorators import asyncify, once_at_a_time
+import asyncio
+
+
+class CertificationController(ComponentController):
+    """
+    The Certification view
+    """
+
+    def __init__(self, parent, view, model, search_user):
+        """
+        Constructor of the Certification component
+
+        :param sakia.gui.Certification.view.CertificationView: the view
+        :param sakia.gui.Certification.model.CertificationModel model: the model
+        :param sakia.gui.SearchUser.controller.SearchUserController search_user: the search user component
+        """
+        super().__init__(parent, view, model)
+        self.view.button_box.accepted.connect(self.accept)
+        self.view.button_box.rejected.connect(self.reject)
+        self.view.combo_community.currentIndexChanged.connect(self.change_current_community)
+        self.search_user = search_user
+
+    @classmethod
+    def create(cls, parent, app, **kwargs):
+        """
+        Instanciate a Certification component
+        :param sakia.gui.component.controller.ComponentController parent:
+        :return: a new Certification controller
+        :rtype: CertificationController
+        """
+        account = kwargs['account']
+        community = kwargs['community']
+        communities_names = [c.name for c in account.communities]
+        contacts_names = [c['name'] for c in account.contacts]
+
+        view = CertificationView(parent.view, None, communities_names, contacts_names)
+        model = CertificationModel(None, app, account, community)
+        certification = cls(parent, view, model, None)
+
+        search_user = SearchUserController.create(certification, app, account=model.account, community=model.community)
+        view.set_search_user(search_user.view)
+        model.setParent(certification)
+        return certification
+
+    @classmethod
+    def open_dialog(cls, parent, app, account, community, password_asker):
+        """
+        Certify and identity
+        :param sakia.gui.component.controller.ComponentController parent: the parent
+        :param sakia.core.Application app: the application
+        :param sakia.core.Account account: the account certifying the identity
+        :param sakia.core.Community community: the community
+        :param sakia.gui.password_asker.PasswordAsker password_asker: the password asker
+        :return:
+        """
+        dialog = cls.create(parent, app, account=account, community=community, password_asker=password_asker)
+        if community:
+            dialog.ui.combo_community.setCurrentText(community.name)
+        dialog.refresh()
+        return dialog.exec()
+
+    @classmethod
+    async def certify_identity(cls, parent, app, account, password_asker, community, identity):
+        """
+        Certify and identity
+        :param sakia.gui.component.controller.ComponentController parent: the parent
+        :param sakia.core.Application app: the application
+        :param sakia.core.Account account: the account certifying the identity
+        :param sakia.gui.password_asker.PasswordAsker password_asker: the password asker
+        :param sakia.core.Community community: the community
+        :param sakia.core.registry.Identity identity: the identity certified
+        :return:
+        """
+        dialog = cls.create(parent, app, account=account, community=community, password_asker=password_asker)
+        dialog.view.combo_community.setCurrentText(community.name)
+        dialog.view.edit_pubkey.setText(identity.pubkey)
+        dialog.view.radio_pubkey.setChecked(True)
+        dialog.refresh()
+        return await dialog.async_exec()
+
+    @property
+    def view(self) -> CertificationView:
+        return self._view
+
+    @property
+    def model(self) -> CertificationModel:
+        return self._model
+
+    @asyncify
+    async def accept(self):
+        """
+        Validate the dialog
+        """
+        pubkey = self.selected_pubkey()
+        if pubkey:
+            password = await self.password_asker.async_exec()
+            if password == "":
+                self.view.enable_button_box()
+                return
+            QApplication.setOverrideCursor(Qt.WaitCursor)
+            result = await self.account.certify(password, self.community, pubkey)
+            if result[0]:
+                QApplication.restoreOverrideCursor()
+                await self.view.show_success()
+                self.view.accept()
+            else:
+                await self.view.show_error(result[1])
+                QApplication.restoreOverrideCursor()
+                self.view.enable_button_box()
+
+    def reject(self):
+        self.view.reject()
+
+    def selected_pubkey(self):
+        """
+        Get selected pubkey in the widgets of the window
+        :return: the current pubkey
+        :rtype: str
+        """
+        pubkey = None
+
+        if self.view.recipient_mode() == CertificationView.RecipientMode.CONTACT:
+            contact_name = self.view.selected_contact()
+            pubkey = self.model.contact_name_pubkey(contact_name)
+        elif self.view.recipient_mode() == CertificationView.RecipientMode.SEARCH:
+            if self.search_user.current_identity():
+                pubkey = self.search_user.current_identity().pubkey
+        else:
+            pubkey = self.view.pubkey_value()
+        return pubkey
+
+    @once_at_a_time
+    @asyncify
+    async def refresh(self):
+        stock = await self.model.get_cert_stock()
+        written, pending = await self.model.nb_certifications()
+        days, hours, minutes, seconds = await self.model.remaining_time()
+        self.view.display_cert_stock(written, pending, stock, days, hours, minutes)
+
+        if await self.model.could_certify():
+            if written < stock or stock == 0:
+                if days+hours+minutes > 0:
+                    if days > 0:
+                        remaining_localized = self.tr("{days} days").format(days=days)
+                    else:
+                        remaining_localized = self.tr("{hours}h {min}min").format(hours=hours, min=minutes)
+                    self.view.set_button_box(CertificationView.ButtonBoxState.REMAINING_TIME_BEFORE_VALIDATION,
+                                             remaining=remaining_localized)
+                else:
+                    self.view.set_button_box(CertificationView.ButtonBoxState.OK)
+            else:
+                    self.view.set_button_box(CertificationView.ButtonBoxState.NO_MORE_CERTIFICATION)
+        else:
+            self.view.set_button_box(CertificationView.ButtonBoxState.NOT_A_MEMBER)
+
+    def change_current_community(self, index):
+        self.model.change_community(index)
+        self.search_user.set_community(self.community)
+        #self.member_widget.change_community(self.community)
+        self.refresh()
+
+    def async_exec(self):
+        future = asyncio.Future()
+        self.view.finished.connect(lambda r: future.set_result(r))
+        self.view.open()
+        self.refresh()
+        return future
+
+    def exec(self):
+        self.refresh()
+        self.view.exec()
diff --git a/src/sakia/gui/certification/model.py b/src/sakia/gui/certification/model.py
new file mode 100644
index 0000000000000000000000000000000000000000..94ac1aba768990d147f42273dc004a19da2dba23
--- /dev/null
+++ b/src/sakia/gui/certification/model.py
@@ -0,0 +1,90 @@
+from ..component.model import ComponentModel
+from duniterpy.api import errors
+from sakia.tools.exceptions import NoPeerAvailable
+
+import logging
+
+
+class CertificationModel(ComponentModel):
+    """
+    The model of Certification component
+    """
+
+    def __init__(self, parent, app, account, community):
+        super().__init__(parent)
+        self.app = app
+        self.account = account
+        self.community = community
+        if self.community is None:
+            self.community = self.account.communities[0]
+
+    def contact_name_pubkey(self, name):
+        """
+        Get the pubkey of a contact from its name
+        :param str name:
+        :return:
+        :rtype: str
+        """
+        for contact in self.account.contacts:
+            if contact['name'] == name:
+                return contact['pubkey']
+
+    def change_community(self, index):
+        """
+        Change current community
+        :param int index: index of the community in the account list
+        """
+        self.community = self.account.communities[index]
+
+    async def get_cert_stock(self):
+        """
+
+        :return: the certifications stock
+        :rtype: int
+        """
+        params = await self.community.parameters()
+        return params['sigStock']
+
+    async def remaining_time(self):
+        """
+        Get remaining time as a tuple to display
+        :return: a tuple containing (days, hours, minutes, seconds)
+        :rtype: tuple[int]
+        """
+        account_identity = await self.account.identity(self.community)
+        remaining_time = await account_identity.cert_issuance_delay(self.app.identities_registry, self.community)
+
+        days, remainder = divmod(remaining_time, 3600 * 24)
+        hours, remainder = divmod(remainder, 3600)
+        minutes, seconds = divmod(remainder, 60)
+        return days, hours, minutes, seconds
+
+    async def nb_certifications(self):
+        """
+        Get
+        :return: a tuple containing (written valid certifications, pending certifications)
+        :rtype: tuple[int]
+        """
+        account_identity = await self.account.identity(self.community)
+        certifications = await account_identity.unique_valid_certified_by(self.app.identities_registry, self.community)
+        nb_certifications = len([c for c in certifications if c['block_number']])
+        nb_cert_pending = len([c for c in certifications if not c['block_number']])
+        return nb_certifications, nb_cert_pending
+
+    async def could_certify(self):
+        """
+        Check if the user could theorically certify
+        :return: true if the user can certifiy
+        :rtype: bool
+        """
+        account_identity = await self.account.identity(self.community)
+        is_member = await account_identity.is_member(self.community)
+        try:
+            block_0 = await self.community.get_block(0)
+        except errors.DuniterError as e:
+            if e.ucode == errors.BLOCK_NOT_FOUND:
+                block_0 = None
+        except NoPeerAvailable as e:
+            logging.debug(str(e))
+            block_0 = None
+        return is_member or not block_0
\ No newline at end of file
diff --git a/src/sakia/gui/certification/view.py b/src/sakia/gui/certification/view.py
new file mode 100644
index 0000000000000000000000000000000000000000..3afba6ff21a7368ba48151ff8e0c5a284034ca33
--- /dev/null
+++ b/src/sakia/gui/certification/view.py
@@ -0,0 +1,153 @@
+from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QMessageBox
+from PyQt5.QtCore import QT_TRANSLATE_NOOP
+from .certification_uic import Ui_CertificationDialog
+from ..widgets import toast
+from ..widgets.dialogs import QAsyncMessageBox
+from enum import Enum
+
+
+class CertificationView(QDialog, Ui_CertificationDialog):
+    """
+    The view of the certification component
+    """
+
+    class ButtonBoxState(Enum):
+        NO_MORE_CERTIFICATION = 0
+        NOT_A_MEMBER = 1
+        REMAINING_TIME_BEFORE_VALIDATION = 2
+        OK = 3
+
+    class RecipientMode(Enum):
+        CONTACT = 0
+        PUBKEY = 1
+        SEARCH = 2
+
+    _button_box_values = {
+        ButtonBoxState.NO_MORE_CERTIFICATION: (False,
+                                               QT_TRANSLATE_NOOP("CertificationView", "No more certifications")),
+        ButtonBoxState.NOT_A_MEMBER: (False, QT_TRANSLATE_NOOP("CertificationView", "Not a member")),
+        ButtonBoxState.REMAINING_TIME_BEFORE_VALIDATION: (True,
+                                                          QT_TRANSLATE_NOOP("CertificationView",
+                                                                            "&Ok (Not validated before {remaining})")),
+        ButtonBoxState.OK: (True, QT_TRANSLATE_NOOP("CertificationView", "&Ok"))
+    }
+
+    def __init__(self, parent, search_user_view, communities_names, contacts_names):
+        """
+        Constructor
+        """
+        super().__init__(parent)
+        self.setupUi(self)
+
+        self.radio_contact.toggled.connect(lambda c, radio=CertificationView.RecipientMode.CONTACT: self.recipient_mode_changed(radio))
+        self.radio_pubkey.toggled.connect(lambda c, radio=CertificationView.RecipientMode.PUBKEY: self.recipient_mode_changed(radio))
+        self.radio_search.toggled.connect(lambda c, radio=CertificationView.RecipientMode.SEARCH: self.recipient_mode_changed(radio))
+
+        for name in communities_names:
+            self.combo_community.addItem(name)
+
+        for name in sorted(contacts_names):
+            self.combo_contact.addItem(name)
+
+        if len(contacts_names) == 0:
+            self.radio_pubkey.setChecked(True)
+            self.radio_contact.setEnabled(False)
+
+        self.search_user = search_user_view
+
+        #self.combo_contact.currentIndexChanged.connect(self.refresh_member)
+        #self.edit_pubkey.textChanged.connect(self.refresh_member)
+        #self.search_user.identity_selected.connect(self.refresh_member)
+        #self.radio_contact.toggled.connect(self.refresh_member)
+        #self.radio_search.toggled.connect(self.refresh_member)
+        #self.radio_pubkey.toggled.connect(self.refresh_member)
+
+    def set_search_user(self, search_user_view):
+        """
+
+        :param sakia.gui.search_user.view.SearchUserView search_user_view:
+        :return:
+        """
+        self.search_user = search_user_view
+        self.layout_mode_search.addWidget(search_user_view)
+        self.search_user.button_reset.hide()
+
+    def set_member_widget(self, member_widget):
+        self.horizontalLayout_5.addWidget(member_widget)
+
+    def recipient_mode(self):
+        if self.radio_contact.isChecked():
+            return CertificationView.RecipientMode.CONTACT
+        elif self.radio_search.isChecked():
+            return CertificationView.RecipientMode.SEARCH
+        else:
+            return CertificationView.RecipientMode.PUBKEY
+
+    def selected_contact(self):
+        return self.combo_contact.currentText()
+
+    def pubkey_value(self):
+        return self.edit_pubkey.text()
+
+    async def show_success(self):
+        if self.app.preferences['notifications']:
+            toast.display(self.tr("Certification"),
+                          self.tr("Success sending certification"))
+        else:
+            await QAsyncMessageBox.information(self.widget, self.tr("Certification"),
+                                         self.tr("Success sending certification"))
+
+    async def show_error(self, error_txt):
+
+        if self.app.preferences['notifications']:
+            toast.display(self.tr("Certification"), self.tr("Could not broadcast certification : {0}"
+                                                            .format(error_txt)))
+        else:
+            await QAsyncMessageBox.critical(self.widget, self.tr("Certification"),
+                                            self.tr("Could not broadcast certification : {0}"
+                                                    .format(error_txt)))
+
+    def display_cert_stock(self, written, pending, stock,
+                           remaining_days, remaining_hours, remaining_minutes):
+        """
+        Display values in informations label
+        :param int written: number of written certifications
+        :param int pending: number of pending certifications
+        :param int stock: maximum certifications
+        :param int remaining_days:
+        :param int remaining_hours:
+        :param int remaining_minutes:
+        """
+        cert_text = self.tr("Certifications sent : {nb_certifications}/{stock}").format(
+            nb_certifications=written,
+            stock=stock)
+        if pending > 0:
+            cert_text += " (+{nb_cert_pending} certifications pending)".format(nb_cert_pending=pending)
+
+        if remaining_days > 0:
+            remaining_localized = self.tr("{days} days").format(days=remaining_days)
+        else:
+            remaining_localized = self.tr("{hours} hours and {min} min.").format(hours=remaining_hours,
+                                                                            min=remaining_minutes)
+        cert_text += self.tr("Remaining time before next certification validation : {0}".format(remaining_localized))
+        self.label_cert_stock.setText(cert_text)
+
+    def set_button_box(self, state, **kwargs):
+        """
+        Set button box state
+        :param sakia.gui.certification.view.CertificationView.ButtonBoxState state: the state of te button box
+        :param dict kwargs: the values to replace from the text in the state
+        :return:
+        """
+        button_box_state = CertificationView._button_box_values[state]
+        self.button_box.button(QDialogButtonBox.Ok).setEnabled(button_box_state[0])
+        self.button_box.button(QDialogButtonBox.Ok).setText(button_box_state[1].format(**kwargs))
+
+    def recipient_mode_changed(self, radio):
+        """
+        :param str radio:
+        """
+        self.edit_pubkey.setEnabled(radio == CertificationView.RecipientMode.PUBKEY)
+        self.combo_contact.setEnabled(radio == CertificationView.RecipientMode.CONTACT)
+        self.search_user.setEnabled(radio == CertificationView.RecipientMode.SEARCH)
+
diff --git a/src/sakia/gui/homescreen/controller.py b/src/sakia/gui/homescreen/controller.py
index 7f1dfdd9b2d25ed03de0cb4ec66b3ad6acc488ce..3a63a3a989f40ab65a51a310f051dc448536b8c0 100644
--- a/src/sakia/gui/homescreen/controller.py
+++ b/src/sakia/gui/homescreen/controller.py
@@ -21,9 +21,10 @@ class HomeScreenController(ComponentController):
     def create(cls, parent, app, **kwargs):
         """
         Instanciate a homescreen component
-        :param sakia.gui.agent.controller.AgentController parent:
+        :param sakia.gui.component.controller.ComponentController parent:
+        :param sakia.core.Application app:
         :return: a new Homescreen controller
-        :rtype: NavigationController
+        :rtype: HomeScreenController
         """
         view = HomeScreenView(parent.view)
         model = HomeScreenModel(None, app)
diff --git a/src/sakia/gui/homescreen/model.py b/src/sakia/gui/homescreen/model.py
index c306fb2b2a860edb18d955c2f017f2212a32bc68..66db3c5cf7d1a234625d5a942824c9aa54fb5b30 100644
--- a/src/sakia/gui/homescreen/model.py
+++ b/src/sakia/gui/homescreen/model.py
@@ -3,7 +3,7 @@ from sakia.gui.component.model import ComponentModel
 
 class HomeScreenModel(ComponentModel):
     """
-    The model of Navigation component
+    The model of HomeScreen component
     """
 
     def __init__(self, parent, app):
diff --git a/src/sakia/gui/homescreen/view.py b/src/sakia/gui/homescreen/view.py
index dd4e7040a527151254a7dae2f1bc6ad583425967..5f8f92acc6c2f6d4b42f14382356b5ce090a2241 100644
--- a/src/sakia/gui/homescreen/view.py
+++ b/src/sakia/gui/homescreen/view.py
@@ -7,10 +7,9 @@ class HomeScreenView(QWidget, Ui_HomescreenWidget):
     classdocs
     """
 
-    def __init__(self, app):
+    def __init__(self, parent):
         """
         Constructor
         """
-        super().__init__()
+        super().__init__(parent)
         self.setupUi(self)
-        self.app = app
diff --git a/src/sakia/gui/identities/view.py b/src/sakia/gui/identities/view.py
index cbb4ce5b425bb4297a815115191b348788c56e71..24e6bb955d2f0a5a01838d65a5ae8f7328f74163 100644
--- a/src/sakia/gui/identities/view.py
+++ b/src/sakia/gui/identities/view.py
@@ -12,8 +12,8 @@ class IdentitiesView(QWidget, Ui_IdentitiesWidget):
     search_by_text_requested = pyqtSignal(str)
     search_directly_connected_requested = pyqtSignal()
 
-    _direct_connections_text = QT_TRANSLATE_NOOP("IdentitiesTabWidget", "Search direct certifications")
-    _search_placeholder = QT_TRANSLATE_NOOP("IdentitiesTabWidget", "Research a pubkey, an uid...")
+    _direct_connections_text = QT_TRANSLATE_NOOP("IdentitiesView", "Search direct certifications")
+    _search_placeholder = QT_TRANSLATE_NOOP("IdentitiesView", "Research a pubkey, an uid...")
 
     def __init__(self, parent):
         super().__init__(parent)
diff --git a/src/sakia/gui/main_window/controller.py b/src/sakia/gui/main_window/controller.py
index b4735244dcc8b5842dd819f83e42f196291b4ca4..bdde74da84c7f5465b4b5d65acabff7349e1ddfa 100644
--- a/src/sakia/gui/main_window/controller.py
+++ b/src/sakia/gui/main_window/controller.py
@@ -61,11 +61,15 @@ class MainWindowController(ComponentController):
         main_window.status_bar = main_window.attach(StatusBarController.create(main_window, app))
         view.setStatusBar(main_window.status_bar._view)
 
-        main_window.toolbar = main_window.attach(ToolbarController.create(main_window, password_asker))
-        view.top_layout.addWidget(main_window.toolbar._view)
-
         main_window.navigation = main_window.attach(NavigationController.create(main_window, app))
         view.bottom_layout.insertWidget(0, main_window.navigation._view)
+        main_window.navigation.community_changed.connect(main_window.handle_community_change)
+        main_window.navigation.account_changed.connect(main_window.handle_community_change)
+
+        main_window.toolbar = main_window.attach(ToolbarController.create(main_window, app,
+                                                                          app.current_account, None,
+                                                                          password_asker))
+        view.top_layout.addWidget(main_window.toolbar._view)
 
         #app.version_requested.connect(main_window.latest_version_requested)
         #app.account_imported.connect(main_window.import_account_accepted)
@@ -107,6 +111,20 @@ class MainWindowController(ComponentController):
                 version_info=version_info,
                 version_url=version_url))
 
+    def handle_account_change(self, account):
+        """
+        Set current account
+        :param sakia.core.Account account:
+        """
+        self.toolbar.set_account(account)
+
+    def handle_community_change(self, community):
+        """
+        Set current community
+        :param sakia.core.Community community:
+        """
+        self.toolbar.set_community(community)
+
     def refresh(self):
         """
         Refresh main window
diff --git a/src/sakia/gui/navigation/controller.py b/src/sakia/gui/navigation/controller.py
index ac01f3bbd9ec9506dc2ed642d02468cb3aa63724..568f049a753c62d1f4eda62c9aa4713404f5b4a2 100644
--- a/src/sakia/gui/navigation/controller.py
+++ b/src/sakia/gui/navigation/controller.py
@@ -8,12 +8,16 @@ from ..identities.controller import IdentitiesController
 from ..informations.controller import InformationsController
 from ..graphs.wot.controller import WotController
 from ..graphs.explorer.controller import ExplorerController
+from sakia.core import Account, Community
+from PyQt5.QtCore import pyqtSignal
 
 
 class NavigationController(ComponentController):
     """
     The navigation panel
     """
+    community_changed = pyqtSignal(Community)
+    account_changed = pyqtSignal(Account)
 
     def __init__(self, parent, view, model):
         """
@@ -32,6 +36,7 @@ class NavigationController(ComponentController):
             'Wot': WotController,
             'Explorer': ExplorerController
         }
+        self.view.current_view_changed.connect(self.handle_view_change)
 
     @classmethod
     def create(cls, parent, app):
@@ -74,3 +79,16 @@ class NavigationController(ComponentController):
 
         self.view.set_model(self.model)
 
+    def handle_view_change(self, raw_data):
+        """
+        Handle view change
+        :param dict raw_data:
+        :return:
+        """
+        account = raw_data.get('account', None)
+        community = raw_data.get('community', None)
+        if account != self.model.current_data('account'):
+            self.account_changed.emit(account)
+        if community != self.model.current_data('community'):
+            self.community_changed.emit(community)
+        self.model.set_current_data(raw_data)
diff --git a/src/sakia/gui/navigation/model.py b/src/sakia/gui/navigation/model.py
index d487b5c129a154ac62c1b70e294e79978b079849..8a7f49ee67ce95416a308c9eaa0e830153270181 100644
--- a/src/sakia/gui/navigation/model.py
+++ b/src/sakia/gui/navigation/model.py
@@ -18,17 +18,20 @@ class NavigationModel(ComponentModel):
         super().__init__(parent)
         self.app = app
         self.navigation = {}
+        self._current_data = None
 
     def init_navigation_data(self):
         self.navigation = [
             {
                 'node': {
                     'title': self.app.current_account.name,
-                    'component': "HomeScreen"
+                    'component': "HomeScreen",
+                    'account': self.app.current_account
                 },
                 'children': []
             }
         ]
+        self._current_data = self.navigation[0]
         for c in self.app.current_account.communities:
             self.navigation[0]['children'].append({
                 'node': {
@@ -89,3 +92,9 @@ class NavigationModel(ComponentModel):
 
     def generic_tree(self):
         return GenericTreeModel.create("Navigation", self.navigation)
+
+    def set_current_data(self, raw_data):
+        self._current_data = raw_data
+
+    def current_data(self, key):
+        return self._current_data.get(key, None)
\ No newline at end of file
diff --git a/src/sakia/gui/navigation/view.py b/src/sakia/gui/navigation/view.py
index 178e1dabb484e87b76125926f570c84d11d7feb1..4518017f0b25ef779e55641a3b9d3b2762b6fe1a 100644
--- a/src/sakia/gui/navigation/view.py
+++ b/src/sakia/gui/navigation/view.py
@@ -1,5 +1,5 @@
 from PyQt5.QtWidgets import QFrame, QSizePolicy
-from PyQt5.QtCore import QModelIndex
+from PyQt5.QtCore import pyqtSignal
 from .navigation_uic import Ui_Navigation
 from ...models.generic_tree import GenericTreeModel
 
@@ -8,6 +8,7 @@ class NavigationView(QFrame, Ui_Navigation):
     """
     The view of navigation panel
     """
+    current_view_changed = pyqtSignal(dict)
 
     def __init__(self, parent):
         super().__init__(parent)
@@ -40,4 +41,5 @@ class NavigationView(QFrame, Ui_Navigation):
             if 'widget' in raw_data:
                 widget = raw_data['widget']
                 if self.stacked_widget.indexOf(widget):
-                    self.stacked_widget.setCurrentWidget(widget)
\ No newline at end of file
+                    self.stacked_widget.setCurrentWidget(widget)
+                    self.current_view_changed.emit(raw_data)
diff --git a/src/sakia/gui/search_user/controller.py b/src/sakia/gui/search_user/controller.py
index 8b7cde236406e65a4589c514bd827deb6de819ab..ba26cc77be7f6d8a77443c20338d8c3dfb6e49a8 100644
--- a/src/sakia/gui/search_user/controller.py
+++ b/src/sakia/gui/search_user/controller.py
@@ -60,4 +60,12 @@ class SearchUserController(ComponentController):
         Select node in graph when item is selected in combobox
         """
         self.model.select_identity(index)
-        self.identity_selected.emit(self.model.identity())
\ No newline at end of file
+        self.identity_selected.emit(self.model.identity())
+
+    def set_community(self, community):
+        """
+        Set community
+        :param sakia.core.Community community:
+        :return:
+        """
+        self.model.community = community
diff --git a/src/sakia/gui/toolbar/controller.py b/src/sakia/gui/toolbar/controller.py
index 6e2ebd9f6544ad06b469e53c5dd4d2fe9e132d5d..b9622b26b719ce238c9ebeba69fcbf0c6462dd5a 100644
--- a/src/sakia/gui/toolbar/controller.py
+++ b/src/sakia/gui/toolbar/controller.py
@@ -6,6 +6,7 @@ from .view import ToolbarView
 from ...tools.decorators import asyncify, once_at_a_time, cancel_once_task
 from ..widgets.dialogs import QAsyncMessageBox, QAsyncFileDialog, dialog_async_exec
 from ..widgets import toast
+from ..certification.controller import CertificationController
 import logging
 
 
@@ -16,7 +17,7 @@ class ToolbarController(ComponentController):
 
     def __init__(self, parent, view, model, password_asker):
         """
-        :param sakia.gui.agent.controller.AgentController parent: the parent
+        :param sakia.gui.component.controller.ComponentController parent: the parent
         :param sakia.gui.toolbar.view.ToolbarView view:
         :param sakia.gui.toolbar.model.ToolbarModel model:
         """
@@ -30,7 +31,7 @@ class ToolbarController(ComponentController):
         self.view.button_membership.clicked.connect(self.send_membership_demand)
 
     @classmethod
-    def create(cls, parent, password_asker):
+    def create(cls, parent, app, account, community, password_asker):
         """
         Instanciate a navigation component
         :param sakia.gui.agent.controller.AgentController parent:
@@ -38,7 +39,7 @@ class ToolbarController(ComponentController):
         :rtype: ToolbarController
         """
         view = ToolbarView(parent.view)
-        model = ToolbarModel(None)
+        model = ToolbarModel(None, app, account, community)
         toolbar = cls(parent, view, model, password_asker)
         model.setParent(toolbar)
         return toolbar
@@ -173,10 +174,24 @@ The process to join back the community later will have to be done again.""")
                 self.button_certification.setEnabled(False)
                 self.action_publish_uid.setEnabled(False)
 
+    def set_account(self, account):
+        """
+        Set current account
+        :param sakia.core.Account account:
+        """
+        self.model.account = account
+
+    def set_community(self, community):
+        """
+        Set current community
+        :param sakia.core.Community community:
+        """
+        self.model.community = community
+
     def open_certification_dialog(self):
-        CertificationDialog.open_dialog(self.app,
-                                     self.account,
-                                     self.community_view.community,
+        CertificationController.open_dialog(self, self.model.app,
+                                     self.model.account,
+                                     self.model.community,
                                      self.password_asker)
 
     def open_revocation_dialog(self):
diff --git a/src/sakia/gui/toolbar/model.py b/src/sakia/gui/toolbar/model.py
index 6d8d4ce41e719462c5cc561d52632b3ca093fdd4..68a011601e8983feca9a374be0fca00e7ab81715 100644
--- a/src/sakia/gui/toolbar/model.py
+++ b/src/sakia/gui/toolbar/model.py
@@ -6,5 +6,8 @@ class ToolbarModel(ComponentModel):
     The model of Navigation component
     """
 
-    def __init__(self, parent):
+    def __init__(self, parent, app, account, community):
         super().__init__(parent)
+        self.app = app
+        self.account = account
+        self.community = community
diff --git a/src/sakia/gui/widgets/context_menu.py b/src/sakia/gui/widgets/context_menu.py
index 60e7b4a14ca899b66231c30894fe693978ee6b76..5124c826abd2e433a1ce5016e8a3541e87e7884f 100644
--- a/src/sakia/gui/widgets/context_menu.py
+++ b/src/sakia/gui/widgets/context_menu.py
@@ -6,7 +6,7 @@ import logging
 from ..member import MemberDialog
 from ..contact import ConfigureContactDialog
 from ..transfer import TransferMoneyDialog
-from ..certification import CertificationDialog
+from ..certification.controller import CertificationController
 from ...tools.decorators import asyncify
 from ...core.transfer import Transfer, TransferState
 from ...core.registry import Identity
@@ -152,7 +152,7 @@ class ContextMenu(QObject):
 
     @asyncify
     async def certify_identity(self, identity):
-        await CertificationDialog.certify_identity(self._app, self._account, self._password_asker,
+        await CertificationController.certify_identity(None, self._app, self._account, self._password_asker,
                                              self._community, identity)
 
     @asyncify