From 06de0dd9db3b89ba65da0b58e2bcabe0eb315deb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Tue, 16 May 2017 17:02:06 +0200 Subject: [PATCH] [escher] Only one app is on the heap at one time Change-Id: I6c77601cb0cc883083a4dd05370ca543fa7951cc --- apps/apps_container.cpp | 158 ++++++++---------------- apps/apps_container.h | 23 ++-- apps/calculation/app.cpp | 27 +++- apps/calculation/app.h | 10 +- apps/graph/app.cpp | 27 +++- apps/graph/app.h | 10 +- apps/hardware_test/app.cpp | 12 +- apps/hardware_test/app.h | 9 +- apps/hardware_test/color_controller.cpp | 2 +- apps/home/app.cpp | 22 +++- apps/home/app.h | 9 +- apps/home/app_cell.cpp | 6 +- apps/home/app_cell.h | 2 +- apps/home/controller.cpp | 6 +- apps/main.cpp | 2 +- apps/on_boarding/app.cpp | 15 ++- apps/on_boarding/app.h | 7 +- apps/on_boarding/update_controller.cpp | 4 +- apps/probability/app.cpp | 24 +++- apps/probability/app.h | 10 +- apps/regression/app.cpp | 24 +++- apps/regression/app.h | 10 +- apps/sequence/app.cpp | 27 +++- apps/sequence/app.h | 10 +- apps/settings/app.cpp | 24 +++- apps/settings/app.h | 10 +- apps/settings/sub_controller.cpp | 2 +- apps/shared/function_app.cpp | 4 +- apps/shared/function_app.h | 2 +- apps/shared/text_field_delegate_app.cpp | 4 +- apps/shared/text_field_delegate_app.h | 2 +- apps/statistics/app.cpp | 24 +++- apps/statistics/app.h | 10 +- escher/include/escher/app.h | 23 ++-- escher/include/escher/container.h | 7 +- escher/src/app.cpp | 36 +++--- escher/src/container.cpp | 14 ++- escher/src/window.cpp | 8 +- 38 files changed, 414 insertions(+), 212 deletions(-) diff --git a/apps/apps_container.cpp b/apps/apps_container.cpp index b554107a5..510cab5e7 100644 --- a/apps/apps_container.cpp +++ b/apps/apps_container.cpp @@ -20,44 +20,27 @@ AppsContainer::AppsContainer() : m_batteryTimer(BatteryTimer(this)), m_USBTimer(USBTimer(this)), m_suspendTimer(SuspendTimer(this)), - m_backlightDimmingTimer(BacklightDimmingTimer()), - m_onBoardingApp(new OnBoarding::App(this, &m_updateController)), - m_homeApp(new Home::App(this)), - m_graphApp(new Graph::App(this, &m_globalContext)), - m_probabilityApp(new Probability::App(this)), - m_calculationApp(new Calculation::App(this, &m_globalContext)), - m_hardwareTestApp(new HardwareTest::App(this)), - m_regressionApp(new Regression::App(this)), - m_sequenceApp(new Sequence::App(this, &m_globalContext)), - m_settingsApp(new Settings::App(this)), - m_statisticsApp(new Statistics::App(this)) + m_backlightDimmingTimer(BacklightDimmingTimer()) { + m_descriptors[0] = Home::App::buildDescriptor(); + m_descriptors[1] = Calculation::App::buildDescriptor(); + m_descriptors[2] = Graph::App::buildDescriptor(); + m_descriptors[3] = Sequence::App::buildDescriptor(); + m_descriptors[4] = Settings::App::buildDescriptor(); + m_descriptors[5] = Statistics::App::buildDescriptor(); + m_descriptors[6] = Probability::App::buildDescriptor(); + m_descriptors[7] = Regression::App::buildDescriptor(); + m_descriptors[8] = OnBoarding::App::buildDescriptor(); + m_descriptors[9] = HardwareTest::App::buildDescriptor(); refreshPreferences(); m_emptyBatteryWindow.setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height)); Poincare::Expression::setCircuitBreaker(AppsContainer::poincareCircuitBreaker); } AppsContainer::~AppsContainer() { - delete m_onBoardingApp; - m_onBoardingApp = nullptr; - delete m_homeApp; - m_homeApp = nullptr; - delete m_graphApp; - m_graphApp = nullptr; - delete m_probabilityApp; - m_probabilityApp = nullptr; - delete m_calculationApp; - m_calculationApp = nullptr; - delete m_hardwareTestApp; - m_hardwareTestApp = nullptr; - delete m_regressionApp; - m_regressionApp = nullptr; - delete m_sequenceApp; - m_sequenceApp = nullptr; - delete m_settingsApp; - m_settingsApp = nullptr; - delete m_statisticsApp; - m_statisticsApp = nullptr; + for (int i = 0; i < k_totalNumberOfApps; i++) { + delete m_descriptors[i]; + } } bool AppsContainer::poincareCircuitBreaker(const Poincare::Expression * e) { @@ -66,58 +49,25 @@ bool AppsContainer::poincareCircuitBreaker(const Poincare::Expression * e) { } int AppsContainer::numberOfApps() { - return k_numberOfApps; + return k_numberOfCommonApps; } -App * AppsContainer::appAtIndex(int index) { - if (index == -1) { - return m_onBoardingApp; - } - App * apps[] = { - m_homeApp, - m_calculationApp, - m_graphApp, - m_sequenceApp, - m_settingsApp, - m_statisticsApp, - m_probabilityApp, - m_regressionApp, - }; - assert(sizeof(apps)/sizeof(apps[0]) == k_numberOfApps); - assert(index >= 0 && index < k_numberOfApps); - return apps[index]; +App::Descriptor * AppsContainer::appDescriptorAtIndex(int index) { + assert(index >= 0 && index < k_numberOfCommonApps); + return m_descriptors[index]; } -App * AppsContainer::hardwareTestApp() { - return m_hardwareTestApp; +App::Descriptor * AppsContainer::hardwareTestAppDescriptor() { + return m_descriptors[k_totalNumberOfApps-1]; +} + +App::Descriptor * AppsContainer::onBoardingAppDescriptor() { + return m_descriptors[k_totalNumberOfApps - 2]; } void AppsContainer::reset() { Clipboard::sharedClipboard()->reset(); - if (m_calculationApp != nullptr) { - delete m_calculationApp; - } - m_calculationApp = new Calculation::App(this, &m_globalContext); - if (m_graphApp != nullptr) { - delete m_graphApp; - } - m_graphApp = new Graph::App(this, &m_globalContext); - if (m_sequenceApp != nullptr) { - delete m_sequenceApp; - } - m_sequenceApp = new Sequence::App(this, &m_globalContext); - if (m_statisticsApp != nullptr) { - delete m_statisticsApp; - } - m_statisticsApp = new Statistics::App(this); - if (m_probabilityApp != nullptr) { - delete m_probabilityApp; - } - m_probabilityApp = new Probability::App(this); - if (m_regressionApp != nullptr) { - delete m_regressionApp; - } - m_regressionApp = new Regression::App(this); + //TODO: persitence->reset() } Poincare::Context * AppsContainer::globalContext() { @@ -133,7 +83,7 @@ VariableBoxController * AppsContainer::variableBoxController() { } void AppsContainer::suspend(bool checkIfPowerKeyReleased) { - if (activeApp() != m_onBoardingApp && GlobalPreferences::sharedGlobalPreferences()->showUpdatePopUp()) { + if (activeApp()->descriptor() != onBoardingAppDescriptor() && GlobalPreferences::sharedGlobalPreferences()->showUpdatePopUp()) { activeApp()->displayModalViewController(&m_updateController, 0.f, 0.f); } Ion::Power::suspend(checkIfPowerKeyReleased); @@ -153,20 +103,20 @@ bool AppsContainer::dispatchEvent(Ion::Events::Event event) { bool alphaLockWantsRedraw = m_window.updateAlphaLock(); // Home and Power buttons are not sent to apps. We handle them straight away. - if (event == Ion::Events::Home && activeApp() != m_hardwareTestApp && activeApp() != m_onBoardingApp) { - switchTo(appAtIndex(0)); + if (event == Ion::Events::Home && activeApp()->descriptor() != onBoardingAppDescriptor() && activeApp()->descriptor() != hardwareTestAppDescriptor() && activeApp()->descriptor() != appDescriptorAtIndex(0)) { + switchTo(appDescriptorAtIndex(0)); return true; } - if (event == Ion::Events::OnOff && activeApp() != m_hardwareTestApp) { - if (activeApp() == m_onBoardingApp) { - m_onBoardingApp->reinitOnBoarding(); + if (event == Ion::Events::OnOff && activeApp()->descriptor() != hardwareTestAppDescriptor()) { + if (activeApp()->descriptor() == onBoardingAppDescriptor()) { + ((OnBoarding::App *)activeApp())->reinitOnBoarding(); } suspend(true); return true; } bool didProcessEvent = Container::dispatchEvent(event); if (!didProcessEvent && event == Ion::Events::Back) { - switchTo(appAtIndex(0)); + switchTo(appDescriptorAtIndex(0)); return true; } if (!didProcessEvent && alphaLockWantsRedraw) { @@ -176,18 +126,18 @@ bool AppsContainer::dispatchEvent(Ion::Events::Event event) { return didProcessEvent; } -void AppsContainer::switchTo(App * app) { - if (app == hardwareTestApp() || app == m_onBoardingApp) { +void AppsContainer::switchTo(App::Descriptor * descriptor) { + if (descriptor == hardwareTestAppDescriptor() || descriptor == onBoardingAppDescriptor()) { m_window.hideTitleBarView(true); } else { m_window.hideTitleBarView(false); } - if (app) { - m_window.setTitle(app->upperName()); + if (descriptor) { + m_window.setTitle(descriptor->upperName()); } - Container::switchTo(app); - if (activeApp() == m_onBoardingApp) { - m_onBoardingApp->reinitOnBoarding(); + Container::switchTo(descriptor); + if (activeApp()->descriptor() == onBoardingAppDescriptor()) { + ((OnBoarding::App *)activeApp())->reinitOnBoarding(); } } @@ -219,32 +169,24 @@ void AppsContainer::reloadTitleBar() { m_window.reloadTitleBar(); } +UpdateController * AppsContainer::updatePopUpController() { + return &m_updateController; +} + Window * AppsContainer::window() { return &m_window; } int AppsContainer::numberOfTimers() { - return 4+(GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Activate) + (m_onBoardingApp->hasTimer()); + bool onBoardingTimer = activeApp()->descriptor() == onBoardingAppDescriptor() && ((OnBoarding::App *)activeApp())->hasTimer(); + return 4+(GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Activate) + onBoardingTimer; } Timer * AppsContainer::timerAtIndex(int i) { - switch (i) { - case 0: - return &m_batteryTimer; - case 1: - return &m_USBTimer; - case 2: - return &m_suspendTimer; - case 3: - return &m_backlightDimmingTimer; - case 4: - if (m_onBoardingApp->hasTimer() == 1) { - return m_onBoardingApp->timer(); - } - case 5: - return &m_ledTimer; - default: - assert(false); - return nullptr; + bool onBoardingTimer = activeApp()->descriptor() == onBoardingAppDescriptor() && ((OnBoarding::App *)activeApp())->hasTimer(); + if (onBoardingTimer && i == 4) { + return ((OnBoarding::App *)activeApp())->timer(); } + Timer * timers[6] = {&m_batteryTimer, &m_USBTimer, &m_suspendTimer, &m_backlightDimmingTimer, &m_ledTimer, &m_ledTimer}; + return timers[i]; } diff --git a/apps/apps_container.h b/apps/apps_container.h index 574cbd2e2..7dd01c73e 100644 --- a/apps/apps_container.h +++ b/apps/apps_container.h @@ -42,28 +42,30 @@ public: AppsContainer(AppsContainer&& other) = delete; AppsContainer& operator=(const AppsContainer& other) = delete; AppsContainer& operator=(AppsContainer&& other) = delete; - /* */ static bool poincareCircuitBreaker(const Poincare::Expression * e); int numberOfApps(); - App * appAtIndex(int index); - App * hardwareTestApp(); + App::Descriptor * appDescriptorAtIndex(int index); + App::Descriptor * hardwareTestAppDescriptor(); + App::Descriptor * onBoardingAppDescriptor(); void reset(); Poincare::Context * globalContext(); MathToolbox * mathToolbox(); VariableBoxController * variableBoxController(); void suspend(bool checkIfPowerKeyReleased = false); virtual bool dispatchEvent(Ion::Events::Event event) override; - void switchTo(App * app) override; + void switchTo(App::Descriptor * descriptor) override; void updateBatteryState(); void refreshPreferences(); void displayExamModePopUp(bool activate); void shutdownDueToLowBattery(); void reloadTitleBar(); + UpdateController * updatePopUpController(); private: Window * window() override; int numberOfTimers() override; Timer * timerAtIndex(int i) override; - static constexpr int k_numberOfApps = 8; + static constexpr int k_numberOfCommonApps = 8; + static constexpr int k_totalNumberOfApps = 2+k_numberOfCommonApps; AppsWindow m_window; EmptyBatteryWindow m_emptyBatteryWindow; #if USE_PIC_VIEW_APP @@ -79,16 +81,7 @@ private: USBTimer m_USBTimer; SuspendTimer m_suspendTimer; BacklightDimmingTimer m_backlightDimmingTimer; - OnBoarding::App * m_onBoardingApp; - Home::App * m_homeApp; - Graph::App * m_graphApp; - Probability::App * m_probabilityApp; - Calculation::App * m_calculationApp; - HardwareTest::App * m_hardwareTestApp; - Regression::App * m_regressionApp; - Sequence::App * m_sequenceApp; - Settings::App * m_settingsApp; - Statistics::App * m_statisticsApp; + App::Descriptor * m_descriptors[k_totalNumberOfApps]; }; #endif diff --git a/apps/calculation/app.cpp b/apps/calculation/app.cpp index e793ae4fc..2d3bd0b36 100644 --- a/apps/calculation/app.cpp +++ b/apps/calculation/app.cpp @@ -1,4 +1,5 @@ #include "app.h" +#include "../apps_container.h" #include "calculation_icon.h" #include "../i18n.h" using namespace Poincare; @@ -7,15 +8,35 @@ using namespace Shared; namespace Calculation { -App::App(Container * container, Context * context) : - TextFieldDelegateApp(container, &m_editExpressionController, I18n::Message::CalculApp, I18n::Message::CalculAppCapital, ImageStore::CalculationIcon), - m_localContext((GlobalContext *)context, &m_calculationStore), +App * App::Descriptor::build(Container * container) { + return new App(container, this); +} + +I18n::Message App::Descriptor::name() { + return I18n::Message::CalculApp; +} + +I18n::Message App::Descriptor::upperName() { + return I18n::Message::CalculAppCapital; +} + +const Image * App::Descriptor::icon() { + return ImageStore::CalculationIcon; +} + +App::App(Container * container, Descriptor * descriptor) : + TextFieldDelegateApp(container, &m_editExpressionController, descriptor), + m_localContext((GlobalContext *)((AppsContainer *)container)->globalContext(), &m_calculationStore), m_calculationStore(), m_historyController(&m_editExpressionController, &m_calculationStore), m_editExpressionController(&m_modalViewController, &m_historyController, &m_calculationStore) { } +App::App::Descriptor * App::buildDescriptor() { + return new App::Descriptor(); +} + Context * App::localContext() { return &m_localContext; } diff --git a/apps/calculation/app.h b/apps/calculation/app.h index 5a9f73999..c5dc6faf5 100644 --- a/apps/calculation/app.h +++ b/apps/calculation/app.h @@ -11,9 +11,17 @@ namespace Calculation { class App : public Shared::TextFieldDelegateApp { public: - App(Container * container, Poincare::Context * context); + class Descriptor : public ::App::Descriptor { + public: + App * build(Container * container) override; + I18n::Message name() override; + I18n::Message upperName() override; + const Image * icon() override; + }; + static Descriptor * buildDescriptor(); Poincare::Context * localContext() override; private: + App(Container * container, Descriptor * descriptor); LocalContext m_localContext; CalculationStore m_calculationStore; HistoryController m_historyController; diff --git a/apps/graph/app.cpp b/apps/graph/app.cpp index c41fa78d5..a65ad761d 100644 --- a/apps/graph/app.cpp +++ b/apps/graph/app.cpp @@ -1,4 +1,5 @@ #include "app.h" +#include "../apps_container.h" #include "graph_icon.h" #include "../i18n.h" @@ -7,10 +8,26 @@ using namespace Shared; namespace Graph { -App::App(Container * container, Context * context) : - FunctionApp(container, &m_inputViewController, I18n::Message::FunctionApp, I18n::Message::FunctionAppCapital, ImageStore::GraphIcon), +App * App::Descriptor::build(Container * container) { + return new App(container, this); +} + +I18n::Message App::Descriptor::name() { + return I18n::Message::FunctionApp; +} + +I18n::Message App::Descriptor::upperName() { + return I18n::Message::FunctionAppCapital; +} + +const Image * App::Descriptor::icon() { + return ImageStore::GraphIcon; +} + +App::App(Container * container, Descriptor * descriptor) : + FunctionApp(container, &m_inputViewController, descriptor), m_functionStore(), - m_xContext('x', context), + m_xContext('x',((AppsContainer *)container)->globalContext()), m_listController(&m_listFooter, &m_functionStore, &m_listHeader, &m_listFooter), m_listFooter(&m_listHeader, &m_listController, &m_listController, ButtonRowController::Position::Bottom, ButtonRowController::Style::EmbossedGrey), m_listHeader(&m_listStackViewController, &m_listFooter, &m_listController), @@ -28,6 +45,10 @@ App::App(Container * container, Context * context) : { } +App::Descriptor * App::buildDescriptor() { + return new App::Descriptor(); +} + InputViewController * App::inputViewController() { return &m_inputViewController; } diff --git a/apps/graph/app.h b/apps/graph/app.h index d4f47ea5f..58c8f4bc9 100644 --- a/apps/graph/app.h +++ b/apps/graph/app.h @@ -13,7 +13,14 @@ namespace Graph { class App : public Shared::FunctionApp { public: - App(Container * container, Poincare::Context * context); + class Descriptor : public ::App::Descriptor { + public: + App * build(Container * container) override; + I18n::Message name() override; + I18n::Message upperName() override; + const Image * icon() override; + }; + static Descriptor * buildDescriptor(); InputViewController * inputViewController() override; /* This local context can parse x. However, it always stores NAN * as x value. When we need to evaluate expression with a specific x value, we @@ -21,6 +28,7 @@ public: * weird x values after drawing curves or displaying the value table. */ Poincare::Context * localContext() override; private: + App(Container * container, Descriptor * descriptor); CartesianFunctionStore m_functionStore; Poincare::VariableContext m_xContext; ListController m_listController; diff --git a/apps/hardware_test/app.cpp b/apps/hardware_test/app.cpp index ce49a0dc4..6ce7b02d5 100644 --- a/apps/hardware_test/app.cpp +++ b/apps/hardware_test/app.cpp @@ -7,10 +7,18 @@ extern "C" { namespace HardwareTest { -App::App(AppsContainer * container) : - ::App(container, &m_keyboardController), +App * App::Descriptor::build(Container * container) { + return new App(container, this); +} + +App::App(Container * container, Descriptor * descriptor) : + ::App(container, &m_keyboardController, descriptor), m_keyboardController(&m_modalViewController) { } +App::Descriptor * App::buildDescriptor() { + return new App::Descriptor(); +} + } diff --git a/apps/hardware_test/app.h b/apps/hardware_test/app.h index baa18af3c..2c67bd694 100644 --- a/apps/hardware_test/app.h +++ b/apps/hardware_test/app.h @@ -8,10 +8,15 @@ class AppsContainer; namespace HardwareTest { - class App : public ::App { +class App : public ::App { public: - App(AppsContainer * container); + class Descriptor : public ::App::Descriptor { + public: + App * build(Container * container) override; + }; + static Descriptor * buildDescriptor(); private: + App(Container * container, Descriptor * descriptor); KeyboardController m_keyboardController; }; diff --git a/apps/hardware_test/color_controller.cpp b/apps/hardware_test/color_controller.cpp index 21d516382..a7557ae93 100644 --- a/apps/hardware_test/color_controller.cpp +++ b/apps/hardware_test/color_controller.cpp @@ -20,7 +20,7 @@ bool ColorController::handleEvent(Ion::Events::Event event) { m_view.setColors(nextColor(m_view.fillColor()), nextColor(m_view.outlineColor())); if (m_view.fillColor() == KDColorBlack) { AppsContainer * container = (AppsContainer *)app()->container(); - container->switchTo(container->appAtIndex(0)); + container->switchTo(container->appDescriptorAtIndex(0)); } return true; } diff --git a/apps/home/app.cpp b/apps/home/app.cpp index eb17ffc8f..3117414ff 100644 --- a/apps/home/app.cpp +++ b/apps/home/app.cpp @@ -8,10 +8,26 @@ extern "C" { namespace Home { -App::App(AppsContainer * container) : - ::App(container, &m_controller, I18n::Message::Apps, I18n::Message::AppsCapital, nullptr, I18n::Message::Warning), - m_controller(&m_modalViewController, container) +App * App::Descriptor::build(Container * container) { + return new App(container, this); +} + +I18n::Message App::Descriptor::name() { + return I18n::Message::Apps; +} + +I18n::Message App::Descriptor::upperName() { + return I18n::Message::AppsCapital; +} + +App::App(Container * container, Descriptor * descriptor) : + ::App(container, &m_controller, descriptor, I18n::Message::Warning), + m_controller(&m_modalViewController, (AppsContainer *)container) { } +App::Descriptor * App::buildDescriptor() { + return new App::Descriptor(); +} + } diff --git a/apps/home/app.h b/apps/home/app.h index f7ad3adb9..6af9f4d49 100644 --- a/apps/home/app.h +++ b/apps/home/app.h @@ -10,8 +10,15 @@ namespace Home { class App : public ::App { public: - App(AppsContainer * container); + class Descriptor : public ::App::Descriptor { + public: + App * build(Container * container) override; + I18n::Message name() override; + I18n::Message upperName() override; + }; + static Descriptor * buildDescriptor(); private: + App(Container * container, Descriptor * descriptor); Controller m_controller; }; diff --git a/apps/home/app_cell.cpp b/apps/home/app_cell.cpp index bd5afae93..ffeb1a381 100644 --- a/apps/home/app_cell.cpp +++ b/apps/home/app_cell.cpp @@ -31,9 +31,9 @@ void AppCell::layoutSubviews() { m_nameView.setFrame(KDRect((bounds().width()-nameSize.width())/2-k_nameWidthMargin, bounds().height()-nameSize.height() - 2*k_nameHeightMargin, nameSize.width()+2*k_nameWidthMargin, nameSize.height()+2*k_nameHeightMargin)); } -void AppCell::setApp(::App * app) { - m_iconView.setImage(app->icon()); - m_nameView.setMessage(app->name()); +void AppCell::setAppDescriptor(::App::Descriptor * descriptor) { + m_iconView.setImage(descriptor->icon()); + m_nameView.setMessage(descriptor->name()); layoutSubviews(); } diff --git a/apps/home/app_cell.h b/apps/home/app_cell.h index a46cc63d9..c614b7cb9 100644 --- a/apps/home/app_cell.h +++ b/apps/home/app_cell.h @@ -16,7 +16,7 @@ public: void setVisible(bool visible); void reloadCell() override; - void setApp(::App * app); + void setAppDescriptor(::App::Descriptor * appDescriptor); private: static constexpr KDCoordinate k_iconMargin = 18; static constexpr KDCoordinate k_iconWidth = 55; diff --git a/apps/home/controller.cpp b/apps/home/controller.cpp index f59de86fe..139908950 100644 --- a/apps/home/controller.cpp +++ b/apps/home/controller.cpp @@ -47,7 +47,7 @@ Controller::Controller(Responder * parentResponder, ::AppsContainer * container) bool Controller::handleEvent(Ion::Events::Event event) { if (event == Ion::Events::OK || event == Ion::Events::EXE) { - m_container->switchTo(m_container->appAtIndex(selectedRow()*k_numberOfColumns+selectedColumn()+1)); + m_container->switchTo(m_container->appDescriptorAtIndex(selectedRow()*k_numberOfColumns+selectedColumn()+1)); return true; } return false; @@ -101,8 +101,8 @@ void Controller::willDisplayCellAtLocation(HighlightCell * cell, int i, int j) { appCell->setVisible(false); } else { appCell->setVisible(true); - ::App * app = m_container->appAtIndex((j*k_numberOfColumns+i)+1); - appCell->setApp(app); + ::App::Descriptor * descriptor = m_container->appDescriptorAtIndex((j*k_numberOfColumns+i)+1); + appCell->setAppDescriptor(descriptor); } } diff --git a/apps/main.cpp b/apps/main.cpp index e88ee6bd7..d32cff3b0 100644 --- a/apps/main.cpp +++ b/apps/main.cpp @@ -3,7 +3,7 @@ AppsContainer container; void ion_app() { - container.switchTo(container.appAtIndex(-1)); + container.switchTo(container.onBoardingAppDescriptor()); container.run(); container.switchTo(nullptr); } diff --git a/apps/on_boarding/app.cpp b/apps/on_boarding/app.cpp index 828ffc8e3..d7b09f812 100644 --- a/apps/on_boarding/app.cpp +++ b/apps/on_boarding/app.cpp @@ -1,14 +1,23 @@ #include "app.h" +#include "../apps_container.h" namespace OnBoarding { -App::App(Container * container, UpdateController * updateController) : - ::App(container, &m_languageController), - m_languageController(&m_modalViewController, &m_logoController, updateController), +App * App::Descriptor::build(Container * container) { + return new App(container, this); +} + +App::App(Container * container, Descriptor * descriptor) : + ::App(container, &m_languageController, descriptor), + m_languageController(&m_modalViewController, &m_logoController, ((AppsContainer *)container)->updatePopUpController()), m_logoController() { } +App::Descriptor * App::buildDescriptor() { + return new App::Descriptor(); +} + void App::reinitOnBoarding() { m_languageController.reinitOnBoarding(); } diff --git a/apps/on_boarding/app.h b/apps/on_boarding/app.h index 7048858d1..81f57ab64 100644 --- a/apps/on_boarding/app.h +++ b/apps/on_boarding/app.h @@ -10,11 +10,16 @@ namespace OnBoarding { class App : public ::App { public: - App(Container * container, UpdateController * updateController); + class Descriptor : public ::App::Descriptor { + public: + App * build(Container * container) override; + }; + static Descriptor * buildDescriptor(); void reinitOnBoarding(); bool hasTimer(); Timer * timer(); private: + App(Container * container, Descriptor * descriptor); LanguageController m_languageController; LogoController m_logoController; }; diff --git a/apps/on_boarding/update_controller.cpp b/apps/on_boarding/update_controller.cpp index d3e7e3a19..e37b53673 100644 --- a/apps/on_boarding/update_controller.cpp +++ b/apps/on_boarding/update_controller.cpp @@ -16,7 +16,9 @@ bool UpdateController::handleEvent(Ion::Events::Event event) { if (event != Ion::Events::Back) { app()->dismissModalViewController(); AppsContainer * appsContainer = (AppsContainer *)app()->container(); - appsContainer->switchTo(appsContainer->appAtIndex(0)); + if (appsContainer->activeApp()->descriptor() == appsContainer->onBoardingAppDescriptor()) { + appsContainer->switchTo(appsContainer->appDescriptorAtIndex(0)); + } return true; } return false; diff --git a/apps/probability/app.cpp b/apps/probability/app.cpp index ddfce90ec..7af503ebf 100644 --- a/apps/probability/app.cpp +++ b/apps/probability/app.cpp @@ -5,11 +5,31 @@ using namespace Shared; namespace Probability { -App::App(Container * container) : - TextFieldDelegateApp(container, &m_stackViewController, I18n::Message::ProbaApp, I18n::Message::ProbaAppCapital, ImageStore::ProbabilityIcon), +App * App::Descriptor::build(Container * container) { + return new App(container, this); +} + +I18n::Message App::Descriptor::name() { + return I18n::Message::ProbaApp; +} + +I18n::Message App::Descriptor::upperName() { + return I18n::Message::ProbaAppCapital; +} + +const Image * App::Descriptor::icon() { + return ImageStore::ProbabilityIcon; +} + +App::App(Container * container, Descriptor * descriptor) : + TextFieldDelegateApp(container, &m_stackViewController, descriptor), m_lawController(nullptr), m_stackViewController(&m_modalViewController, &m_lawController) { } +App::Descriptor * App::buildDescriptor() { + return new App::Descriptor(); +} + } diff --git a/apps/probability/app.h b/apps/probability/app.h index 40ffe5010..f27bdcf7a 100644 --- a/apps/probability/app.h +++ b/apps/probability/app.h @@ -10,8 +10,16 @@ namespace Probability { class App : public Shared::TextFieldDelegateApp { public: - App(Container * container); + class Descriptor : public ::App::Descriptor { + public: + App * build(Container * container) override; + I18n::Message name() override; + I18n::Message upperName() override; + const Image * icon() override; + }; + static Descriptor * buildDescriptor(); private: + App(Container * container, Descriptor * descriptor); LawController m_lawController; StackViewController m_stackViewController; }; diff --git a/apps/regression/app.cpp b/apps/regression/app.cpp index c06e34cb1..5df331321 100644 --- a/apps/regression/app.cpp +++ b/apps/regression/app.cpp @@ -6,8 +6,24 @@ using namespace Shared; namespace Regression { -App::App(Container * container) : - TextFieldDelegateApp(container, &m_tabViewController, I18n::Message::RegressionApp, I18n::Message::RegressionAppCapital, ImageStore::RegressionIcon), +App * App::Descriptor::build(Container * container) { + return new App(container, this); +} + +I18n::Message App::Descriptor::name() { + return I18n::Message::RegressionApp; +} + +I18n::Message App::Descriptor::upperName() { + return I18n::Message::RegressionAppCapital; +} + +const Image * App::Descriptor::icon() { + return ImageStore::RegressionIcon; +} + +App::App(Container * container, Descriptor * descriptor) : + TextFieldDelegateApp(container, &m_tabViewController, descriptor), m_store(), m_calculationController(&m_calculationAlternateEmptyViewController, &m_calculationHeader, &m_store), m_calculationAlternateEmptyViewController(&m_calculationHeader, &m_calculationController, &m_calculationController), @@ -23,4 +39,8 @@ App::App(Container * container) : { } +App::Descriptor * App::buildDescriptor() { + return new App::Descriptor(); +} + } diff --git a/apps/regression/app.h b/apps/regression/app.h index a477739da..0a16cf9dc 100644 --- a/apps/regression/app.h +++ b/apps/regression/app.h @@ -12,8 +12,16 @@ namespace Regression { class App : public Shared::TextFieldDelegateApp { public: - App(Container * container); + class Descriptor : public ::App::Descriptor { + public: + App * build(Container * container) override; + I18n::Message name() override; + I18n::Message upperName() override; + const Image * icon() override; + }; + static Descriptor * buildDescriptor(); private: + App(Container * container, Descriptor * descriptor); Store m_store; CalculationController m_calculationController; AlternateEmptyViewController m_calculationAlternateEmptyViewController; diff --git a/apps/sequence/app.cpp b/apps/sequence/app.cpp index 023cb2727..b5c964796 100644 --- a/apps/sequence/app.cpp +++ b/apps/sequence/app.cpp @@ -1,14 +1,31 @@ #include "app.h" +#include "../apps_container.h" #include "sequence_icon.h" using namespace Poincare; namespace Sequence { -App::App(Container * container, Context * context) : - FunctionApp(container, &m_inputViewController, I18n::Message::SequenceApp, I18n::Message::SequenceAppCapital, ImageStore::SequenceIcon), +App * App::Descriptor::build(Container * container) { + return new App(container, this); +} + +I18n::Message App::Descriptor::name() { + return I18n::Message::SequenceApp; +} + +I18n::Message App::Descriptor::upperName() { + return I18n::Message::SequenceAppCapital; +} + +const Image * App::Descriptor::icon() { + return ImageStore::SequenceIcon; +} + +App::App(Container * container, Descriptor * descriptor) : + FunctionApp(container, &m_inputViewController, descriptor), m_sequenceStore(), - m_nContext(context), + m_nContext(((AppsContainer *)container)->globalContext()), m_listController(&m_listFooter, &m_sequenceStore, &m_listHeader, &m_listFooter), m_listFooter(&m_listHeader, &m_listController, &m_listController, ButtonRowController::Position::Bottom, ButtonRowController::Style::EmbossedGrey), m_listHeader(nullptr, &m_listFooter, &m_listController), @@ -26,6 +43,10 @@ App::App(Container * container, Context * context) : { } +App::Descriptor * App::buildDescriptor() { + return new App::Descriptor(); +} + InputViewController * App::inputViewController() { return &m_inputViewController; } diff --git a/apps/sequence/app.h b/apps/sequence/app.h index 7624954e9..8ad0d6ca1 100644 --- a/apps/sequence/app.h +++ b/apps/sequence/app.h @@ -14,11 +14,19 @@ namespace Sequence { class App : public Shared::FunctionApp { public: - App(Container * container, Poincare::Context * context); + class Descriptor : public ::App::Descriptor { + public: + App * build(Container * container) override; + I18n::Message name() override; + I18n::Message upperName() override; + const Image * icon() override; + }; + static Descriptor * buildDescriptor(); InputViewController * inputViewController() override; Poincare::Context * localContext() override; const char * XNT() override; private: + App(Container * container, Descriptor * descriptor); SequenceStore m_sequenceStore; LocalContext m_nContext; ListController m_listController; diff --git a/apps/settings/app.cpp b/apps/settings/app.cpp index 5c2c333c2..b68f28124 100644 --- a/apps/settings/app.cpp +++ b/apps/settings/app.cpp @@ -4,11 +4,31 @@ namespace Settings { -App::App(Container * container) : - ::App(container, &m_stackViewController, I18n::Message::SettingsApp, I18n::Message::SettingsAppCapital, ImageStore::SettingsIcon, I18n::Message::Warning), +App * App::Descriptor::build(Container * container) { + return new App(container, this); +} + +I18n::Message App::Descriptor::name() { + return I18n::Message::SettingsApp; +} + +I18n::Message App::Descriptor::upperName() { + return I18n::Message::SettingsAppCapital; +} + +const Image * App::Descriptor::icon() { + return ImageStore::SettingsIcon; +} + +App::App(Container * container, Descriptor * descriptor) : + ::App(container, &m_stackViewController, descriptor, I18n::Message::Warning), m_mainController(&m_stackViewController), m_stackViewController(&m_modalViewController, &m_mainController) { } +App::Descriptor * App::buildDescriptor() { + return new App::Descriptor(); +} + } diff --git a/apps/settings/app.h b/apps/settings/app.h index 8124f3851..6661a38e5 100644 --- a/apps/settings/app.h +++ b/apps/settings/app.h @@ -8,8 +8,16 @@ namespace Settings { class App : public ::App { public: - App(Container * container); + class Descriptor : public ::App::Descriptor { + public: + App * build(Container * container) override; + I18n::Message name() override; + I18n::Message upperName() override; + const Image * icon() override; + }; + static Descriptor * buildDescriptor(); private: + App(Container * container, Descriptor * descriptor); MainController m_mainController; StackViewController m_stackViewController; }; diff --git a/apps/settings/sub_controller.cpp b/apps/settings/sub_controller.cpp index d116ce015..9dea636cd 100644 --- a/apps/settings/sub_controller.cpp +++ b/apps/settings/sub_controller.cpp @@ -60,7 +60,7 @@ bool SubController::handleEvent(Ion::Events::Event event) { * clicking on '6' on the serial number row. */ if (event == Ion::Events::Six && m_nodeModel->label() == I18n::Message::About && selectedRow() == 1) { AppsContainer * appsContainer = (AppsContainer *)app()->container(); - appsContainer->switchTo(appsContainer->hardwareTestApp()); + appsContainer->switchTo(appsContainer->hardwareTestAppDescriptor()); return true; } if (event == Ion::Events::OK || event == Ion::Events::EXE) { diff --git a/apps/shared/function_app.cpp b/apps/shared/function_app.cpp index a301199e3..d15392b64 100644 --- a/apps/shared/function_app.cpp +++ b/apps/shared/function_app.cpp @@ -5,8 +5,8 @@ using namespace Poincare; namespace Shared { -FunctionApp::FunctionApp(Container * container, ViewController * rootViewController, I18n::Message name, I18n::Message upperName, const Image * icon) : - TextFieldDelegateApp(container, rootViewController, name, upperName, icon) +FunctionApp::FunctionApp(Container * container, ViewController * rootViewController, Descriptor * descriptor) : + TextFieldDelegateApp(container, rootViewController, descriptor) { } diff --git a/apps/shared/function_app.h b/apps/shared/function_app.h index 50057e5df..575663b74 100644 --- a/apps/shared/function_app.h +++ b/apps/shared/function_app.h @@ -10,7 +10,7 @@ namespace Shared { class FunctionApp : public TextFieldDelegateApp { public: - FunctionApp(Container * container, ViewController * rootViewController, I18n::Message name = (I18n::Message)0, I18n::Message upperName = (I18n::Message)0, const Image * icon = nullptr); + FunctionApp(Container * container, ViewController * rootViewController, Descriptor * descriptor); virtual InputViewController * inputViewController() = 0; void willBecomeInactive() override; }; diff --git a/apps/shared/text_field_delegate_app.cpp b/apps/shared/text_field_delegate_app.cpp index 18fdb4c2a..628419c69 100644 --- a/apps/shared/text_field_delegate_app.cpp +++ b/apps/shared/text_field_delegate_app.cpp @@ -7,8 +7,8 @@ using namespace Poincare; namespace Shared { -TextFieldDelegateApp::TextFieldDelegateApp(Container * container, ViewController * rootViewController, I18n::Message name, I18n::Message upperName, const Image * icon) : - ::App(container, rootViewController, name, upperName, icon, I18n::Message::Warning), +TextFieldDelegateApp::TextFieldDelegateApp(Container * container, ViewController * rootViewController, Descriptor * descriptor) : + ::App(container, rootViewController, descriptor, I18n::Message::Warning), TextFieldDelegate() { } diff --git a/apps/shared/text_field_delegate_app.h b/apps/shared/text_field_delegate_app.h index 3e2efb1ff..29c41d7d2 100644 --- a/apps/shared/text_field_delegate_app.h +++ b/apps/shared/text_field_delegate_app.h @@ -11,7 +11,7 @@ namespace Shared { class TextFieldDelegateApp : public ::App, public TextFieldDelegate { public: - TextFieldDelegateApp(Container * container, ViewController * rootViewController, I18n::Message name = (I18n::Message)0, I18n::Message upperName = (I18n::Message)0, const Image * icon = nullptr); + TextFieldDelegateApp(Container * container, ViewController * rootViewController, Descriptor * descriptor); virtual Poincare::Context * localContext(); AppsContainer * container(); virtual const char * XNT(); diff --git a/apps/statistics/app.cpp b/apps/statistics/app.cpp index 69c14ab4d..f65290228 100644 --- a/apps/statistics/app.cpp +++ b/apps/statistics/app.cpp @@ -5,8 +5,24 @@ using namespace Shared; namespace Statistics { -App::App(Container * container) : - TextFieldDelegateApp(container, &m_tabViewController, I18n::Message::StatsApp, I18n::Message::StatsAppCapital, ImageStore::StatIcon), +App * App::Descriptor::build(Container * container) { + return new App(container, this); +} + +I18n::Message App::Descriptor::name() { + return I18n::Message::StatsApp; +} + +I18n::Message App::Descriptor::upperName() { + return I18n::Message::StatsAppCapital; +} + +const Image * App::Descriptor::icon() { + return ImageStore::StatIcon; +} + +App::App(Container * container, Descriptor * descriptor) : + TextFieldDelegateApp(container, &m_tabViewController, descriptor), m_store(), m_calculationController(&m_calculationAlternateEmptyViewController, &m_calculationHeader, &m_store), m_calculationAlternateEmptyViewController(&m_calculationHeader, &m_calculationController, &m_calculationController), @@ -25,4 +41,8 @@ App::App(Container * container) : { } +App::Descriptor * App::buildDescriptor() { + return new App::Descriptor(); +} + } diff --git a/apps/statistics/app.h b/apps/statistics/app.h index 2f591fa86..56c4699a9 100644 --- a/apps/statistics/app.h +++ b/apps/statistics/app.h @@ -13,8 +13,16 @@ namespace Statistics { class App : public Shared::TextFieldDelegateApp { public: - App(Container * container); + class Descriptor : public ::App::Descriptor { + public: + App * build(Container * container) override; + I18n::Message name() override; + I18n::Message upperName() override; + const Image * icon() override; + }; + static Descriptor * buildDescriptor(); private: + App(Container * container, Descriptor * descriptor); Store m_store; CalculationController m_calculationController; AlternateEmptyViewController m_calculationAlternateEmptyViewController; diff --git a/escher/include/escher/app.h b/escher/include/escher/app.h index 0c3748f8d..792ab6ed8 100644 --- a/escher/include/escher/app.h +++ b/escher/include/escher/app.h @@ -21,9 +21,18 @@ class Container; class App : public Responder { public: - constexpr static uint8_t Magic = 0xA8; - App(Container * container, ViewController * rootViewController, I18n::Message name = (I18n::Message)0, I18n::Message upperName = (I18n::Message)0, const Image * icon = nullptr, I18n::Message warningMessage = (I18n::Message)0); + class Descriptor { + public: + virtual App * build(Container * container) = 0; + virtual I18n::Message name(); + virtual I18n::Message upperName(); + virtual const Image * icon(); + }; + /* Each App subclass must implement + * static Descriptor * builDescriptor(); */ + Descriptor * descriptor(); virtual ~App() = default; + constexpr static uint8_t Magic = 0xA8; void setFirstResponder(Responder * responder); Responder * firstResponder(); bool processEvent(Ion::Events::Event event); @@ -32,23 +41,19 @@ public: void dismissModalViewController(); void displayWarning(I18n::Message warningMessage); const Container * container() const; - I18n::Message name(); - I18n::Message upperName(); - const Image * icon(); uint8_t m_magic; // Poor man's RTTI - virtual void didBecomeActive(Window * window); virtual void willBecomeInactive(); protected: + App(Container * container, ViewController * rootViewController, Descriptor * descriptor, I18n::Message warningMessage = (I18n::Message)0); ModalViewController m_modalViewController; private: + Descriptor * m_descriptor; Container * m_container; Responder * m_firstResponder; WarningController m_warningController; - I18n::Message m_name; - I18n::Message m_upperName; - const Image * m_icon; }; #endif + diff --git a/escher/include/escher/container.h b/escher/include/escher/container.h index 595f0a177..78343454c 100644 --- a/escher/include/escher/container.h +++ b/escher/include/escher/container.h @@ -18,10 +18,15 @@ class Container : public RunLoop { public: Container(); + virtual ~Container(); + Container(const Container& other) = delete; + Container(Container&& other) = delete; + Container& operator=(const Container& other) = delete; + Container& operator=(Container&& other) = delete; void run(); App * activeApp(); virtual bool dispatchEvent(Ion::Events::Event event) override; - virtual void switchTo(App * app); + virtual void switchTo(App::Descriptor * descriptor); protected: virtual Window * window() = 0; void windowRedraw() override; diff --git a/escher/src/app.cpp b/escher/src/app.cpp index 3a1fe358a..b3bf406a7 100644 --- a/escher/src/app.cpp +++ b/escher/src/app.cpp @@ -4,19 +4,33 @@ extern "C" { #include } -App::App(Container * container, ViewController * rootViewController, I18n::Message name, I18n::Message upperName, const Image * icon, I18n::Message warningMessage) : +I18n::Message App::Descriptor::name() { + return (I18n::Message)0; +} + +I18n::Message App::Descriptor::upperName() { + return (I18n::Message)0; +} + +const Image * App::Descriptor::icon() { + return nullptr; +} + +App::App(Container * container, ViewController * rootViewController, Descriptor * descriptor, I18n::Message warningMessage) : Responder(nullptr), m_magic(Magic), m_modalViewController(this, rootViewController), + m_descriptor(descriptor), m_container(container), m_firstResponder(nullptr), - m_warningController(this, warningMessage), - m_name(name), - m_upperName(upperName), - m_icon(icon) + m_warningController(this, warningMessage) { } +App::Descriptor * App::descriptor() { + return m_descriptor; +} + bool App::processEvent(Ion::Events::Event event) { Responder * responder = m_firstResponder; bool didHandleEvent = false; @@ -57,18 +71,6 @@ void App::setFirstResponder(Responder * responder) { } } -I18n::Message App::name() { - return m_name; -} - -I18n::Message App::upperName() { - return m_upperName; -} - -const Image * App::icon() { - return m_icon; -} - void App::displayModalViewController(ViewController * vc, float verticalAlignment, float horizontalAlignment, KDCoordinate topMargin, KDCoordinate leftMargin, KDCoordinate bottomMargin, KDCoordinate rightMargin) { if (m_modalViewController.isDisplayingModal()) { diff --git a/escher/src/container.cpp b/escher/src/container.cpp index 53319bf06..cd7c273c1 100644 --- a/escher/src/container.cpp +++ b/escher/src/container.cpp @@ -7,14 +7,20 @@ Container::Container() : { } -void Container::switchTo(App * app) { - if (m_activeApp == app) { - return; +Container::~Container() { + if (m_activeApp) { + delete m_activeApp; } +} + +void Container::switchTo(App::Descriptor * descriptor) { if (m_activeApp) { m_activeApp->willBecomeInactive(); + delete m_activeApp; + } + if (descriptor) { + m_activeApp = descriptor->build(this); } - m_activeApp = app; if (m_activeApp) { m_activeApp->didBecomeActive(window()); } diff --git a/escher/src/window.cpp b/escher/src/window.cpp index 5ef730f1e..618b6fba4 100644 --- a/escher/src/window.cpp +++ b/escher/src/window.cpp @@ -18,11 +18,9 @@ void Window::redraw(bool force) { } void Window::setContentView(View * contentView) { - if (m_contentView != contentView) { - m_contentView = contentView; - markRectAsDirty(bounds()); - layoutSubviews(); - } + m_contentView = contentView; + markRectAsDirty(bounds()); + layoutSubviews(); } const Window * Window::window() const {