Skip to content

Commit

Permalink
Options buttons in home controller, logout and quit work
Browse files Browse the repository at this point in the history
  • Loading branch information
dacharyc committed Mar 21, 2024
1 parent 6d15499 commit 29aa2e3
Show file tree
Hide file tree
Showing 15 changed files with 181 additions and 85 deletions.
1 change: 1 addition & 0 deletions sync-todo/v2/client/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ add_executable(sync_todo
main.cpp
ss.hpp
controllers/app_controller.hpp
controllers/app_controller.cpp
controllers/controller.hpp
controllers/home_controller.hpp
controllers/home_controller.cpp
Expand Down
6 changes: 6 additions & 0 deletions sync-todo/v2/client/cpp/app_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@

#include "managers/auth_manager.hpp"
#include "managers/error_manager.hpp"
#include "database_state.hpp"

#include "ftxui/component/screen_interactive.hpp"

struct AppState {
std::unique_ptr<AuthManager> authManager;
std::unique_ptr<ErrorManager> errorManager;
std::unique_ptr<realm::App> app;
std::unique_ptr<DatabaseState> databaseState;

ftxui::ScreenInteractive *screen;
};
2 changes: 1 addition & 1 deletion sync-todo/v2/client/cpp/atlasConfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"appId": "cpp-tester-foylc",
"appId": "INSERT-YOUR-APP-ID-HERE",
"appUrl": "https://services.cloud.mongodb.com/groups/6388cb218e4d865c34158da5/apps/65f46bd16a5a245b65769e5d",
"baseUrl": "https://services.cloud.mongodb.com",
"clientApiBaseUrl": "https://us-east-1.aws.services.cloud.mongodb.com",
Expand Down
4 changes: 4 additions & 0 deletions sync-todo/v2/client/cpp/controllers/app_controller.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#include "app_controller.hpp"

void AppController::onFrame() {
_navigation.onFrame();
}

//AppController::AppController() {
//
// _appState.authManager = std::make_unique<AuthManager>(this);
Expand Down
10 changes: 9 additions & 1 deletion sync-todo/v2/client/cpp/controllers/app_controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@
#include "../managers/auth_manager.hpp"
#include "../managers/error_manager.hpp"
#include "../app_state.hpp"
#include "../database_state.hpp"
#include "home_controller.hpp"
#include "login_controller.hpp"
#include "../app_config_metadata.hpp"

class AppController final : public Controller, public AuthManager::Delegate, public ErrorManager::Delegate {
private:
AppState _appState;
DatabaseState _databaseState;
Navigation _navigation;

bool _showErrorModal{true};
Expand All @@ -25,7 +27,8 @@ class AppController final : public Controller, public AuthManager::Delegate, pub

public:
// AppController();
AppController() {
AppController(ftxui::ScreenInteractive *screen) {
_appState.screen = screen;

/** Read the contents of the atlasConfig.json to get the metadata for the App Services App.
* This path assumes you are running the app from a `/build` directory within this project. If you're
Expand All @@ -45,6 +48,9 @@ class AppController final : public Controller, public AuthManager::Delegate, pub
_appState.authManager = std::make_unique<AuthManager>(this);
_appState.errorManager = std::make_unique<ErrorManager>(this);

auto dbState = DatabaseState();
_appState.databaseState = std::make_unique<DatabaseState>(std::move(dbState));

_errorModal = ftxui::Container::Vertical({
ftxui::Renderer([this] {
return ftxui::text(_appState.errorManager->getError().value());
Expand All @@ -63,6 +69,8 @@ class AppController final : public Controller, public AuthManager::Delegate, pub
}
}

void onFrame() override;

private:
void onRegisteredAndLoggedIn() override {
_navigation.goTo(std::make_unique<HomeController>(&_appState));
Expand Down
1 change: 1 addition & 0 deletions sync-todo/v2/client/cpp/controllers/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class Controller {
Controller(): Controller(ftxui::Container::Stacked({})) {}
Controller(ftxui::Component component): _component(component) {}
virtual ~Controller() = 0;
virtual void onFrame() {}

ftxui::Component component() {
return _component;
Expand Down
75 changes: 67 additions & 8 deletions sync-todo/v2/client/cpp/controllers/home_controller.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,70 @@
#include "home_controller.hpp"

HomeController::HomeController(AppState *appState): Controller(ftxui::Container::Vertical({
ftxui::Button("Log out", [this] {
_appState->authManager->logOut(_appState->app.get());
}),
ftxui::Button("Trigger error", [this] {
_appState->errorManager->setError("Uh oh!");
})
})), _appState(appState) {
ftxui::Component VWrap(std::string name, ftxui::Component component) {
return Renderer(component, [name, component] {
return ftxui::vbox({
hbox(ftxui::text(name)) | ftxui::hcenter | size(ftxui::WIDTH, ftxui::EQUAL, 18),
ftxui::separator(),
component->Render() | ftxui::hcenter,
});
});
}

HomeController::HomeController(AppState *appState): Controller(ftxui::Container::Vertical({})), _appState(appState) {
// ItemManager *itemManager;
// itemManager->init(appState);

/** This button row displays at the top of the home screen and provides most of the interactions that change app state.*/
auto goOfflineButtonLabel = std::string{"Go Offline"};
auto goOnlineButtonLabel = std::string{"Go Online"};

if (_appState->databaseState->offlineModeSelection == offlineModeEnabled) {
state.toggleOfflineModeButtonLabel = goOnlineButtonLabel;
} else if (_appState->databaseState->offlineModeSelection == offlineModeDisabled) {
state.toggleOfflineModeButtonLabel = goOfflineButtonLabel;
}

// auto toggleOfflineModeButton = ftxui::Button(&state.toggleOfflineModeButtonLabel, [=]{ itemManager->toggleOfflineMode(); });
auto toggleOfflineModeButton = ftxui::Button(&state.toggleOfflineModeButtonLabel, [=]{ });
toggleOfflineModeButton = VWrap("Offline Mode", toggleOfflineModeButton);

auto showAllButtonLabel = std::string{"Show All Tasks"};
auto showMineButtonLabel = std::string{"Show Only My Tasks"};

if (_appState->databaseState->subscriptionSelection == allItems) {
state.toggleSubscriptionsButtonLabel = showMineButtonLabel;
} else if (_appState->databaseState->subscriptionSelection == myItems) {
state.toggleSubscriptionsButtonLabel = showAllButtonLabel;
}

//auto toggleSubscriptionsButton = ftxui::Button(&state.toggleSubscriptionsButtonLabel, [&]{ itemManager->toggleSubscriptions(); });
auto toggleSubscriptionsButton = ftxui::Button(&state.toggleSubscriptionsButtonLabel, [&]{ });
toggleSubscriptionsButton = VWrap("Offline Mode", toggleSubscriptionsButton);

auto filters = ftxui::Checkbox("Hide completed", &_appState->databaseState->hideCompletedTasks);
filters = VWrap("Filters", filters);

auto logoutButton = ftxui::Button("Logout", [&]{ _appState->authManager->logOut(_appState->app.get()); });
logoutButton = VWrap("Auth", logoutButton);

auto quitButton = ftxui::Button("Quit", appState->screen->ExitLoopClosure());
//auto quitButton = ftxui::Button("Quit", {});
quitButton = VWrap("Exit", quitButton);

auto optionsLayout = ftxui::Container::Horizontal(
{toggleOfflineModeButton, toggleSubscriptionsButton, filters, logoutButton, quitButton});

auto homeControllerButtonView = Renderer(optionsLayout, [=] {
return vbox(
hbox(toggleOfflineModeButton->Render(), ftxui::separator(), toggleSubscriptionsButton->Render(),
ftxui::separator(), filters->Render(), ftxui::separator(),
logoutButton->Render(), ftxui::separator(), quitButton->Render()) |
ftxui::border);
});

component()->Add(homeControllerButtonView);
}

void HomeController::onFrame() {
// TODO: Refresh the realm from here to get the synced data between runloops
}
7 changes: 7 additions & 0 deletions sync-todo/v2/client/cpp/controllers/home_controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,15 @@ class HomeController final : public Controller {
private:
AppState *_appState{nullptr};

struct HomeControllerViewState {
std::string toggleOfflineModeButtonLabel;
std::string toggleSubscriptionsButtonLabel;
} state;

public:
HomeController(AppState *appState);

void onFrame() override;
// HomeController(AppState *appState): Controller(ftxui::Container::Vertical({
// ftxui::Button("Log out", [this] {
// _appState->authManager->logOut(_appState->app.get());
Expand Down
6 changes: 6 additions & 0 deletions sync-todo/v2/client/cpp/controllers/navigation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ class Navigation final : public Controller {
Navigation(): Controller(ftxui::Container::Vertical({})) {}
//Navigation();

void onFrame() override {
if (_currentController) {
_currentController->onFrame();
}
}

void goTo(std::unique_ptr<Controller> controller) {
component()->DetachAllChildren();
_currentController = std::move(controller);
Expand Down
8 changes: 4 additions & 4 deletions sync-todo/v2/client/cpp/database_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@
struct DatabaseState {
/** The app uses these properties when creating a new task. */
std::string newTaskSummary;
bool newTaskIsComplete;
bool newTaskIsComplete{false};

/** The app uses this to determine which item list to display - all items,
* or an item list that only displays incomplete items.
*/
bool hideCompletedTasks;
bool hideCompletedTasks{false};

/** The app uses this int with the `SubscriptionSelection` enum to determine
* whether to subscribe to all items, or only the user's items.
*/
SubscriptionSelection subscriptionSelection;
SubscriptionSelection subscriptionSelection{allItems};

/** The app uses this int with the `OfflineModeSelection` enum to determine
* whether to immediately sync all changes, or simulate offline mode and stop syncing.
*/
OfflineModeSelection offlineModeSelection;
OfflineModeSelection offlineModeSelection{offlineModeDisabled};
};
3 changes: 2 additions & 1 deletion sync-todo/v2/client/cpp/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ int main() {
// Initialize render destination
auto screen = ftxui::ScreenInteractive::Fullscreen();

AppController appController;
AppController appController(&screen);

// Declare loop that handles events and renders the component to the screen
ftxui::Loop loop(&screen, appController.component());

while (!loop.HasQuitted()) {
appController.onFrame();
loop.RunOnce();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
Expand Down
33 changes: 18 additions & 15 deletions sync-todo/v2/client/cpp/managers/item_manager.cpp
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
#include "item_manager.hpp"

void ItemManager::init(realm::user& user, AppState* appState) {
void ItemManager::init(AppState* appState) {
_appState = appState;
auto user = _appState->app->get_current_user();

// Sync configuration and sync subscription management.
allItemSubscriptionName = "all_items";
myItemSubscriptionName = "my_items";
userId = user.identifier();
userId = user->identifier();

auto config = user.flexible_sync_configuration();
auto config = user->flexible_sync_configuration();

// Handle database sync errors. If there is an error, add the message to the `appState`
// and change the screen that is displaying to the error modal.
config.sync_config().set_error_handler([&appState](const realm::sync_session &session,
config.sync_config().set_error_handler([=](const realm::sync_session &session,
const realm::internal::bridge::sync_error &error) {

auto errorText = SS("A sync error occurred. Message: " << error.message() << std::endl);
appState->errorManager->setError(errorText);
_appState->errorManager->setError(errorText);
});

/* Initialize the database, and add a subscription to all items. This enables the app to read
Expand All @@ -37,10 +40,10 @@ void ItemManager::init(realm::user& user, AppState* appState) {
}

/// Add a new item to the task list.
void ItemManager::addNew(DatabaseState* databaseState) {
void ItemManager::addNew() {
auto item = realm::Item {
.isComplete = databaseState->newTaskIsComplete,
.summary = std::move(databaseState->newTaskSummary),
.isComplete = _appState->databaseState->newTaskIsComplete,
.summary = std::move(_appState->databaseState->newTaskSummary),
.owner_id = std::move(userId),
};

Expand Down Expand Up @@ -91,22 +94,22 @@ void ItemManager::refreshDatabase() {

/// Toggling offline mode simulates having no network connection by pausing sync.
/// The user can write to the database on device, and the data syncs automatically when sync is resumed.
void ItemManager::toggleOfflineMode(DatabaseState* databaseState) {
void ItemManager::toggleOfflineMode() {
auto syncSession = databasePtr->get_sync_session();
if (syncSession->state() == realm::internal::bridge::sync_session::state::paused) {
syncSession->resume();
databaseState->offlineModeSelection = offlineModeDisabled;
_appState->databaseState->offlineModeSelection = offlineModeDisabled;
} else if (syncSession->state() == realm::internal::bridge::sync_session::state::active) {
syncSession->pause();
databaseState->offlineModeSelection = offlineModeEnabled;
_appState->databaseState->offlineModeSelection = offlineModeEnabled;
}
}

/** Changing the database subscriptions changes which data syncs to the device. */
void ItemManager::toggleSubscriptions(DatabaseState* databaseState) {
void ItemManager::toggleSubscriptions() {
// Note the subscription state at the start of the toggle operation.
// We'll change it after updating the subscriptions.
int currentSubscriptionState = databaseState->subscriptionSelection;
int currentSubscriptionState = _appState->databaseState->subscriptionSelection;

// TODO: THIS COULD BE A PROBLEM
databasePtr->subscriptions().update([&](realm::mutable_sync_subscription_set& subs) {
Expand All @@ -122,7 +125,7 @@ void ItemManager::toggleSubscriptions(DatabaseState* databaseState) {
});
}
// Update the subscription selection to reflect the new subscription.
databaseState->subscriptionSelection = myItems;
_appState->databaseState->subscriptionSelection = myItems;

// If the currentSubscriptionState is `myItems`, toggling should show all items.
// Remove the `myItems` subscription and make sure the subscription for the all items is present.
Expand All @@ -135,7 +138,7 @@ void ItemManager::toggleSubscriptions(DatabaseState* databaseState) {
}

// Update the subscription selection to reflect the new subscription.
databaseState->subscriptionSelection = allItems;
_appState->databaseState->subscriptionSelection = allItems;
}
}).get();

Expand Down
9 changes: 5 additions & 4 deletions sync-todo/v2/client/cpp/managers/item_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,21 @@ class ItemManager {
virtual void onOfflineModeChange() = 0;
};

void init(realm::user& user, AppState* appState);
void addNew(DatabaseState* databaseState);
void init(AppState* appState);
void addNew();
void remove(realm::managed<realm::Item> itemToDelete);
void markComplete(realm::managed<realm::Item> itemToMarkComplete);
void refreshDatabase();
void toggleOfflineMode(DatabaseState* databaseState);
void toggleOfflineMode();
realm::results<realm::Item> getItemList();
realm::results<realm::Item> getIncompleteItemList();
void toggleSubscriptions(DatabaseState* databaseState);
void toggleSubscriptions();

private:
std::string allItemSubscriptionName;
std::string myItemSubscriptionName;
std::unique_ptr<realm::db> databasePtr;
std::string userId;
Delegate *_delegate{nullptr};
AppState *_appState;
};
24 changes: 12 additions & 12 deletions sync-todo/v2/client/cpp/views/home_screen_button_row.cpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
#include "home_screen_button_row.hpp"

ftxui::Component VWrap(std::string name, ftxui::Component component) {
return Renderer(component, [name, component] {
return ftxui::vbox({
hbox(ftxui::text(name)) | ftxui::hcenter | size(ftxui::WIDTH, ftxui::EQUAL, 18),
ftxui::separator(),
component->Render() | ftxui::hcenter,
});
});
}

/// Options display at the top of the dashboard and provide most of the interactions that change app state.
//ftxui::Component Options::init(std::shared_ptr<AuthManager> g_auth_manager, ItemManager* itemManager, AppState* appState) {
//ftxui::Component VWrap(std::string name, ftxui::Component component) {
// return Renderer(component, [name, component] {
// return ftxui::vbox({
// hbox(ftxui::text(name)) | ftxui::hcenter | size(ftxui::WIDTH, ftxui::EQUAL, 18),
// ftxui::separator(),
// component->Render() | ftxui::hcenter,
// });
// });
//}
//
///** This button row displays at the top of the home screen and provides most of the interactions that change app state.*/
//ftxui::Component Options::init(AppState *appState, ItemManager* itemManager) {
// goOfflineButtonLabel = "Go Offline";
// goOnlineButtonLabel = "Go Online";
//
Expand Down
Loading

0 comments on commit 29aa2e3

Please sign in to comment.