Skip to content

Commit d33ae9a

Browse files
committed
Add ThemeEngine class
1 parent 93625df commit d33ae9a

File tree

9 files changed

+242
-0
lines changed

9 files changed

+242
-0
lines changed

src/ui/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ set(MODULE_SRC
44
uimodule.cpp
55
uimodule.h
66
iuiengine.h
7+
ithemeengine.h
78
internal/uiengine.cpp
89
internal/uiengine.h
10+
internal/themeengine.cpp
11+
internal/themeengine.h
912
)
1013

1114
include(${PROJECT_SOURCE_DIR}/build/module.cmake)

src/ui/internal/themeengine.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// SPDX-License-Identifier: GPL-3.0-or-later
2+
3+
#include "themeengine.h"
4+
#include "isettings.h"
5+
6+
using namespace scratchcpp;
7+
8+
static const QString MODULE = "ui";
9+
static const QString THEME_KEY = "theme";
10+
11+
std::shared_ptr<ThemeEngine> ThemeEngine::m_instance = std::make_shared<ThemeEngine>();
12+
13+
std::shared_ptr<ThemeEngine> ThemeEngine::instance()
14+
{
15+
return m_instance;
16+
}
17+
18+
IThemeEngine::Theme ThemeEngine::theme() const
19+
{
20+
return static_cast<Theme>(settings()->getValue(MODULE, THEME_KEY).toInt());
21+
}
22+
23+
void ThemeEngine::setTheme(Theme newTheme)
24+
{
25+
settings()->setValue(MODULE, THEME_KEY, static_cast<int>(newTheme));
26+
reloadTheme();
27+
}
28+
29+
void ThemeEngine::reloadTheme()
30+
{
31+
emit bgColorChanged();
32+
emit borderColorChanged();
33+
emit themeChanged();
34+
}
35+
36+
void ThemeEngine::resetTheme()
37+
{
38+
setTheme(Theme::DarkTheme);
39+
}
40+
41+
const QColor &ThemeEngine::bgColor() const
42+
{
43+
static const QColor dark = QColor(31, 30, 28);
44+
static const QColor light = QColor(255, 255, 255);
45+
return theme() == Theme::DarkTheme ? dark : light;
46+
}
47+
48+
const QColor &ThemeEngine::borderColor() const
49+
{
50+
static const QColor dark = QColor(255, 255, 255, 64);
51+
static const QColor light = QColor(0, 0, 0, 64);
52+
return theme() == Theme::DarkTheme ? dark : light;
53+
}

src/ui/internal/themeengine.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// SPDX-License-Identifier: GPL-3.0-or-later
2+
3+
#pragma once
4+
5+
#include <QColor>
6+
7+
#include "ithemeengine.h"
8+
9+
Q_MOC_INCLUDE("isettings.h")
10+
11+
namespace scratchcpp
12+
{
13+
14+
class ISettings;
15+
16+
class ThemeEngine : public IThemeEngine
17+
{
18+
Q_OBJECT
19+
INJECT(ISettings, settings)
20+
Q_PROPERTY(Theme theme READ theme WRITE setTheme NOTIFY themeChanged FINAL)
21+
Q_PROPERTY(QColor bgColor READ bgColor NOTIFY bgColorChanged FINAL)
22+
Q_PROPERTY(QColor borderColor READ borderColor NOTIFY borderColorChanged FINAL)
23+
public:
24+
static std::shared_ptr<ThemeEngine> instance();
25+
26+
Theme theme() const override;
27+
void setTheme(Theme newTheme) override;
28+
Q_INVOKABLE void reloadTheme() override;
29+
Q_INVOKABLE void resetTheme() override;
30+
31+
const QColor &bgColor() const override;
32+
const QColor &borderColor() const override;
33+
34+
signals:
35+
void themeChanged();
36+
void bgColorChanged();
37+
void borderColorChanged();
38+
39+
private:
40+
static std::shared_ptr<ThemeEngine> m_instance;
41+
};
42+
43+
} // namespace scratchcpp

src/ui/ithemeengine.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// SPDX-License-Identifier: GPL-3.0-or-later
2+
3+
#pragma once
4+
5+
#include <QObject>
6+
7+
#include "modularity/ioc.h"
8+
9+
namespace scratchcpp
10+
{
11+
12+
class IThemeEngine
13+
: public QObject
14+
, MODULE_EXPORT_INTERFACE
15+
{
16+
Q_OBJECT
17+
public:
18+
virtual ~IThemeEngine() { }
19+
20+
enum class Theme
21+
{
22+
LightTheme = 1,
23+
DarkTheme = 0
24+
};
25+
Q_ENUM(Theme)
26+
27+
virtual Theme theme() const = 0;
28+
virtual void setTheme(Theme newTheme) = 0;
29+
virtual void reloadTheme() = 0;
30+
virtual void resetTheme() = 0;
31+
32+
virtual const QColor &bgColor() const = 0;
33+
virtual const QColor &borderColor() const = 0;
34+
};
35+
36+
} // namespace scratchcpp

src/ui/test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
set(MODULE_TEST_SRC
22
uiengine.cpp
3+
themeengine.cpp
34
)
45

56
include(${PROJECT_SOURCE_DIR}/build/module_test.cmake)

src/ui/test/mocks/settingsmock.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#pragma once
2+
3+
#include <isettings.h>
4+
#include <gmock/gmock.h>
5+
6+
namespace scratchcpp
7+
{
8+
9+
class SettingsMock : public ISettings
10+
{
11+
public:
12+
MOCK_METHOD(void, addKey, (const QString &, const QString &, const QVariant &), (override));
13+
MOCK_METHOD(void, setValue, (const QString &, const QString &, const QVariant &), (override));
14+
MOCK_METHOD(QVariant, getValue, (const QString &, const QString &), (const, override));
15+
MOCK_METHOD(bool, containsKey, (const QString &, const QString &), (const, override));
16+
17+
MOCK_METHOD(void, freeze, (), (override));
18+
MOCK_METHOD(void, saveChanges, (), (override));
19+
MOCK_METHOD(void, discardChanges, (), (override));
20+
MOCK_METHOD(bool, isFrozen, (), (const, override));
21+
};
22+
23+
} // namespace scratchcpp

src/ui/test/themeengine.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#include <gtest/gtest.h>
2+
#include <gmock/gmock.h>
3+
#include <QSignalSpy>
4+
5+
#include "mocks/settingsmock.h"
6+
7+
#include "internal/themeengine.h"
8+
9+
using namespace scratchcpp;
10+
11+
using ::testing::Return;
12+
using ::testing::_;
13+
14+
static const QString MODULE = "ui";
15+
static const QString THEME_KEY = "theme";
16+
17+
class ThemeEngineTest : public testing::Test
18+
{
19+
public:
20+
void SetUp() override
21+
{
22+
m_settings = std::make_shared<SettingsMock>();
23+
m_themeEngine.setsettings(m_settings);
24+
25+
m_themeSpies.push_back(std::make_unique<QSignalSpy>(&m_themeEngine, &ThemeEngine::themeChanged));
26+
m_themeSpies.push_back(std::make_unique<QSignalSpy>(&m_themeEngine, &ThemeEngine::bgColorChanged));
27+
m_themeSpies.push_back(std::make_unique<QSignalSpy>(&m_themeEngine, &ThemeEngine::borderColorChanged));
28+
}
29+
30+
void TearDown() override { m_themeEngine.setsettings(nullptr); }
31+
32+
void checkThemeSpies(int count)
33+
{
34+
for (const auto &spy : m_themeSpies)
35+
ASSERT_EQ(spy->count(), count);
36+
}
37+
38+
ThemeEngine m_themeEngine;
39+
std::shared_ptr<SettingsMock> m_settings;
40+
std::vector<std::unique_ptr<QSignalSpy>> m_themeSpies;
41+
};
42+
43+
TEST_F(ThemeEngineTest, Instance)
44+
{
45+
ASSERT_TRUE(ThemeEngine::instance());
46+
}
47+
48+
TEST_F(ThemeEngineTest, Theme)
49+
{
50+
EXPECT_CALL(*m_settings, getValue(MODULE, THEME_KEY)).WillOnce(Return(0));
51+
ASSERT_EQ(m_themeEngine.theme(), ThemeEngine::Theme::DarkTheme);
52+
53+
EXPECT_CALL(*m_settings, getValue(MODULE, THEME_KEY)).WillOnce(Return(1));
54+
ASSERT_EQ(m_themeEngine.theme(), ThemeEngine::Theme::LightTheme);
55+
checkThemeSpies(0);
56+
57+
EXPECT_CALL(*m_settings, setValue(MODULE, THEME_KEY, QVariant(0)));
58+
m_themeEngine.setTheme(ThemeEngine::Theme::DarkTheme);
59+
checkThemeSpies(1);
60+
61+
EXPECT_CALL(*m_settings, setValue(MODULE, THEME_KEY, QVariant(1)));
62+
m_themeEngine.setTheme(ThemeEngine::Theme::LightTheme);
63+
checkThemeSpies(2);
64+
65+
EXPECT_CALL(*m_settings, setValue(MODULE, THEME_KEY, _));
66+
m_themeEngine.resetTheme();
67+
checkThemeSpies(3);
68+
69+
m_themeEngine.reloadTheme();
70+
checkThemeSpies(4);
71+
}

src/ui/uimodule.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
#include <QQmlEngine>
44

55
#include "uimodule.h"
6+
#include "isettings.h"
67
#include "internal/uiengine.h"
8+
#include "internal/themeengine.h"
79

810
using namespace scratchcpp::ui;
911

@@ -21,4 +23,13 @@ void scratchcpp::ui::UiModule::registerExports()
2123
QQmlEngine::setObjectOwnership(UiEngine::instance().get(), QQmlEngine::CppOwnership);
2224
qmlRegisterSingletonInstance<UiEngine>("ScratchCPP.Ui", 1, 0, "UiEngine", UiEngine::instance().get());
2325
modularity::ioc()->registerExport<IUiEngine>(UiEngine::instance());
26+
27+
QQmlEngine::setObjectOwnership(ThemeEngine::instance().get(), QQmlEngine::CppOwnership);
28+
qmlRegisterSingletonInstance<ThemeEngine>("ScratchCPP.Ui", 1, 0, "ThemeEngine", ThemeEngine::instance().get());
29+
modularity::ioc()->registerExport<IThemeEngine>(ThemeEngine::instance());
30+
}
31+
32+
void UiModule::initSettings()
33+
{
34+
INIT_SETTINGS_KEY("theme", static_cast<int>(IThemeEngine::Theme::DarkTheme));
2435
}

src/ui/uimodule.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class UiModule : public modularity::IModuleSetup
1515
std::string moduleName() const override;
1616

1717
void registerExports() override;
18+
void initSettings() override;
1819
};
1920

2021
} // namespace scratchcpp::ui

0 commit comments

Comments
 (0)