diff --git a/src/Lib/Utils.hh b/src/Lib/Utils.hh
index 52a3b8dbd21877ce70f37ba06096939751c00bfe..c2ac33642dbf2cb15e435f2105bf0c19ff726369 100644
--- a/src/Lib/Utils.hh
+++ b/src/Lib/Utils.hh
@@ -21,6 +21,11 @@
 #define VIVY_DEPRECATED  __attribute__((__deprecated__))
 #define VIVY_CONSTRUCTOR __attribute__((constructor))
 #define VIVY_DESTRUCTOR  __attribute__((destructor))
+#define VIVY_ASSERT(cond)              \
+    {                                  \
+        if (!cond)                     \
+            VIVY_ASSERT_STRING(#cond); \
+    }
 
 // Use chrono instead of std::chrono...
 namespace chrono = std::chrono;
diff --git a/src/UI/Theme/Theme.cc b/src/UI/Theme/Theme.cc
index 12d07e2b7cb1a5386cfa86657fb823e728850004..2c7512057e86c27a96fdacc89733bcce41da7c55 100644
--- a/src/UI/Theme/Theme.cc
+++ b/src/UI/Theme/Theme.cc
@@ -1,6 +1,7 @@
 #include "Theme.hh"
+#include "../../VivyApplication.hh"
 #include "../../Lib/HostOsInfo.hh"
-#ifdef Q_OS_MACOS
+#if VIVY_MACOS
 #import "ThemeMac.hh"
 #endif
 
@@ -18,15 +19,26 @@ Theme::ThemePrivate::ThemePrivate() noexcept
 void
 Theme::applyToApplication() const noexcept
 {
-#ifdef Q_OS_MACOS
-    // Match the native UI theme and palette with the creator
-    // theme by forcing light aqua for light creator themes.
-    if (!flag(Theme::DarkUserInterface))
-        Internal::forceMacOSLightAquaApperance();
-#endif
+    if (d->classType == Type::QssFile) {
+        QFile stylesheet(d->fileName);
+        if (!stylesheet.exists()) {
+            qFatal("Missing stylesheet");
+        } else {
+            stylesheet.open(QFile::ReadOnly | QFile::Text);
+            QTextStream stylesheetStream(&stylesheet);
+            vivyApp->setStyleSheet(stylesheetStream.readAll());
+        }
+    }
 
-    // if (flag(Theme::ApplyThemePaletteGlobally))
-    QApplication::setPalette(palette());
+    else {
+#if VIVY_MACOS
+        // Match the native UI theme and palette with the creator
+        // theme by forcing light aqua for light creator themes.
+        if (!flag(Theme::DarkUserInterface))
+            Utils::forceMacOSLightAquaApperance();
+#endif
+        QApplication::setPalette(palette());
+    }
 }
 
 Theme::Theme(const QString &id, QObject *parent) noexcept
@@ -115,10 +127,36 @@ Theme::setDisplayName(const QString &name) noexcept
     d->displayName = name;
 }
 
+Theme *
+Theme::fromQssFile(const QString &id, const QString &file) noexcept
+{
+    Theme *ret        = new Theme(id);
+    ret->d->fileName  = file;
+    ret->d->classType = Type::QssFile;
+    return ret;
+}
+
+Theme *
+Theme::fromSettings(const QString &id, QSettings *const settings) noexcept
+{
+    Theme *ret = new Theme(id);
+    ret->readSettings(settings);
+    return ret;
+}
+
+Theme *
+Theme::fromVivyTheme(const QString &id, const VivyTheme which) noexcept
+{
+    return fromQssFile(id, which == VivyTheme::Dark
+                               ? QStringLiteral(":qdarkstyle/dark/style.qss")
+                               : QStringLiteral(":qdarkstyle/light/style.qss"));
+}
+
 void
 Theme::readSettings(QSettings *const settings) noexcept
 {
     d->fileName          = settings->fileName();
+    d->classType         = Type::QtCreator;
     const QMetaObject &m = *metaObject();
 
     {
@@ -169,10 +207,9 @@ Theme::readSettings(QSettings *const settings) noexcept
             int size = settings->beginReadArray(key);
             for (int j = 0; j < size; ++j) {
                 settings->setArrayIndex(j);
-                TODO(Assert things when needed !);
-                settings->contains(QLatin1String("pos")); // TODO: Assert it
+                VIVY_ASSERT(settings->contains(QLatin1String("pos")));
+                VIVY_ASSERT(settings->contains(QLatin1String("color")));
                 const double pos = settings->value(QLatin1String("pos")).toDouble();
-                settings->contains(QLatin1String("color")); // TODO: Assert it
                 const QColor c('#' + settings->value(QLatin1String("color")).toString());
                 stops.append(qMakePair(pos, c));
             }
@@ -186,8 +223,7 @@ Theme::readSettings(QSettings *const settings) noexcept
         QMetaEnum e = m.enumerator(m.indexOfEnumerator("Flag"));
         for (int i = 0, total = e.keyCount(); i < total; ++i) {
             const QString key = QLatin1String(e.key(i));
-            TODO(Assert it);
-            settings->contains(key); // TODO: Assert it!
+            VIVY_ASSERT(settings->contains(key));
             d->flags[i] = settings->value(key).toBool();
         }
         settings->endGroup();
@@ -238,8 +274,6 @@ QPalette
 Theme::palette() const noexcept
 {
     QPalette pal = initialPalette();
-    // if (!flag(DerivePaletteFromTheme))
-    //     return pal;
 
     const static struct {
         Color themeColor;
diff --git a/src/UI/Theme/Theme.hh b/src/UI/Theme/Theme.hh
index 86a3dc489085cddaaa3bd472c7b045b832d3e894..3b3542d9adb4a60a4b820ec20e9edee3743c479f 100644
--- a/src/UI/Theme/Theme.hh
+++ b/src/UI/Theme/Theme.hh
@@ -10,9 +10,16 @@ class Theme;
 class Theme final : public QObject {
     Q_OBJECT
 
+public:
+    enum class Type { QtCreator, System, QssFile };
+    enum class VivyTheme { Dark, Light };
+
+private:
     struct ThemePrivate final {
         ThemePrivate() noexcept;
 
+        Theme::Type classType{ Theme::Type::System };
+
         QString id;
         QString fileName;
         QString displayName;
@@ -25,10 +32,17 @@ class Theme final : public QObject {
         QMap<QString, QColor> palette;
     };
 
-public:
     Theme(const QString &id, QObject *parent = nullptr) noexcept;
+
+    void readSettings(QSettings *const settings) noexcept;
+
+public:
     ~Theme() noexcept override;
 
+    [[nodiscard]] static Theme *fromQssFile(const QString &, const QString &) noexcept;
+    [[nodiscard]] static Theme *fromSettings(const QString &, QSettings *const) noexcept;
+    [[nodiscard]] static Theme *fromVivyTheme(const QString &, const VivyTheme) noexcept;
+
     void applyToApplication() const noexcept;
 
     enum Color {
@@ -463,8 +477,6 @@ public:
     QString displayName() const noexcept;
     void setDisplayName(const QString &displayName) noexcept;
 
-    void readSettings(QSettings *const settings) noexcept;
-
     static bool systemUsesDarkMode() noexcept;
     static QPalette initialPalette() noexcept;
 
diff --git a/src/VivyApplication.cc b/src/VivyApplication.cc
index 08f2b2aca14c97e496073a570893b7198b7e64dc..907e02c0dca08eca00a0d7bcafee3acece9b304b 100644
--- a/src/VivyApplication.cc
+++ b/src/VivyApplication.cc
@@ -1,6 +1,7 @@
 #include "VivyApplication.hh"
 #include "UI/MainWindow.hh"
 #include "UI/DockWidgetTitleBar.hh"
+#include "UI/LogConsole.hh"
 #include "UI/Theme/Theme.hh"
 #include "Lib/Document/VivyDocumentStore.hh"
 #include "Lib/Document/VivyDocument.hh"
@@ -44,34 +45,25 @@ VivyApplication::VivyApplication(int &argc, char **argv)
 VivyApplication::~VivyApplication() noexcept {}
 
 void
-VivyApplication::setTheme(Theme theme) noexcept
+VivyApplication::setTheme(Theme::Type theme, Theme::VivyTheme preferedColor) noexcept
 {
-    if (theme == Theme::System) {
-        logInfo() << "Set theme to system theme";
+    if (theme == Theme::Type::System) {
         return;
     }
 
-    else if (theme == Theme::QtCreator) {
-        qtCreatorThemePtr.reset(new Vivy::Theme("QtCreator"));
+    else if (theme == Theme::Type::QtCreator) {
         QSettings settings(QStringLiteral(":theme/design.creatortheme"), QSettings::IniFormat);
-        qtCreatorThemePtr->readSettings(&settings);
+        qtCreatorThemePtr.reset(Vivy::Theme::fromSettings("QtCreator", &settings));
         qtCreatorThemePtr->applyToApplication();
         return;
     }
 
-    const QString sheet = theme == Theme::Dark ? QStringLiteral(":qdarkstyle/dark/style.qss")
-                                               : QStringLiteral(":qdarkstyle/light/style.qss");
-
-    QFile stylesheet(sheet);
-    if (!stylesheet.exists()) {
-        logFatal() << "Missing stylesheet!";
-        exit(EXIT_FAILURE);
-    } else {
-        stylesheet.open(QFile::ReadOnly | QFile::Text);
-        QTextStream stylesheetStream(&stylesheet);
-        setStyleSheet(stylesheetStream.readAll());
-        logInfo() << "Theme set using " << VIVY_LOG_QUOTED(sheet);
+    if (theme != Theme::Type::QssFile) {
+        qFatal("Unknown Theme type");
     }
+
+    qtCreatorThemePtr.reset(Vivy::Theme::fromVivyTheme("VivyTheme", preferedColor));
+    qtCreatorThemePtr->applyToApplication();
 }
 
 int
@@ -93,8 +85,7 @@ VivyApplication::exec() noexcept
     setAttribute(Qt::AA_DontShowIconsInMenus, false);
     setAttribute(Qt::AA_DontShowShortcutsInContextMenus, false);
     setFont(getApplicationFont(Font::Default));
-    setTheme(Theme::QtCreator); // TODO: Set system theme for now (because we
-                                // don't have a central theme provider).
+    setTheme(Theme::Type::QtCreator, Theme::VivyTheme::Dark);
 
     // Cursor blinking
     setCursorFlashTime(0);
diff --git a/src/VivyApplication.hh b/src/VivyApplication.hh
index 1d4164412b0cb8cd01a9a92e28c884d445644689..b716bf4556ef221d20b01d91a16bf8563786a1c9 100644
--- a/src/VivyApplication.hh
+++ b/src/VivyApplication.hh
@@ -36,11 +36,13 @@
 
 // Detect MacOS
 #if defined(Q_OS_DARWIN) || defined(Q_OS_MACOS)
-#define VIVY_MACOS
+#define VIVY_MACOS 1
+#else
+#define VIVY_MACOS 0
 #endif
 
 #include "Lib/Log.hh"
-#include "UI/LogConsole.hh"
+#include "UI/Theme/Theme.hh"
 
 namespace Vivy
 {
@@ -74,8 +76,6 @@ public:
         DefaultBoldItalic
     };
 
-    enum class Theme { System, Dark, Light, QtCreator };
-
 private:
     int fontIdMonospace;
     int fontIdMonospaceBold;
@@ -103,11 +103,10 @@ public:
     [[nodiscard]] MainWindow *getMainWindow() const;
     [[nodiscard]] AbstractDocument *getCurrentDocument() const;
     [[nodiscard]] bool getUseFakeVimEditor() const noexcept;
+    std::shared_ptr<LogSink> getLogSink() noexcept { return logSink; }
 
     void setUseFakeVimEditor(bool) noexcept;
-    void setTheme(Theme) noexcept;
-
-    std::shared_ptr<LogSink> getLogSink() noexcept { return logSink; }
+    void setTheme(Theme::Type, Theme::VivyTheme) noexcept;
 };
 
 }