Skip to content

Commit

Permalink
feat: add view data to ViewManager (#17)
Browse files Browse the repository at this point in the history
* fix: added assert to `UiBridge::call`

* refactor: added included header in `BasicView` for convenience

* feat: added view data to `ViewManager`
  • Loading branch information
cEvolve05 authored Aug 17, 2024
1 parent 8034c19 commit 1aa929e
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 23 deletions.
3 changes: 3 additions & 0 deletions src/Controller/Core/BasicView.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#pragma once

#include <Controller/Core/AccountManager.h>
#include <Controller/Core/GlobalAgent.hh>
#include <Controller/Core/MessageManager.h>
#include <Controller/Core/UiBase.h>
#include <Controller/Core/ViewManager.h>

EVENTO_UI_START

Expand Down
3 changes: 1 addition & 2 deletions src/Controller/Core/MessageManager.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
#pragma once

#include <Controller/Core/BasicView.h>
#include <Controller/Core/GlobalAgent.hh>
#include <Controller/Core/UiBase.h>
#include <chrono>
#include <string>

EVENTO_UI_START

class MessageManager : GlobalAgent<MessageManagerBridge> {
class MessageManager : private GlobalAgent<MessageManagerBridge> {
friend class UiBridge;
UiBridge& bridge;
std::string logOrigin = "MessageManager";
Expand Down
34 changes: 23 additions & 11 deletions src/Controller/Core/ViewManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <Controller/UiBridge.h>
#include <algorithm>
#include <cassert>
#include <memory>
#include <set>
#include <spdlog/spdlog.h>

Expand All @@ -25,53 +26,54 @@ ViewManager::ViewManager(slint::ComponentHandle<UiEntryName> uiEntry, UiBridge&
});
}

void ViewManager::initStack(ViewName newView) {
viewStack.emplace(newView);
void ViewManager::initStack(ViewName newView, std::shared_ptr<ViewData> data) {
assert(!bridge.inEventLoop());
pushView(newView, std::move(data));
// separate operation reduce (possible) flicking when window start up and keeps invoke order
visibleViews.emplace(newView);
slint::invoke_from_event_loop([this, newView] { return showView(newView); });
}

void ViewManager::navigateTo(ViewName newView) {
void ViewManager::navigateTo(ViewName newView, std::shared_ptr<ViewData> data) {
auto& self = *this;
navAssert();
if (newView == viewStack.top()) {
return;
}

viewStack.push(newView);
pushView(newView, std::move(data));

syncViewVisibility();
}

void ViewManager::cleanNavigateTo(ViewName newView) {
void ViewManager::cleanNavigateTo(ViewName newView, std::shared_ptr<ViewData> data) {
auto& self = *this;
navAssert();
if (newView == viewStack.top()) {
return;
}

while (viewStack.size() > 1) {
viewStack.pop();
popView();
}
if (newView == viewStack.top()) {
syncViewVisibility();
return;
}
viewStack.push(newView);
pushView(newView, std::move(data));

syncViewVisibility();
}

void ViewManager::replaceNavigateTo(ViewName newView) {
void ViewManager::replaceNavigateTo(ViewName newView, std::shared_ptr<ViewData> data) {
auto& self = *this;
navAssert();
if (newView == viewStack.top()) {
return;
}

viewStack.pop();
viewStack.push(newView);
popView();
pushView(newView, std::move(data));

syncViewVisibility();
}
Expand All @@ -85,7 +87,7 @@ void ViewManager::priorView() {
return;
}

viewStack.pop();
popView();

syncViewVisibility();
}
Expand All @@ -94,6 +96,16 @@ bool ViewManager::isVisible(ViewName target) {
return visibleViews.find(target) != visibleViews.end();
}

void ViewManager::pushView(ViewName newView, std::shared_ptr<ViewData>&& data) {
viewStack.push(newView);
viewData.emplace(std::move(data));
}

void ViewManager::popView() {
viewStack.pop();
viewData.pop();
}

void ViewManager::syncViewVisibility() {
static std::set<ViewName> newVisibleViews;
auto& self = *this;
Expand Down
52 changes: 42 additions & 10 deletions src/Controller/Core/ViewManager.h
Original file line number Diff line number Diff line change
@@ -1,51 +1,83 @@
#pragma once

#include <Controller/Core/BasicView.h>
#include <Controller/Core/GlobalAgent.hh>
#include <Controller/Core/UiBase.h>
#include <cassert>
#include <memory>
#include <set>
#include <stack>
#include <string>

EVENTO_UI_START

// intended to be inherited
struct ViewData {};

// adding a new page should do:
// - push to viewStack
// - re-calculate visibleViews
// - add data to viewData
// - call onShow
//
// pop a page should do:
// - pop viewStack
// - re-calculate visibleViews
// - pop data to current index(after pop)
// - call onHide/Show
class ViewManager : private GlobalAgent<ViewManagerBridge> {
friend class UiBridge;
UiBridge& bridge;
std::string logOrigin = "ViewManager";

std::stack<ViewName> viewStack;
std::stack<std::shared_ptr<ViewData>> viewData;

std::set<ViewName> visibleViews;

public:
ViewManager(slint::ComponentHandle<UiEntryName> uiEntry, UiBridge& bridge);
ViewManager(ViewManager&) = delete;

// invoked before event loop running
void initStack(ViewName newView);
void initStack(ViewName newView, std::shared_ptr<ViewData> data = {});

// view will be added to stack and show on top, overlay won't hide prior view.
// auto refresh
void navigateTo(ViewName newView);
void navigateTo(ViewName newView, std::shared_ptr<ViewData> data = {});

// stack will be clean (init view left), and push new view.
// auto refresh
void cleanNavigateTo(ViewName newView);
void cleanNavigateTo(ViewName newView, std::shared_ptr<ViewData> data = {});

// current page pop and new view pushed.
// auto refresh
void replaceNavigateTo(ViewName newView);
void replaceNavigateTo(ViewName newView, std::shared_ptr<ViewData> data = {});

// view will be pop from stack, new top will be show if it not.
// auto refresh
void priorView();

// check view visibility
bool isVisible(ViewName target);

/**
* get data corresponding to current view, set by all navigate function,
* useful when needed to transfer data between view or save data for current view in case of a view opened twice,
* pop view will destroy its data, data type required to inherit ViewData
*
* @param T(template argument) target view data type
* @example getDate<MyDataType>();
*/
template<typename T>
std::shared_ptr<T> getData() {
assert(viewData.top() && "no view data");
auto res = std::dynamic_pointer_cast<T>(viewData.top());
assert(res && "down cast failed");
return res;
}

private:
void pushView(ViewName newView, std::shared_ptr<ViewData>&& data);
void popView();

// sync view visibility from viewStack to visibleViews.
void syncViewVisibility();

void showView(ViewName target);
void hideView(ViewName target);

Expand Down
2 changes: 2 additions & 0 deletions src/Controller/UiBridge.cc
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ bool UiBridge::inEventLoop() const {
}

void UiBridge::call(Action& action) {
slint::private_api::assert_main_thread();
std::for_each(views.begin(),
views.end(),
[&action](const std::pair<const ViewName, std::shared_ptr<BasicView>>& view) {
Expand All @@ -103,6 +104,7 @@ void UiBridge::call(Action& action) {
}

void UiBridge::call(Action& action, ViewName target) {
slint::private_api::assert_main_thread();
action(*views.at(target));
}

Expand Down

0 comments on commit 1aa929e

Please sign in to comment.