mirror of
https://github.com/mudita/MuditaOS.git
synced 2026-04-21 07:28:21 -04:00
[BH-1989][BH-1990] Core functionality of What's New app
Implemented core functionality of What's New application.
This commit is contained in:
@@ -103,6 +103,11 @@
|
||||
"app_bell_onboarding_shortcuts_step_restart": "Press both side buttons for 10s to restart the device",
|
||||
"app_bell_onboarding_shortcuts_step_rotate": "Rotate to select",
|
||||
"app_bell_onboarding_shortcuts_step_turn_off": "Press back for 10s to turn off the device",
|
||||
"app_bell_whatsnew_title": "What's New",
|
||||
"app_bell_whatsnew_version": "<text>OS version: <token>$VERSION</token></text>",
|
||||
"app_bell_whatsnew_continue": "Continue",
|
||||
"app_bell_whatsnew_skip": "Skip",
|
||||
"app_bell_whatsnew_end_screen_text": "<text>We'd love to hear your feedback about this update at<br/><b>mudita.com/forum</b></text>",
|
||||
"app_bell_relaxation_loop": "loop",
|
||||
"app_bell_relaxation_loop_description": "the song will play until you turn it off",
|
||||
"app_bell_relaxation_looped": "looped",
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace gui
|
||||
void setBottomDescriptionText(const std::string &description);
|
||||
|
||||
protected:
|
||||
BellSideListItem(BellBaseLayout::LayoutType type = BellBaseLayout::LayoutType::WithArrows);
|
||||
explicit BellSideListItem(BellBaseLayout::LayoutType type = BellBaseLayout::LayoutType::WithArrows);
|
||||
void setupBottomTextBox(const std::string &description);
|
||||
void setupTopTextBox(const std::string &description);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
|
||||
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#pragma once
|
||||
@@ -10,4 +10,4 @@
|
||||
/// Zero terminated string with single-quotes on both ends, for instance: 'my string'
|
||||
#define str_ "%Q"
|
||||
/// The same as above with additional comma at the end, for instance: 'my string',
|
||||
#define str_c "%Q,"
|
||||
#define str_c "%Q,"
|
||||
|
||||
@@ -27,7 +27,6 @@ target_sources(application-bell-meditation-timer
|
||||
presenter/MeditationProgressPresenter.cpp
|
||||
presenter/MeditationTimerPresenter.cpp
|
||||
presenter/ReadyGoingPresenter.cpp
|
||||
presenter/SessionEndedPresenter.cpp
|
||||
presenter/SettingsPresenter.cpp
|
||||
presenter/StatisticsPresenter.cpp
|
||||
windows/MeditationMainWindow.cpp
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#include "SessionEndedPresenter.hpp"
|
||||
|
||||
#include <service-appmgr/Controller.hpp>
|
||||
|
||||
namespace app::meditation
|
||||
{
|
||||
SessionEndedPresenter::SessionEndedPresenter(app::ApplicationCommon *app) : app{app}
|
||||
{}
|
||||
|
||||
void SessionEndedPresenter::activate()
|
||||
{
|
||||
app::manager::Controller::sendAction(app, app::manager::actions::Home);
|
||||
}
|
||||
} // namespace app::meditation
|
||||
@@ -1,39 +0,0 @@
|
||||
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Application.hpp>
|
||||
#include <apps-common/BasePresenter.hpp>
|
||||
|
||||
namespace app
|
||||
{
|
||||
class ApplicationCommon;
|
||||
}
|
||||
|
||||
namespace app::meditation
|
||||
{
|
||||
class SessionEndedPresenterContract
|
||||
{
|
||||
public:
|
||||
class View
|
||||
{
|
||||
public:
|
||||
virtual ~View() = default;
|
||||
};
|
||||
class Presenter : public BasePresenter<SessionEndedPresenterContract::View>
|
||||
{
|
||||
public:
|
||||
virtual void activate() = 0;
|
||||
};
|
||||
};
|
||||
|
||||
class SessionEndedPresenter : public SessionEndedPresenterContract::Presenter
|
||||
{
|
||||
app::ApplicationCommon *app{};
|
||||
void activate() override;
|
||||
|
||||
public:
|
||||
explicit SessionEndedPresenter(app::ApplicationCommon *app);
|
||||
};
|
||||
} // namespace app::meditation
|
||||
@@ -97,7 +97,6 @@ namespace app
|
||||
|
||||
void ApplicationBellOnBoarding::createUserInterface()
|
||||
{
|
||||
|
||||
windowsFactory.attach(gui::name::window::main_window, [this](ApplicationCommon *app, const std::string &name) {
|
||||
auto powerOffPresenter = std::make_unique<gui::BellPowerOffPresenter>(app);
|
||||
return std::make_unique<gui::OnBoardingOnOffWindow>(app, std::move(powerOffPresenter), name);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
|
||||
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <apps-common/widgets/BellSideListItem.hpp>
|
||||
#include <apps-common/widgets/spinners/Spinners.hpp>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
|
||||
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#include "AboutYourBellWindow.hpp"
|
||||
@@ -11,7 +11,7 @@ namespace gui
|
||||
{
|
||||
namespace
|
||||
{
|
||||
static constexpr auto top_margin = 41U;
|
||||
constexpr auto top_margin = 41U;
|
||||
}
|
||||
|
||||
AboutYourBellWindow::AboutYourBellWindow(
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
|
||||
#include "ApplicationWhatsNew.hpp"
|
||||
#include "WhatsNewCommon.hpp"
|
||||
#include "WhatsNewMainWindow.hpp"
|
||||
#include "WhatsNewMainPresenter.hpp"
|
||||
#include "WhatsNewFeaturesWindow.hpp"
|
||||
#include "WhatsNewFeaturesPresenter.hpp"
|
||||
#include "WhatsNewFeaturesModel.hpp"
|
||||
|
||||
#include "windows/WhatsNewWindow.hpp"
|
||||
#include "presenter/WhatsNewPresenter.hpp"
|
||||
#include "models/WhatsNewModel.hpp"
|
||||
|
||||
#include <common/windows/BellFinishedWindow.hpp>
|
||||
#include <common/windows/AppsBatteryStatusWindow.hpp>
|
||||
#include <system/messages/SentinelRegistrationMessage.hpp>
|
||||
|
||||
@@ -33,10 +35,6 @@ namespace app
|
||||
return ret;
|
||||
}
|
||||
|
||||
whatsNewModel = std::make_unique<whatsNew::models::WhatsNewModel>(this);
|
||||
|
||||
batteryModel = std::make_unique<app::BatteryModel>(this);
|
||||
lowBatteryInfoModel = std::make_unique<app::LowBatteryInfoModel>();
|
||||
cpuSentinel = std::make_shared<sys::CpuSentinel>(applicationWhatsNewName, this);
|
||||
auto sentinelRegistrationMsg = std::make_shared<sys::SentinelRegistrationMessage>(cpuSentinel);
|
||||
bus.sendUnicast(std::move(sentinelRegistrationMsg), service::name::system_manager);
|
||||
@@ -49,16 +47,27 @@ namespace app
|
||||
|
||||
void ApplicationWhatsNew::createUserInterface()
|
||||
{
|
||||
windowsFactory.attach(whatsNew::window::name::main, [this](ApplicationCommon *app, const std::string &name) {
|
||||
auto presenter = std::make_unique<app::whatsNew::WhatsNewPresenter>(*batteryModel, *lowBatteryInfoModel);
|
||||
return std::make_unique<whatsNew::WhatsNewWindow>(app, std::move(presenter));
|
||||
windowsFactory.attach(whatsnew::window::name::main, [this](ApplicationCommon *app, const std::string &name) {
|
||||
auto presenter = std::make_unique<whatsnew::WhatsNewMainPresenter>(settings.get());
|
||||
return std::make_unique<whatsnew::WhatsNewMainWindow>(app, std::move(presenter), name);
|
||||
});
|
||||
|
||||
windowsFactory.attach(whatsNew::window::name::whatsNewLowBattery,
|
||||
windowsFactory.attach(
|
||||
whatsnew::window::name::features, [this](ApplicationCommon *app, const std::string &name) {
|
||||
auto model = std::make_unique<whatsnew::models::WhatsNewFeaturesModel>(this, settings.get());
|
||||
auto presenter = std::make_unique<whatsnew::WhatsNewFeaturesPresenter>(std::move(model));
|
||||
return std::make_unique<whatsnew::WhatsNewFeaturesWindow>(app, std::move(presenter), name);
|
||||
});
|
||||
windowsFactory.attach(gui::window::bell_finished::defaultName,
|
||||
[](ApplicationCommon *app, const std::string &name) {
|
||||
return std::make_unique<gui::AppsBatteryStatusWindow>(app, name);
|
||||
return std::make_unique<gui::BellFinishedWindow>(app, name);
|
||||
});
|
||||
|
||||
// windowsFactory.attach(whatsnew::window::name::whatsNewLowBattery,
|
||||
// [](ApplicationCommon *app, const std::string &name) {
|
||||
// return std::make_unique<gui::AppsBatteryStatusWindow>(app, name);
|
||||
// });
|
||||
|
||||
attachPopups({gui::popup::ID::AlarmActivated,
|
||||
gui::popup::ID::AlarmDeactivated,
|
||||
gui::popup::ID::PowerOff,
|
||||
|
||||
@@ -12,6 +12,7 @@ target_include_directories(application-bell-whats-new
|
||||
data
|
||||
models
|
||||
presenter
|
||||
widgets
|
||||
windows
|
||||
>
|
||||
PUBLIC
|
||||
@@ -21,10 +22,16 @@ target_include_directories(application-bell-whats-new
|
||||
target_sources(application-bell-whats-new
|
||||
PRIVATE
|
||||
ApplicationWhatsNew.cpp
|
||||
|
||||
windows/WhatsNewWindow.cpp
|
||||
presenter/WhatsNewPresenter.cpp
|
||||
models/WhatsNewModel.cpp
|
||||
|
||||
models/WhatsNewFeaturesModel.cpp
|
||||
|
||||
presenter/WhatsNewFeaturesPresenter.cpp
|
||||
presenter/WhatsNewMainPresenter.cpp
|
||||
|
||||
widgets/WhatsNewFeaturesLayout.cpp
|
||||
|
||||
windows/WhatsNewMainWindow.cpp
|
||||
windows/WhatsNewFeaturesWindow.cpp
|
||||
|
||||
PUBLIC
|
||||
include/application-bell-whats-new/ApplicationWhatsNew.hpp
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
|
||||
#include <AppWindowConstants.hpp>
|
||||
|
||||
namespace app::whatsNew
|
||||
namespace app::whatsnew
|
||||
{
|
||||
namespace window::name
|
||||
{
|
||||
inline constexpr auto main = gui::name::window::main_window;
|
||||
inline constexpr auto whatsNewLowBattery = "WhatsNewLowBatteryWindow";
|
||||
inline constexpr auto features = "WhatsNewFeaturesWindow";
|
||||
// inline constexpr auto whatsNewLowBattery = "WhatsNewLowBatteryWindow";
|
||||
} // namespace window::name
|
||||
|
||||
} // namespace app::whatsNew
|
||||
} // namespace app::whatsnew
|
||||
|
||||
@@ -6,5 +6,56 @@
|
||||
#include <Style.hpp>
|
||||
#include "widgets/BellBaseLayout.hpp"
|
||||
|
||||
namespace app::whatsNew
|
||||
{} // namespace app::whatsNew
|
||||
namespace gui::whats_new_style
|
||||
{
|
||||
namespace main_window
|
||||
{
|
||||
inline constexpr auto list_title_font = style::window::font::large;
|
||||
inline constexpr auto description_font = style::window::font::mediumbigbold;
|
||||
inline constexpr auto description_height = 136U;
|
||||
} // namespace main_window
|
||||
|
||||
namespace features_window
|
||||
{
|
||||
namespace layout
|
||||
{
|
||||
inline constexpr auto width = style::window_width;
|
||||
inline constexpr auto height = style::window_height;
|
||||
} // namespace layout
|
||||
|
||||
namespace container
|
||||
{
|
||||
inline constexpr auto width = 544U;
|
||||
inline constexpr auto height = 436U;
|
||||
inline constexpr auto margin_top = 42U;
|
||||
} // namespace container
|
||||
|
||||
namespace center_box
|
||||
{
|
||||
inline constexpr auto width = 448U;
|
||||
inline constexpr auto height = 436U;
|
||||
} // namespace center_box
|
||||
|
||||
namespace icon
|
||||
{
|
||||
inline constexpr auto width = center_box::width;
|
||||
inline constexpr auto height = 120U;
|
||||
} // namespace icon
|
||||
|
||||
namespace title
|
||||
{
|
||||
inline constexpr auto font = style::window::font::large;
|
||||
inline constexpr auto width = center_box::width;
|
||||
inline constexpr auto height = 56U;
|
||||
inline constexpr auto margin_top = 16U;
|
||||
} // namespace title
|
||||
|
||||
namespace description
|
||||
{
|
||||
inline constexpr auto font = style::window::font::verybiglight;
|
||||
inline constexpr auto width = center_box::width;
|
||||
inline constexpr auto height = 168U;
|
||||
inline constexpr auto margin_top = 40U;
|
||||
} // namespace description
|
||||
} // namespace features_window
|
||||
} // namespace gui::whats_new_style
|
||||
|
||||
@@ -7,25 +7,26 @@
|
||||
#include <common/models/BatteryModel.hpp>
|
||||
#include <common/models/LowBatteryInfoModel.hpp>
|
||||
|
||||
namespace app::whatsNew::models
|
||||
namespace app::whatsnew::models
|
||||
{
|
||||
class WhatsNewModel;
|
||||
} // namespace app::whatsNew::models
|
||||
class WhatsNewFeaturesModel;
|
||||
}
|
||||
|
||||
namespace app
|
||||
{
|
||||
inline constexpr auto applicationWhatsNewName = "ApplicationWhatsNew";
|
||||
inline constexpr auto applicationWhatsNewStackSize = 1024 * 8;
|
||||
inline constexpr auto applicationWhatsNewStackSize = 1024 * 10;
|
||||
|
||||
class ApplicationWhatsNew : public Application
|
||||
{
|
||||
public:
|
||||
ApplicationWhatsNew(std::string name = applicationWhatsNewName,
|
||||
std::string parent = "",
|
||||
StatusIndicators statusIndicators = StatusIndicators{},
|
||||
StartInBackground startInBackground = false,
|
||||
std::uint32_t stackDepth = applicationWhatsNewStackSize);
|
||||
~ApplicationWhatsNew();
|
||||
explicit ApplicationWhatsNew(std::string name = applicationWhatsNewName,
|
||||
std::string parent = "",
|
||||
StatusIndicators statusIndicators = StatusIndicators{},
|
||||
StartInBackground startInBackground = false,
|
||||
std::uint32_t stackDepth = applicationWhatsNewStackSize);
|
||||
~ApplicationWhatsNew() override;
|
||||
|
||||
sys::ReturnCodes InitHandler() override;
|
||||
|
||||
void createUserInterface() override;
|
||||
@@ -40,7 +41,7 @@ namespace app
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<whatsNew::models::WhatsNewModel> whatsNewModel;
|
||||
std::unique_ptr<whatsnew::models::WhatsNewFeaturesModel> whatsNewModel;
|
||||
|
||||
std::unique_ptr<AbstractBatteryModel> batteryModel;
|
||||
std::unique_ptr<AbstractLowBatteryInfoModel> lowBatteryInfoModel;
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#include "WhatsNewFeaturesModel.hpp"
|
||||
#include <ApplicationCommon.hpp>
|
||||
#include <db/ServiceDB.hpp>
|
||||
#include <db/WhatsNewMessages.hpp>
|
||||
#include <service-db/Settings.hpp>
|
||||
#include <service-db/agents/settings/SystemSettings.hpp>
|
||||
#include <Utils.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace service::db::whatsnew;
|
||||
|
||||
auto getVersionNumber(const std::string &version) -> std::optional<VersionNumber>
|
||||
{
|
||||
constexpr auto versionSize{3U};
|
||||
|
||||
std::vector<std::string> strVector{utils::split(version, '.')};
|
||||
if (strVector.size() != versionSize) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::uint16_t> uintVector{};
|
||||
uintVector.reserve(versionSize);
|
||||
|
||||
for (const auto &str : strVector) {
|
||||
if (!utils::is_number(str)) {
|
||||
return {};
|
||||
}
|
||||
uintVector.push_back(utils::getNumericValue<std::uint16_t>(str));
|
||||
}
|
||||
return VersionNumber{uintVector[0], uintVector[1], uintVector[2]};
|
||||
}
|
||||
|
||||
auto sendDBRequest(sys::Service *serv, std::shared_ptr<sys::Message> &&msg) -> std::optional<messages::Response>
|
||||
{
|
||||
const auto ret = serv->bus.sendUnicastSync(std::move(msg), service::name::db, sys::BusProxy::defaultTimeout);
|
||||
if (ret.first == sys::ReturnCodes::Success) {
|
||||
if (auto resp = std::dynamic_pointer_cast<messages::Response>(ret.second)) {
|
||||
return *resp;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace app::whatsnew::models
|
||||
{
|
||||
WhatsNewFeaturesModel::WhatsNewFeaturesModel(app::ApplicationCommon *app, settings::Settings *settings)
|
||||
: settings{settings}
|
||||
{
|
||||
const auto &lastVersion =
|
||||
this->settings->getValue(settings::SystemProperties::osCurrentVersion, settings::SettingsScope::Global);
|
||||
const auto &version = getVersionNumber(lastVersion);
|
||||
if (!version.has_value()) {
|
||||
LOG_ERROR("Failed to parse last version string!");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &result = sendDBRequest(app, std::make_shared<messages::GetByVersion>(version.value()));
|
||||
if (result.has_value()) {
|
||||
for (const auto &record : result->records) {
|
||||
features.push_back(Feature{record.title, record.description, record.iconName});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto WhatsNewFeaturesModel::getFeatures() -> std::vector<Feature>
|
||||
{
|
||||
return features;
|
||||
}
|
||||
|
||||
auto WhatsNewFeaturesModel::setCurrentOsVersion(const std::string &version) -> void
|
||||
{
|
||||
settings->setValue(settings::SystemProperties::osCurrentVersion, version, settings::SettingsScope::Global);
|
||||
}
|
||||
} // namespace app::whatsnew::models
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace app
|
||||
{
|
||||
class ApplicationCommon;
|
||||
}
|
||||
|
||||
namespace settings
|
||||
{
|
||||
class Settings;
|
||||
}
|
||||
|
||||
namespace app::whatsnew::models
|
||||
{
|
||||
struct Feature
|
||||
{
|
||||
std::string title;
|
||||
std::string description;
|
||||
std::string iconName;
|
||||
};
|
||||
|
||||
class WhatsNewFeaturesModel
|
||||
{
|
||||
public:
|
||||
WhatsNewFeaturesModel(app::ApplicationCommon *app, settings::Settings *settings);
|
||||
|
||||
auto getFeatures() -> std::vector<Feature>;
|
||||
auto setCurrentOsVersion(const std::string &version) -> void;
|
||||
|
||||
private:
|
||||
app::ApplicationCommon *app{nullptr};
|
||||
settings::Settings *settings{nullptr};
|
||||
std::vector<Feature> features;
|
||||
};
|
||||
} // namespace app::whatsnew::models
|
||||
@@ -1,64 +0,0 @@
|
||||
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#include "WhatsNewModel.hpp"
|
||||
#include <ApplicationCommon.hpp>
|
||||
#include <db/ServiceDB.hpp>
|
||||
#include <db/WhatsNewMessages.hpp>
|
||||
#include <product/version.hpp>
|
||||
#include <Utils.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace service::db::whatsNew;
|
||||
constexpr auto versionSize{3U};
|
||||
|
||||
std::optional<VersionNumber> getVersionNumber(std::string version)
|
||||
{
|
||||
std::vector<std::string> strVector{utils::split(version, '.')};
|
||||
if (strVector.size() != versionSize) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::vector<std::uint16_t> uintVector{};
|
||||
uintVector.reserve(versionSize);
|
||||
|
||||
for (auto &str : strVector) {
|
||||
if (!utils::is_number(str)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
uintVector.push_back(utils::getNumericValue<std::uint16_t>(str));
|
||||
}
|
||||
return VersionNumber{.major{uintVector[0]}, .minor{uintVector[1]}, .patch{uintVector[2]}};
|
||||
}
|
||||
|
||||
std::optional<messages::Response> sendDBRequest(sys::Service *serv, std::shared_ptr<sys::Message> &&msg)
|
||||
{
|
||||
const auto ret = serv->bus.sendUnicastSync(std::move(msg), service::name::db, sys::BusProxy::defaultTimeout);
|
||||
if (ret.first == sys::ReturnCodes::Success) {
|
||||
if (auto resp = std::dynamic_pointer_cast<messages::Response>(ret.second)) {
|
||||
return *resp;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace app::whatsNew::models
|
||||
{
|
||||
WhatsNewModel::WhatsNewModel(app::ApplicationCommon *app) : app{app}
|
||||
{
|
||||
const auto version = getVersionNumber(VERSION);
|
||||
if (!version.has_value()) {
|
||||
return;
|
||||
}
|
||||
const auto result = sendDBRequest(app, std::make_shared<messages::GetByVersion>(version.value()));
|
||||
if (result.has_value()) {
|
||||
for (auto &record : result->records) {
|
||||
LOG_ERROR("*** changes: %s iconName: %s ***", record.description.c_str(), record.iconName.c_str());
|
||||
features.push_back({.description = record.description, .iconName = record.iconName});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace app::whatsNew::models
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace app
|
||||
{
|
||||
class ApplicationCommon;
|
||||
}
|
||||
|
||||
namespace app::whatsNew::models
|
||||
{
|
||||
struct Feature
|
||||
{
|
||||
const std::string description;
|
||||
const std::string iconName;
|
||||
};
|
||||
|
||||
class WhatsNewModel
|
||||
{
|
||||
public:
|
||||
explicit WhatsNewModel(app::ApplicationCommon *app);
|
||||
|
||||
private:
|
||||
app::ApplicationCommon *app{nullptr};
|
||||
std::vector<Feature> features;
|
||||
};
|
||||
} // namespace app::whatsNew::models
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#include "WhatsNewFeaturesPresenter.hpp"
|
||||
#include "WhatsNewFeaturesLayout.hpp"
|
||||
#include <product/version.hpp>
|
||||
|
||||
namespace app::whatsnew
|
||||
{
|
||||
WhatsNewFeaturesPresenter::WhatsNewFeaturesPresenter(std::unique_ptr<models::WhatsNewFeaturesModel> &&model)
|
||||
: model{std::move(model)}
|
||||
{
|
||||
createLayouts();
|
||||
}
|
||||
|
||||
auto WhatsNewFeaturesPresenter::getLayouts() const -> std::vector<gui::Item *>
|
||||
{
|
||||
return layouts;
|
||||
}
|
||||
|
||||
auto WhatsNewFeaturesPresenter::isLastLayout(const gui::Item *layout) const -> bool
|
||||
{
|
||||
return !layouts.empty() && (layouts.back() == layout);
|
||||
}
|
||||
|
||||
auto WhatsNewFeaturesPresenter::getFirstLayout() const -> gui::Item *
|
||||
{
|
||||
return layouts.empty() ? nullptr : layouts.front();
|
||||
}
|
||||
|
||||
auto WhatsNewFeaturesPresenter::createLayouts() -> void
|
||||
{
|
||||
const auto &features = model->getFeatures();
|
||||
layouts.reserve(features.size());
|
||||
|
||||
for (auto it = features.begin(); it != features.end(); ++it) {
|
||||
const auto isFirst = (it == features.begin());
|
||||
const auto isLast = (it == std::prev(features.end()));
|
||||
|
||||
auto layout = new gui::WhatsNewFeaturesLayout(it->title, it->description, it->iconName, !isFirst, !isLast);
|
||||
layouts.emplace_back(layout);
|
||||
}
|
||||
}
|
||||
|
||||
auto WhatsNewFeaturesPresenter::setCurrentOsVersion() -> void
|
||||
{
|
||||
model->setCurrentOsVersion(VERSION);
|
||||
}
|
||||
} // namespace app::whatsnew
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "WhatsNewFeaturesModel.hpp"
|
||||
#include <apps-common/BasePresenter.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace app
|
||||
{
|
||||
class ApplicationCommon;
|
||||
}
|
||||
|
||||
namespace gui
|
||||
{
|
||||
class Item;
|
||||
}
|
||||
|
||||
namespace app::whatsnew
|
||||
{
|
||||
class WhatsNewFeaturesContract
|
||||
{
|
||||
public:
|
||||
class View
|
||||
{
|
||||
public:
|
||||
virtual ~View() = default;
|
||||
};
|
||||
|
||||
class Presenter : public BasePresenter<WhatsNewFeaturesContract::View>
|
||||
{
|
||||
public:
|
||||
virtual ~Presenter() = default;
|
||||
|
||||
[[nodiscard]] virtual auto getLayouts() const -> std::vector<gui::Item *> = 0;
|
||||
[[nodiscard]] virtual auto isLastLayout(const gui::Item *layout) const -> bool = 0;
|
||||
[[nodiscard]] virtual auto getFirstLayout() const -> gui::Item * = 0;
|
||||
|
||||
virtual auto setCurrentOsVersion() -> void = 0;
|
||||
};
|
||||
};
|
||||
|
||||
class WhatsNewFeaturesPresenter : public WhatsNewFeaturesContract::Presenter
|
||||
{
|
||||
public:
|
||||
explicit WhatsNewFeaturesPresenter(std::unique_ptr<models::WhatsNewFeaturesModel> &&model);
|
||||
|
||||
[[nodiscard]] auto getLayouts() const -> std::vector<gui::Item *> override;
|
||||
[[nodiscard]] auto isLastLayout(const gui::Item *layout) const -> bool override;
|
||||
[[nodiscard]] auto getFirstLayout() const -> gui::Item * override;
|
||||
|
||||
auto setCurrentOsVersion() -> void override;
|
||||
|
||||
private:
|
||||
auto createLayouts() -> void;
|
||||
|
||||
std::vector<gui::Item *> layouts;
|
||||
std::unique_ptr<models::WhatsNewFeaturesModel> model;
|
||||
};
|
||||
} // namespace app::whatsnew
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#include "WhatsNewMainPresenter.hpp"
|
||||
#include <service-db/Settings.hpp>
|
||||
#include <service-db/agents/settings/SystemSettings.hpp>
|
||||
#include <product/version.hpp>
|
||||
|
||||
namespace app::whatsnew
|
||||
{
|
||||
WhatsNewMainPresenter::WhatsNewMainPresenter(settings::Settings *settings) : settings{settings}
|
||||
{}
|
||||
|
||||
auto WhatsNewMainPresenter::setCurrentOsVersion() -> void
|
||||
{
|
||||
settings->setValue(settings::SystemProperties::osCurrentVersion, VERSION, settings::SettingsScope::Global);
|
||||
}
|
||||
} // namespace app::whatsnew
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <apps-common/BasePresenter.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace settings
|
||||
{
|
||||
class Settings;
|
||||
}
|
||||
|
||||
namespace app::whatsnew
|
||||
{
|
||||
class WhatsNewMainContract
|
||||
{
|
||||
public:
|
||||
class View
|
||||
{
|
||||
public:
|
||||
virtual ~View() = default;
|
||||
};
|
||||
|
||||
class Presenter : public BasePresenter<WhatsNewMainContract::View>
|
||||
{
|
||||
public:
|
||||
virtual ~Presenter() = default;
|
||||
virtual auto setCurrentOsVersion() -> void = 0;
|
||||
};
|
||||
};
|
||||
|
||||
class WhatsNewMainPresenter : public WhatsNewMainContract::Presenter
|
||||
{
|
||||
public:
|
||||
explicit WhatsNewMainPresenter(settings::Settings *settings);
|
||||
auto setCurrentOsVersion() -> void override;
|
||||
|
||||
private:
|
||||
settings::Settings *settings{nullptr};
|
||||
};
|
||||
} // namespace app::whatsnew
|
||||
@@ -1,37 +0,0 @@
|
||||
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#include "WhatsNewPresenter.hpp"
|
||||
|
||||
namespace app::whatsNew
|
||||
{
|
||||
WhatsNewPresenter::WhatsNewPresenter(AbstractBatteryModel &batteryModel,
|
||||
AbstractLowBatteryInfoModel &lowBatteryInfoModel)
|
||||
: batteryModel{batteryModel}, lowBatteryInfoModel{lowBatteryInfoModel}
|
||||
{}
|
||||
|
||||
Store::Battery WhatsNewPresenter::getBatteryState()
|
||||
{
|
||||
return batteryModel.getLevelState();
|
||||
}
|
||||
|
||||
bool WhatsNewPresenter::isBatteryCharging(Store::Battery::State state) const
|
||||
{
|
||||
return batteryModel.isBatteryCharging(state);
|
||||
}
|
||||
|
||||
bool WhatsNewPresenter::isBatteryBelowLowLevelThreshold(units::SOC soc) const
|
||||
{
|
||||
return soc < constants::lowBatteryInfoThreshold;
|
||||
}
|
||||
|
||||
bool WhatsNewPresenter::isLowBatteryWindowHandled() const
|
||||
{
|
||||
return lowBatteryInfoModel.isInfoHandled();
|
||||
}
|
||||
|
||||
void WhatsNewPresenter::handleLowBatteryWindow()
|
||||
{
|
||||
lowBatteryInfoModel.handleInfo();
|
||||
}
|
||||
} // namespace app::whatsNew
|
||||
@@ -1,52 +0,0 @@
|
||||
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <apps-common/BasePresenter.hpp>
|
||||
#include <common/models/BatteryModel.hpp>
|
||||
#include <common/models/LowBatteryInfoModel.hpp>
|
||||
|
||||
namespace app
|
||||
{
|
||||
class ApplicationCommon;
|
||||
}
|
||||
|
||||
namespace app::whatsNew
|
||||
{
|
||||
class WhatsNewContract
|
||||
{
|
||||
public:
|
||||
class View
|
||||
{
|
||||
public:
|
||||
virtual ~View() = default;
|
||||
};
|
||||
|
||||
class Presenter : public BasePresenter<WhatsNewContract::View>
|
||||
{
|
||||
public:
|
||||
virtual ~Presenter() = default;
|
||||
virtual Store::Battery getBatteryState() = 0;
|
||||
virtual bool isBatteryCharging(Store::Battery::State state) const = 0;
|
||||
virtual bool isBatteryBelowLowLevelThreshold(units::SOC soc) const = 0;
|
||||
[[nodiscard]] virtual bool isLowBatteryWindowHandled() const = 0;
|
||||
virtual void handleLowBatteryWindow() = 0;
|
||||
};
|
||||
};
|
||||
|
||||
class WhatsNewPresenter : public WhatsNewContract::Presenter
|
||||
{
|
||||
AbstractBatteryModel &batteryModel;
|
||||
AbstractLowBatteryInfoModel &lowBatteryInfoModel;
|
||||
|
||||
Store::Battery getBatteryState() override;
|
||||
[[nodiscard]] bool isBatteryCharging(Store::Battery::State state) const override;
|
||||
[[nodiscard]] bool isBatteryBelowLowLevelThreshold(units::SOC soc) const override;
|
||||
[[nodiscard]] bool isLowBatteryWindowHandled() const override;
|
||||
void handleLowBatteryWindow() override;
|
||||
|
||||
public:
|
||||
WhatsNewPresenter(AbstractBatteryModel &batteryModel, AbstractLowBatteryInfoModel &lowBatteryInfoModel);
|
||||
};
|
||||
} // namespace app::whatsNew
|
||||
@@ -0,0 +1,111 @@
|
||||
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#include "WhatsNewFeaturesLayout.hpp"
|
||||
#include "WhatsNewStyle.hpp"
|
||||
#include <TextFixedSize.hpp>
|
||||
|
||||
namespace gui
|
||||
{
|
||||
WhatsNewFeaturesLayout::WhatsNewFeaturesLayout(const std::string &title,
|
||||
const std::string &description,
|
||||
const std::string &iconName,
|
||||
bool leftArrowState,
|
||||
bool rightArrowState)
|
||||
: VBox(nullptr,
|
||||
0,
|
||||
0,
|
||||
whats_new_style::features_window::layout::width,
|
||||
whats_new_style::features_window::layout::height)
|
||||
{
|
||||
buildInterface(title, description, iconName, leftArrowState, rightArrowState);
|
||||
}
|
||||
|
||||
auto WhatsNewFeaturesLayout::buildInterface(const std::string &title,
|
||||
const std::string &description,
|
||||
const std::string &iconName,
|
||||
bool leftArrowState,
|
||||
bool rightArrowState) -> void
|
||||
{
|
||||
setAlignment(Alignment::Horizontal::Center);
|
||||
setEdges(rectangle_enums::RectangleEdge::None);
|
||||
|
||||
/* Main container */
|
||||
auto mainContainer = new HThreeBox<HBox, VBox, HBox>(this);
|
||||
mainContainer->setMinimumSize(whats_new_style::features_window::container::width,
|
||||
whats_new_style::features_window::container::height);
|
||||
mainContainer->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Center));
|
||||
mainContainer->setMargins(Margins(0, whats_new_style::features_window::container::margin_top, 0, 0));
|
||||
mainContainer->setEdges(RectangleEdge::None);
|
||||
|
||||
/* Left box - with arrow */
|
||||
mainContainer->firstBox = new HBox(mainContainer);
|
||||
mainContainer->firstBox->setAlignment(Alignment(Alignment::Vertical::Center));
|
||||
mainContainer->firstBox->setEdges(RectangleEdge::None);
|
||||
mainContainer->firstBox->activeItem = false;
|
||||
|
||||
auto leftArrow = new ImageBox(nullptr, new Image("bell_arrow_left_W_M"));
|
||||
leftArrow->setAlignment(Alignment(Alignment::Horizontal::Right, Alignment::Vertical::Center));
|
||||
leftArrow->setMinimumSizeToFitImage();
|
||||
leftArrow->setVisible(leftArrowState);
|
||||
leftArrow->setEdges(RectangleEdge::None);
|
||||
mainContainer->firstBox->setMinimumSize(leftArrow->widgetMinimumArea.w, leftArrow->widgetMinimumArea.h);
|
||||
mainContainer->firstBox->addWidget(leftArrow);
|
||||
|
||||
/* Center box - icon, title and description */
|
||||
mainContainer->centerBox = new VBox(mainContainer);
|
||||
mainContainer->centerBox->setEdges(RectangleEdge::None);
|
||||
mainContainer->centerBox->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Top));
|
||||
mainContainer->centerBox->setMinimumSize(whats_new_style::features_window::center_box::width,
|
||||
whats_new_style::features_window::center_box::height);
|
||||
mainContainer->centerBox->setMaximumSize(whats_new_style::features_window::center_box::width,
|
||||
whats_new_style::features_window::center_box::height);
|
||||
|
||||
auto iconImage = new ImageBox(nullptr, new Image(iconName));
|
||||
iconImage->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Top));
|
||||
iconImage->setMinimumSizeToFitImage();
|
||||
iconImage->setMaximumSize(whats_new_style::features_window::icon::width,
|
||||
whats_new_style::features_window::icon::height);
|
||||
|
||||
auto titleText = new Text(nullptr,
|
||||
0,
|
||||
0,
|
||||
whats_new_style::features_window::title::width,
|
||||
whats_new_style::features_window::title::height);
|
||||
titleText->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Top));
|
||||
titleText->setMargins(Margins(0, whats_new_style::features_window::title::margin_top, 0, 0));
|
||||
titleText->setTextType(TextType::SingleLine);
|
||||
titleText->setFont(whats_new_style::features_window::title::font);
|
||||
titleText->setText(title);
|
||||
|
||||
auto descriptionText = new Text(nullptr,
|
||||
0,
|
||||
0,
|
||||
whats_new_style::features_window::description::width,
|
||||
whats_new_style::features_window::description::height);
|
||||
descriptionText->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Top));
|
||||
descriptionText->setMargins(Margins(0, whats_new_style::features_window::description::margin_top, 0, 0));
|
||||
descriptionText->setFont(whats_new_style::features_window::description::font);
|
||||
descriptionText->setText(description);
|
||||
|
||||
mainContainer->centerBox->addWidget(iconImage);
|
||||
mainContainer->centerBox->addWidget(titleText);
|
||||
mainContainer->centerBox->addWidget(descriptionText);
|
||||
|
||||
/* Right box */
|
||||
mainContainer->lastBox = new HBox(mainContainer);
|
||||
mainContainer->lastBox->setAlignment(Alignment(Alignment::Vertical::Center));
|
||||
mainContainer->lastBox->setEdges(RectangleEdge::None);
|
||||
mainContainer->lastBox->activeItem = false;
|
||||
|
||||
auto rightArrow = new ImageBox(nullptr, new Image("bell_arrow_right_W_M"));
|
||||
rightArrow->setAlignment(Alignment(Alignment::Horizontal::Left, Alignment::Vertical::Center));
|
||||
rightArrow->setMinimumSizeToFitImage();
|
||||
rightArrow->setVisible(rightArrowState);
|
||||
rightArrow->setEdges(RectangleEdge::None);
|
||||
mainContainer->lastBox->setMinimumSize(rightArrow->widgetMinimumArea.w, rightArrow->widgetMinimumArea.h);
|
||||
mainContainer->lastBox->addWidget(rightArrow);
|
||||
|
||||
resizeItems();
|
||||
}
|
||||
} // namespace gui
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ThreeBox.hpp>
|
||||
|
||||
namespace gui
|
||||
{
|
||||
class WhatsNewFeaturesLayout : public VBox
|
||||
{
|
||||
public:
|
||||
WhatsNewFeaturesLayout(const std::string &title,
|
||||
const std::string &description,
|
||||
const std::string &iconName,
|
||||
bool leftArrowState = true,
|
||||
bool rightArrowState = true);
|
||||
|
||||
private:
|
||||
auto buildInterface(const std::string &title,
|
||||
const std::string &description,
|
||||
const std::string &iconName,
|
||||
bool leftArrowState,
|
||||
bool rightArrowState) -> void;
|
||||
};
|
||||
} // namespace gui
|
||||
@@ -0,0 +1,85 @@
|
||||
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#include "WhatsNewFeaturesWindow.hpp"
|
||||
|
||||
#include <SideListView.hpp>
|
||||
#include <common/options/OptionBellMenu.hpp>
|
||||
#include <common/data/BatteryStatusSwitchData.hpp>
|
||||
#include <common/windows/BellFinishedWindow.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr auto endWindowTimeout = std::chrono::seconds{5};
|
||||
}
|
||||
|
||||
namespace app::whatsnew
|
||||
{
|
||||
using namespace gui;
|
||||
|
||||
WhatsNewFeaturesWindow::WhatsNewFeaturesWindow(app::ApplicationCommon *app,
|
||||
std::unique_ptr<WhatsNewFeaturesContract::Presenter> &&presenter,
|
||||
const std::string &name)
|
||||
: AppWindow(app, name), presenter{std::move(presenter)}
|
||||
{
|
||||
buildInterface();
|
||||
}
|
||||
|
||||
auto WhatsNewFeaturesWindow::buildInterface() -> void
|
||||
{
|
||||
AppWindow::buildInterface();
|
||||
|
||||
statusBar->setVisible(false);
|
||||
header->setTitleVisibility(false);
|
||||
navBar->setVisible(false);
|
||||
|
||||
layouts = presenter->getLayouts();
|
||||
|
||||
itemSpinner = new WidgetSpinner(this, {layouts.begin(), layouts.end()}, Boundaries::Fixed);
|
||||
itemSpinner->setSize(style::window_width, style::window_height);
|
||||
itemSpinner->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Center));
|
||||
itemSpinner->setFocusEdges(RectangleEdge::None);
|
||||
itemSpinner->setCurrentValue(presenter->getFirstLayout());
|
||||
|
||||
itemSpinner->onValueChanged = [this]([[maybe_unused]] const auto &value) {
|
||||
getApplication()->render(gui::RefreshModes::GUI_REFRESH_DEEP);
|
||||
};
|
||||
|
||||
setFocusItem(itemSpinner);
|
||||
}
|
||||
|
||||
auto WhatsNewFeaturesWindow::onInput(const gui::InputEvent &inputEvent) -> bool
|
||||
{
|
||||
/* Prevent leaving by long-pressing back */
|
||||
if (inputEvent.isLongRelease(gui::KeyCode::KEY_RF)) {
|
||||
return true;
|
||||
}
|
||||
if (inputEvent.isShortRelease(gui::KeyCode::KEY_RF) ||
|
||||
(inputEvent.isShortRelease(gui::KeyCode::KEY_ENTER) && isLastLayout())) {
|
||||
presenter->setCurrentOsVersion();
|
||||
switchToEndWindow();
|
||||
return true;
|
||||
}
|
||||
if (itemSpinner->onInput(inputEvent)) {
|
||||
return true;
|
||||
}
|
||||
return AppWindow::onInput(inputEvent);
|
||||
}
|
||||
|
||||
auto WhatsNewFeaturesWindow::isLastLayout() -> bool
|
||||
{
|
||||
return itemSpinner->getCurrentValue() == layouts.back();
|
||||
}
|
||||
|
||||
auto WhatsNewFeaturesWindow::switchToEndWindow() -> void
|
||||
{
|
||||
using ExitBehaviour = gui::BellFinishedWindowData::ExitBehaviour;
|
||||
application->switchWindow(
|
||||
gui::window::bell_finished::defaultName,
|
||||
gui::BellFinishedWindowData::Factory::create("big_namaste_W_G",
|
||||
"",
|
||||
utils::translate("app_bell_whatsnew_end_screen_text"),
|
||||
ExitBehaviour::ReturnToHomescreen,
|
||||
endWindowTimeout));
|
||||
}
|
||||
} // namespace app::whatsnew
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "WhatsNewCommon.hpp"
|
||||
#include <presenter/WhatsNewFeaturesPresenter.hpp>
|
||||
#include <apps-common/windows/AppWindow.hpp>
|
||||
#include <widgets/spinners/Spinners.hpp>
|
||||
|
||||
namespace app::whatsnew
|
||||
{
|
||||
class WhatsNewFeaturesWindow : public gui::AppWindow, public WhatsNewFeaturesContract::View
|
||||
{
|
||||
public:
|
||||
WhatsNewFeaturesWindow(app::ApplicationCommon *app,
|
||||
std::unique_ptr<WhatsNewFeaturesContract::Presenter> &&presenter,
|
||||
const std::string &name = window::name::features);
|
||||
|
||||
auto buildInterface() -> void override;
|
||||
auto onInput(const gui::InputEvent &inputEvent) -> bool override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<WhatsNewFeaturesContract::Presenter> presenter;
|
||||
gui::WidgetSpinner *itemSpinner{nullptr};
|
||||
std::vector<gui::Item *> layouts;
|
||||
|
||||
auto isLastLayout() -> bool;
|
||||
auto switchToEndWindow() -> void;
|
||||
};
|
||||
} // namespace app::whatsnew
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#include "WhatsNewMainWindow.hpp"
|
||||
#include "WhatsNewStyle.hpp"
|
||||
#include <common/options/OptionBellMenu.hpp>
|
||||
#include <service-appmgr/Controller.hpp>
|
||||
#include <product/version.hpp>
|
||||
|
||||
namespace app::whatsnew
|
||||
{
|
||||
using namespace gui;
|
||||
|
||||
WhatsNewMainWindow::WhatsNewMainWindow(app::ApplicationCommon *app,
|
||||
std::unique_ptr<WhatsNewMainContract::Presenter> &&presenter,
|
||||
const std::string &name)
|
||||
: BellOptionWithDescriptionWindow(app, name), presenter{std::move(presenter)}
|
||||
{
|
||||
addOptions(settingsOptionsList());
|
||||
setListTitle(utils::translate("app_bell_whatsnew_title"), whats_new_style::main_window::list_title_font);
|
||||
setListDescription(utils::translate("app_bell_whatsnew_version"),
|
||||
gui::BellOptionWithDescriptionWindow::TokenMap({{"$VERSION", std::string(VERSION)}}),
|
||||
whats_new_style::main_window::description_font,
|
||||
whats_new_style::main_window::description_height);
|
||||
}
|
||||
|
||||
auto WhatsNewMainWindow::settingsOptionsList() -> std::list<Option>
|
||||
{
|
||||
std::list<Option> settingsOptionList;
|
||||
|
||||
auto addWinSettings = [&](const UTF8 &name, const std::function<bool(Item &)> &activatedCallback) {
|
||||
settingsOptionList.emplace_back(std::make_unique<option::OptionBellMenu>(
|
||||
name, activatedCallback, []([[maybe_unused]] Item &item) { return true; }, this));
|
||||
};
|
||||
|
||||
addWinSettings(utils::translate("app_bell_whatsnew_continue"), [this]([[maybe_unused]] Item &item) {
|
||||
application->switchWindow(window::name::features);
|
||||
return true;
|
||||
});
|
||||
addWinSettings(utils::translate("app_bell_whatsnew_skip"), [this]([[maybe_unused]] Item &item) {
|
||||
presenter->setCurrentOsVersion();
|
||||
app::manager::Controller::sendAction(application, app::manager::actions::Home);
|
||||
return true;
|
||||
});
|
||||
|
||||
return settingsOptionList;
|
||||
}
|
||||
|
||||
auto WhatsNewMainWindow::onBeforeShow([[maybe_unused]] ShowMode mode, [[maybe_unused]] SwitchData *data) -> void
|
||||
{}
|
||||
} // namespace app::whatsnew
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "WhatsNewCommon.hpp"
|
||||
#include "WhatsNewMainPresenter.hpp"
|
||||
#include <common/options/BellOptionWithDescriptionWindow.hpp>
|
||||
|
||||
namespace app::whatsnew
|
||||
{
|
||||
using namespace gui;
|
||||
|
||||
class WhatsNewMainWindow : public BellOptionWithDescriptionWindow
|
||||
{
|
||||
public:
|
||||
WhatsNewMainWindow(app::ApplicationCommon *app,
|
||||
std::unique_ptr<WhatsNewMainContract::Presenter> &&presenter,
|
||||
const std::string &name = window::name::main);
|
||||
auto onBeforeShow(ShowMode mode, SwitchData *data) -> void override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<WhatsNewMainContract::Presenter> presenter;
|
||||
|
||||
auto settingsOptionsList() -> std::list<Option>;
|
||||
};
|
||||
} // namespace app::whatsnew
|
||||
@@ -1,35 +0,0 @@
|
||||
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#include "WhatsNewWindow.hpp"
|
||||
|
||||
#include <common/options/OptionBellMenu.hpp>
|
||||
#include <common/data/BatteryStatusSwitchData.hpp>
|
||||
|
||||
namespace app::whatsNew
|
||||
{
|
||||
using namespace gui;
|
||||
|
||||
WhatsNewWindow::WhatsNewWindow(app::ApplicationCommon *app,
|
||||
std::unique_ptr<WhatsNewContract::Presenter> &&presenter,
|
||||
const std::string &name)
|
||||
: AppWindow(app, name), presenter{std::move(presenter)}
|
||||
{
|
||||
buildInterface();
|
||||
}
|
||||
|
||||
void WhatsNewWindow::buildInterface()
|
||||
{
|
||||
AppWindow::buildInterface();
|
||||
}
|
||||
|
||||
void WhatsNewWindow::onBeforeShow(gui::ShowMode mode, gui::SwitchData *data)
|
||||
{
|
||||
AppWindow::onBeforeShow(mode, data);
|
||||
}
|
||||
|
||||
bool WhatsNewWindow::onInput(const gui::InputEvent &inputEvent)
|
||||
{
|
||||
return AppWindow::onInput(inputEvent);
|
||||
}
|
||||
} // namespace app::whatsNew
|
||||
@@ -1,29 +0,0 @@
|
||||
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "WhatsNewCommon.hpp"
|
||||
#include <presenter/WhatsNewPresenter.hpp>
|
||||
|
||||
#include <apps-common/windows/AppWindow.hpp>
|
||||
|
||||
namespace app::whatsNew
|
||||
{
|
||||
using namespace gui;
|
||||
|
||||
class WhatsNewWindow : public gui::AppWindow, public WhatsNewContract::View
|
||||
{
|
||||
public:
|
||||
WhatsNewWindow(app::ApplicationCommon *app,
|
||||
std::unique_ptr<WhatsNewContract::Presenter> &&presenter,
|
||||
const std::string &name = window::name::main);
|
||||
|
||||
void buildInterface() override;
|
||||
void onBeforeShow(gui::ShowMode mode, gui::SwitchData *data) override;
|
||||
bool onInput(const gui::InputEvent &inputEvent) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<WhatsNewContract::Presenter> presenter;
|
||||
};
|
||||
} // namespace app::whatsNew
|
||||
@@ -10,8 +10,6 @@
|
||||
|
||||
namespace gui
|
||||
{
|
||||
class BellBaseLayout;
|
||||
|
||||
using Instruction = std::vector<std::pair<std::string, UTF8>>;
|
||||
|
||||
class UpdateInstructionLayoutClassic : public UpdateInstructionLayoutProvider, VBox
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
|
||||
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
||||
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
||||
|
||||
#pragma once
|
||||
@@ -12,17 +12,23 @@ namespace gui
|
||||
{
|
||||
class BellOptionWithDescriptionWindow : public AppWindow, protected OptionsList<ListView>
|
||||
{
|
||||
protected:
|
||||
BellBaseLayout *body{};
|
||||
|
||||
public:
|
||||
using TokenMap = std::optional<text::RichTextParser::TokenMap>;
|
||||
static constexpr auto defaultDescriptionHeight = 175U;
|
||||
|
||||
BellOptionWithDescriptionWindow(app::ApplicationCommon *app, const std::string &name);
|
||||
void setListTitle(const std::string &title);
|
||||
void setListDescription(const std::string &title);
|
||||
void setListTitle(const std::string &title, const std::string &font = style::window::font::largelight);
|
||||
void setListDescription(const std::string &title,
|
||||
TokenMap tokenMap = {},
|
||||
const std::string &font = style::window::font::verybiglight,
|
||||
unsigned height = defaultDescriptionHeight);
|
||||
|
||||
void onBeforeShow(ShowMode mode, SwitchData *data) override;
|
||||
void onClose(CloseReason reason) override;
|
||||
void rebuild() override;
|
||||
void buildInterface() override;
|
||||
|
||||
protected:
|
||||
BellBaseLayout *body{nullptr};
|
||||
};
|
||||
}; // namespace gui
|
||||
|
||||
@@ -10,23 +10,19 @@
|
||||
|
||||
namespace gui
|
||||
{
|
||||
class SideListView;
|
||||
class UpdateInstructionWindow : public AppWindow, public UpdateInstructionWindowContract::View
|
||||
{
|
||||
std::unique_ptr<UpdateInstructionWindowContract::Presenter> presenter;
|
||||
SideListView *sideListView = nullptr;
|
||||
WidgetSpinner *spinner = nullptr;
|
||||
|
||||
bool onInput(const gui::InputEvent &inputEvent) override;
|
||||
void buildInterface() override;
|
||||
|
||||
void onValueChanged(const std::uint32_t currentValue);
|
||||
|
||||
public:
|
||||
UpdateInstructionWindow(app::ApplicationCommon *app,
|
||||
std::unique_ptr<UpdateInstructionWindowContract::Presenter> &&presenter,
|
||||
const std::string &name);
|
||||
|
||||
bool isLastLayout() const;
|
||||
[[nodiscard]] bool isLastLayout() const;
|
||||
};
|
||||
} // namespace gui
|
||||
|
||||
@@ -148,5 +148,4 @@ namespace gui
|
||||
connectionBox->setVisible(connectionStatus->isVisible());
|
||||
widgetBox->informContentChanged();
|
||||
}
|
||||
|
||||
}; // namespace gui
|
||||
} // namespace gui
|
||||
|
||||
@@ -14,8 +14,7 @@ namespace gui
|
||||
{
|
||||
constexpr auto one_option_height = style::bell_options::h + 2U * style::bell_options::option_margin;
|
||||
constexpr auto option_layout_height = 2U * one_option_height;
|
||||
constexpr auto description_height = 175U;
|
||||
constexpr auto max_description_height = description_height + 16U;
|
||||
constexpr auto max_to_min_difference = 16U;
|
||||
constexpr auto top_center_margin = -14;
|
||||
} // namespace
|
||||
|
||||
@@ -62,12 +61,12 @@ namespace gui
|
||||
setFocusItem(optionsList);
|
||||
}
|
||||
|
||||
void BellOptionWithDescriptionWindow::setListTitle(const std::string &title)
|
||||
void BellOptionWithDescriptionWindow::setListTitle(const std::string &title, const std::string &font)
|
||||
{
|
||||
auto titleBody = new TextFixedSize(body->firstBox);
|
||||
titleBody->drawUnderline(false);
|
||||
titleBody->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Top));
|
||||
titleBody->setFont(style::window::font::largelight);
|
||||
titleBody->setFont(font);
|
||||
titleBody->setMinimumWidth(style::bell_base_layout::outer_layouts_w);
|
||||
titleBody->setEdges(RectangleEdge::None);
|
||||
titleBody->setEditMode(EditMode::Browse);
|
||||
@@ -80,19 +79,27 @@ namespace gui
|
||||
body->resizeItems();
|
||||
}
|
||||
|
||||
void BellOptionWithDescriptionWindow::setListDescription(const std::string &title)
|
||||
void BellOptionWithDescriptionWindow::setListDescription(const std::string &title,
|
||||
TokenMap tokenMap,
|
||||
const std::string &font,
|
||||
const unsigned height)
|
||||
{
|
||||
auto descriptionBody = new TextFixedSize(body->centerBox);
|
||||
descriptionBody->drawUnderline(false);
|
||||
descriptionBody->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Center));
|
||||
descriptionBody->setFont(style::window::font::verybiglight);
|
||||
descriptionBody->setMinimumSize(style::window_width, description_height);
|
||||
descriptionBody->setFont(font);
|
||||
descriptionBody->setMinimumSize(style::window_width, height);
|
||||
descriptionBody->setEditMode(EditMode::Browse);
|
||||
descriptionBody->setRichText(title);
|
||||
if (tokenMap.has_value()) {
|
||||
descriptionBody->setRichText(title, std::move(tokenMap.value()));
|
||||
}
|
||||
else {
|
||||
descriptionBody->setText(title);
|
||||
}
|
||||
|
||||
body->centerBox->setMargins(gui::Margins{0, top_center_margin, 0, 0});
|
||||
body->centerBox->setMaximumHeight(max_description_height);
|
||||
body->centerBox->setMinimumHeight(description_height);
|
||||
body->centerBox->setMaximumHeight(height + max_to_min_difference);
|
||||
body->centerBox->setMinimumHeight(height);
|
||||
body->centerBox->resizeItems();
|
||||
body->resizeItems();
|
||||
}
|
||||
|
||||
@@ -127,9 +127,8 @@ namespace app::manager
|
||||
|
||||
auto ApplicationManager::isWhatsNewAvailable() -> bool
|
||||
{
|
||||
const auto lastVersionNumber =
|
||||
const auto &lastVersionNumber =
|
||||
settings->getValue(settings::SystemProperties::osCurrentVersion, settings::SettingsScope::Global);
|
||||
return lastVersionNumber != VERSION;
|
||||
}
|
||||
|
||||
} // namespace app::manager
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace
|
||||
constexpr auto multimediaDatabaseName{"multimedia.db"};
|
||||
constexpr auto settingsDatabaseName{"settings_bell.db"};
|
||||
constexpr auto meditationStatsDatabaseName{"meditation_stats.db"};
|
||||
constexpr auto whatsNewDatabaseName{"whats-new.db"};
|
||||
constexpr auto whatsNewDatabaseName{"whats_new.db"};
|
||||
} // namespace
|
||||
|
||||
ServiceDB::~ServiceDB()
|
||||
|
||||
@@ -14,14 +14,15 @@
|
||||
namespace
|
||||
{
|
||||
using namespace std::chrono;
|
||||
static constexpr auto zeroOffset = 0;
|
||||
static constexpr auto maxLimit = std::numeric_limits<unsigned>::max();
|
||||
static constexpr auto dayInSec = duration_cast<seconds>(24h).count();
|
||||
|
||||
constexpr auto zeroOffset = 0;
|
||||
constexpr auto maxLimit = std::numeric_limits<unsigned>::max();
|
||||
constexpr auto dayInSec = duration_cast<seconds>(24h).count();
|
||||
|
||||
bool hasCrossedMidnight(std::time_t current, std::time_t last)
|
||||
{
|
||||
const std::tm lastTime = *std::localtime(&last);
|
||||
const std::tm currentTime = *std::localtime(¤t);
|
||||
const auto lastTime = *std::localtime(&last);
|
||||
const auto currentTime = *std::localtime(¤t);
|
||||
if (currentTime.tm_mday != lastTime.tm_mday) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4,27 +4,43 @@
|
||||
#include "WhatsNewAgent.hpp"
|
||||
#include "db/WhatsNewMessages.hpp"
|
||||
|
||||
#include <i18n/i18n.hpp>
|
||||
#include <Service/Service.hpp>
|
||||
#include <purefs/filesystem_paths.hpp>
|
||||
#include <i18n/i18n.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace service::db::whatsNew;
|
||||
using namespace service::db::whatsnew;
|
||||
|
||||
constexpr auto query = "SELECT %s, Icon FROM WhatsNew WHERE Major > %d OR (Major = %d AND Minor > %d) OR (Major = "
|
||||
"%d AND Minor = %d AND Patch > %d)";
|
||||
|
||||
std::vector<Record> getRecordsByVersion(Database *db, VersionNumber version)
|
||||
inline std::string createTitleColumnName(const std::string &language)
|
||||
{
|
||||
const auto retQuery = db->query(query,
|
||||
utils::getDisplayLanguage().c_str(),
|
||||
version.major,
|
||||
version.major,
|
||||
version.minor,
|
||||
version.major,
|
||||
version.minor,
|
||||
version.patch);
|
||||
constexpr auto titleSuffix = "_title";
|
||||
return language + titleSuffix;
|
||||
}
|
||||
|
||||
inline std::string createDescriptionColumnName(const std::string &language)
|
||||
{
|
||||
constexpr auto descriptionSuffix = "_desc";
|
||||
return language + descriptionSuffix;
|
||||
}
|
||||
|
||||
std::vector<Record> getRecordsByVersion(Database &db, const VersionNumber &version)
|
||||
{
|
||||
constexpr auto query = "SELECT %s, %s, Icon FROM whats_new "
|
||||
"WHERE Major > %u OR "
|
||||
"(Major = %u AND Minor > %u) OR "
|
||||
"(Major = %u AND Minor = %u AND Patch > %u) "
|
||||
"ORDER BY Major ASC, Minor ASC, Patch ASC;";
|
||||
|
||||
const auto retQuery = db.query(query,
|
||||
createTitleColumnName(utils::getDisplayLanguage()).c_str(),
|
||||
createDescriptionColumnName(utils::getDisplayLanguage()).c_str(),
|
||||
version.major,
|
||||
version.major,
|
||||
version.minor,
|
||||
version.major,
|
||||
version.minor,
|
||||
version.patch);
|
||||
|
||||
if ((retQuery == nullptr) || (retQuery->getRowCount() == 0)) {
|
||||
return {};
|
||||
@@ -34,7 +50,7 @@ namespace
|
||||
ret.reserve(retQuery->getRowCount());
|
||||
|
||||
do {
|
||||
ret.push_back({.description{(*retQuery)[0].getString()}, .iconName{(*retQuery)[1].getString()}});
|
||||
ret.push_back(Record{(*retQuery)[0].getString(), (*retQuery)[1].getString(), (*retQuery)[2].getString()});
|
||||
} while (retQuery->nextRow());
|
||||
|
||||
return ret;
|
||||
@@ -43,19 +59,19 @@ namespace
|
||||
|
||||
namespace service::db::agents
|
||||
{
|
||||
WhatsNew::WhatsNew(sys::Service *parentService, const std::string dbName)
|
||||
WhatsNew::WhatsNew(sys::Service *parentService, const std::string &dbName)
|
||||
: DatabaseAgent{parentService}, dbName{dbName}, db{(purefs::dir::getDatabasesPath() / dbName).c_str()}
|
||||
{}
|
||||
|
||||
void WhatsNew::registerMessages()
|
||||
{
|
||||
parentService->connect(whatsNew::messages::GetByVersion({}),
|
||||
parentService->connect(whatsnew::messages::GetByVersion({}),
|
||||
[this](const auto &req) { return handleGetRecordsByVersion(req); });
|
||||
}
|
||||
|
||||
void WhatsNew::unRegisterMessages()
|
||||
{
|
||||
parentService->disconnect(typeid(whatsNew::messages::GetByVersion));
|
||||
parentService->disconnect(typeid(whatsnew::messages::GetByVersion));
|
||||
}
|
||||
|
||||
auto WhatsNew::getAgentName() -> const std::string
|
||||
@@ -65,10 +81,10 @@ namespace service::db::agents
|
||||
|
||||
sys::MessagePointer WhatsNew::handleGetRecordsByVersion(const sys::Message *req)
|
||||
{
|
||||
if (auto msg = dynamic_cast<const whatsNew::messages::GetByVersion *>(req)) {
|
||||
const auto records = getRecordsByVersion(&db, msg->version);
|
||||
return std::make_shared<whatsNew::messages::Response>(records);
|
||||
if (const auto msg = dynamic_cast<const whatsnew::messages::GetByVersion *>(req)) {
|
||||
const auto &records = getRecordsByVersion(db, msg->version);
|
||||
return std::make_shared<whatsnew::messages::Response>(records);
|
||||
}
|
||||
return std::make_shared<sys::ResponseMessage>();
|
||||
}
|
||||
} // namespace service::db::agents
|
||||
} // namespace service::db::agents
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace service::db::agents
|
||||
class WhatsNew : public DatabaseAgent
|
||||
{
|
||||
public:
|
||||
WhatsNew(sys::Service *parentService, std::string dbName);
|
||||
WhatsNew(sys::Service *parentService, const std::string &dbName);
|
||||
|
||||
void registerMessages() override;
|
||||
void unRegisterMessages() override;
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
#include <Service/Message.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace service::db::whatsNew
|
||||
namespace service::db::whatsnew
|
||||
{
|
||||
struct Record
|
||||
{
|
||||
std::string title;
|
||||
std::string description;
|
||||
std::string iconName;
|
||||
};
|
||||
@@ -39,6 +40,5 @@ namespace service::db::whatsNew
|
||||
|
||||
std::vector<Record> records{};
|
||||
};
|
||||
|
||||
} // namespace messages
|
||||
} // namespace service::db::whatsNew
|
||||
} // namespace service::db::whatsnew
|
||||
|
||||
Reference in New Issue
Block a user