diff --git a/AE/Book.aep b/AE/Book.aep new file mode 100644 index 0000000..a815830 Binary files /dev/null and b/AE/Book.aep differ diff --git a/AE/MainNav.aep b/AE/MainNav.aep index 1f9e57c..a62e605 100644 Binary files a/AE/MainNav.aep and b/AE/MainNav.aep differ diff --git a/AE/Notifications.aep b/AE/Notifications.aep new file mode 100644 index 0000000..9baee7c Binary files /dev/null and b/AE/Notifications.aep differ diff --git a/AE/assets/drawable/default/icon-heart.png b/AE/assets/drawable/default/icon-heart.png new file mode 100644 index 0000000..6c679a9 Binary files /dev/null and b/AE/assets/drawable/default/icon-heart.png differ diff --git a/AE/assets/drawable/default/white-horizontal-line.png b/AE/assets/drawable/default/white-horizontal-line.png new file mode 100644 index 0000000..103eeb2 Binary files /dev/null and b/AE/assets/drawable/default/white-horizontal-line.png differ diff --git a/AE/assets/layout/tablet/Book_Main.layout b/AE/assets/layout/tablet/Book_Main.layout new file mode 100644 index 0000000..3efb019 Binary files /dev/null and b/AE/assets/layout/tablet/Book_Main.layout differ diff --git a/AE/assets/layout/tablet/Book_Main.timeline b/AE/assets/layout/tablet/Book_Main.timeline new file mode 100644 index 0000000..5f9c6d1 Binary files /dev/null and b/AE/assets/layout/tablet/Book_Main.timeline differ diff --git a/AE/assets/layout/tablet/Book_TabbedView.layout b/AE/assets/layout/tablet/Book_TabbedView.layout new file mode 100644 index 0000000..65a226d Binary files /dev/null and b/AE/assets/layout/tablet/Book_TabbedView.layout differ diff --git a/AE/assets/layout/tablet/Book_TabbedView.timeline b/AE/assets/layout/tablet/Book_TabbedView.timeline new file mode 100644 index 0000000..593f470 Binary files /dev/null and b/AE/assets/layout/tablet/Book_TabbedView.timeline differ diff --git a/AE/assets/layout/tablet/MainNav_Main.layout b/AE/assets/layout/tablet/MainNav_Main.layout index 42d0f00..20eed2c 100644 Binary files a/AE/assets/layout/tablet/MainNav_Main.layout and b/AE/assets/layout/tablet/MainNav_Main.layout differ diff --git a/AE/assets/layout/tablet/MainNav_Main.timeline b/AE/assets/layout/tablet/MainNav_Main.timeline index 8a7bb78..795a5bc 100644 Binary files a/AE/assets/layout/tablet/MainNav_Main.timeline and b/AE/assets/layout/tablet/MainNav_Main.timeline differ diff --git a/AE/assets/layout/tablet/Notifications_Btn-Action1.layout b/AE/assets/layout/tablet/Notifications_Btn-Action1.layout new file mode 100644 index 0000000..eb35889 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_Btn-Action1.layout differ diff --git a/AE/assets/layout/tablet/Notifications_Btn-Action1.timeline b/AE/assets/layout/tablet/Notifications_Btn-Action1.timeline new file mode 100644 index 0000000..f3b7e73 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_Btn-Action1.timeline differ diff --git a/AE/assets/layout/tablet/Notifications_Btn-Action2.layout b/AE/assets/layout/tablet/Notifications_Btn-Action2.layout new file mode 100644 index 0000000..228ba82 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_Btn-Action2.layout differ diff --git a/AE/assets/layout/tablet/Notifications_Btn-Action2.timeline b/AE/assets/layout/tablet/Notifications_Btn-Action2.timeline new file mode 100644 index 0000000..dbd2ccd Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_Btn-Action2.timeline differ diff --git a/AE/assets/layout/tablet/Notifications_Btn-Close.layout b/AE/assets/layout/tablet/Notifications_Btn-Close.layout new file mode 100644 index 0000000..2b18ef7 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_Btn-Close.layout differ diff --git a/AE/assets/layout/tablet/Notifications_Btn-Close.timeline b/AE/assets/layout/tablet/Notifications_Btn-Close.timeline new file mode 100644 index 0000000..da0477f Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_Btn-Close.timeline differ diff --git a/AE/assets/layout/tablet/Notifications_ErrorMessage-Fullscreen-ButtonContainer.layout b/AE/assets/layout/tablet/Notifications_ErrorMessage-Fullscreen-ButtonContainer.layout new file mode 100644 index 0000000..1c26f83 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_ErrorMessage-Fullscreen-ButtonContainer.layout differ diff --git a/AE/assets/layout/tablet/Notifications_ErrorMessage-Fullscreen-ButtonContainer.timeline b/AE/assets/layout/tablet/Notifications_ErrorMessage-Fullscreen-ButtonContainer.timeline new file mode 100644 index 0000000..706bd32 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_ErrorMessage-Fullscreen-ButtonContainer.timeline differ diff --git a/AE/assets/layout/tablet/Notifications_ErrorMessage-Fullscreen.layout b/AE/assets/layout/tablet/Notifications_ErrorMessage-Fullscreen.layout new file mode 100644 index 0000000..2fcfa82 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_ErrorMessage-Fullscreen.layout differ diff --git a/AE/assets/layout/tablet/Notifications_ErrorMessage-Fullscreen.timeline b/AE/assets/layout/tablet/Notifications_ErrorMessage-Fullscreen.timeline new file mode 100644 index 0000000..89102d1 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_ErrorMessage-Fullscreen.timeline differ diff --git a/AE/assets/layout/tablet/Notifications_ErrorMessage-PopUp.layout b/AE/assets/layout/tablet/Notifications_ErrorMessage-PopUp.layout new file mode 100644 index 0000000..81e4433 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_ErrorMessage-PopUp.layout differ diff --git a/AE/assets/layout/tablet/Notifications_ErrorMessage-PopUp.timeline b/AE/assets/layout/tablet/Notifications_ErrorMessage-PopUp.timeline new file mode 100644 index 0000000..89c3a04 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_ErrorMessage-PopUp.timeline differ diff --git a/AE/assets/layout/tablet/Notifications_ErrorMessage-PopUp2.layout b/AE/assets/layout/tablet/Notifications_ErrorMessage-PopUp2.layout new file mode 100644 index 0000000..536ab78 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_ErrorMessage-PopUp2.layout differ diff --git a/AE/assets/layout/tablet/Notifications_ErrorMessage-PopUp2.timeline b/AE/assets/layout/tablet/Notifications_ErrorMessage-PopUp2.timeline new file mode 100644 index 0000000..268f178 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_ErrorMessage-PopUp2.timeline differ diff --git a/AE/assets/layout/tablet/Notifications_Main.layout b/AE/assets/layout/tablet/Notifications_Main.layout new file mode 100644 index 0000000..e6decb3 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_Main.layout differ diff --git a/AE/assets/layout/tablet/Notifications_Main.timeline b/AE/assets/layout/tablet/Notifications_Main.timeline new file mode 100644 index 0000000..f1864c5 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_Main.timeline differ diff --git a/AE/assets/layout/tablet/Notifications_MainComp-Fullscreen-Error.layout b/AE/assets/layout/tablet/Notifications_MainComp-Fullscreen-Error.layout new file mode 100644 index 0000000..f027ba4 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_MainComp-Fullscreen-Error.layout differ diff --git a/AE/assets/layout/tablet/Notifications_MainComp-Fullscreen-Error.timeline b/AE/assets/layout/tablet/Notifications_MainComp-Fullscreen-Error.timeline new file mode 100644 index 0000000..2f34637 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_MainComp-Fullscreen-Error.timeline differ diff --git a/AE/assets/layout/tablet/Notifications_MainComp-Popup-Error-Long.layout b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Error-Long.layout new file mode 100644 index 0000000..4c6f066 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Error-Long.layout differ diff --git a/AE/assets/layout/tablet/Notifications_MainComp-Popup-Error-Long.timeline b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Error-Long.timeline new file mode 100644 index 0000000..ce0528e Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Error-Long.timeline differ diff --git a/AE/assets/layout/tablet/Notifications_MainComp-Popup-Error-Short.layout b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Error-Short.layout new file mode 100644 index 0000000..f511d85 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Error-Short.layout differ diff --git a/AE/assets/layout/tablet/Notifications_MainComp-Popup-Error-Short.timeline b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Error-Short.timeline new file mode 100644 index 0000000..6f311b2 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Error-Short.timeline differ diff --git a/AE/assets/layout/tablet/Notifications_MainComp-Popup-Favorite-Long.layout b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Favorite-Long.layout new file mode 100644 index 0000000..0d4c61a Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Favorite-Long.layout differ diff --git a/AE/assets/layout/tablet/Notifications_MainComp-Popup-Favorite-Long.timeline b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Favorite-Long.timeline new file mode 100644 index 0000000..ea333a6 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Favorite-Long.timeline differ diff --git a/AE/assets/layout/tablet/Notifications_MainComp-Popup-Favorite-Short.layout b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Favorite-Short.layout new file mode 100644 index 0000000..2048f25 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Favorite-Short.layout differ diff --git a/AE/assets/layout/tablet/Notifications_MainComp-Popup-Favorite-Short.timeline b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Favorite-Short.timeline new file mode 100644 index 0000000..96a642e Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Favorite-Short.timeline differ diff --git a/AE/assets/layout/tablet/Notifications_MainComp-Popup-General-Long.layout b/AE/assets/layout/tablet/Notifications_MainComp-Popup-General-Long.layout new file mode 100644 index 0000000..2492007 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_MainComp-Popup-General-Long.layout differ diff --git a/AE/assets/layout/tablet/Notifications_MainComp-Popup-General-Long.timeline b/AE/assets/layout/tablet/Notifications_MainComp-Popup-General-Long.timeline new file mode 100644 index 0000000..769914f Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_MainComp-Popup-General-Long.timeline differ diff --git a/AE/assets/layout/tablet/Notifications_MainComp-Popup-General-Short.layout b/AE/assets/layout/tablet/Notifications_MainComp-Popup-General-Short.layout new file mode 100644 index 0000000..17066ce Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_MainComp-Popup-General-Short.layout differ diff --git a/AE/assets/layout/tablet/Notifications_MainComp-Popup-General-Short.timeline b/AE/assets/layout/tablet/Notifications_MainComp-Popup-General-Short.timeline new file mode 100644 index 0000000..54c788f Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_MainComp-Popup-General-Short.timeline differ diff --git a/AE/assets/layout/tablet/Notifications_MainComp-Popup-Success-Long.layout b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Success-Long.layout new file mode 100644 index 0000000..0d16654 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Success-Long.layout differ diff --git a/AE/assets/layout/tablet/Notifications_MainComp-Popup-Success-Long.timeline b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Success-Long.timeline new file mode 100644 index 0000000..3aefd98 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Success-Long.timeline differ diff --git a/AE/assets/layout/tablet/Notifications_MainComp-Popup-Success-Short.layout b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Success-Short.layout new file mode 100644 index 0000000..793c29d Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Success-Short.layout differ diff --git a/AE/assets/layout/tablet/Notifications_MainComp-Popup-Success-Short.timeline b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Success-Short.timeline new file mode 100644 index 0000000..1799ab1 Binary files /dev/null and b/AE/assets/layout/tablet/Notifications_MainComp-Popup-Success-Short.timeline differ diff --git a/build/AndroidNative/assets/text/Notifications.json b/build/AndroidNative/assets/text/Notifications.json new file mode 100644 index 0000000..04d0241 --- /dev/null +++ b/build/AndroidNative/assets/text/Notifications.json @@ -0,0 +1,90 @@ +{ + "QUEST_AVAILABLE" : { + "type": "Success", + "title": "New Quest Available", + "message": "" + }, + + "QUEST_ACCEPTED" : { + "type": "Success", + "title": "Quest Accepted", + "message": "" + }, + + "QUEST_COMPLETED" : { + "type": "Success", + "title": "Quest Completed", + "message": "" + }, + + "QUEST_OBJECTIVE_COMPLETED" : { + "type": "Success", + "title": "Quest Objective Completed", + "message": "" + }, + + "APP_CONFIGURATION_ERROR" : { + "type": "Dialog", + "title": "App configuration failed", + "message": "There was a problem when the app tried to reach the server", + "action": "", + "dismiss": "" + }, + + "VSTB_SERVER_ERROR" : { + "type": "Dialog", + "title": "Server Error", + "message": "Please check your network and restart the application (%1)", + "action": "", + "dismiss": "" + }, + + "VIDEO_PLAYBACK_ERROR" : { + "type": "Error", + "title": "Error", + "message": "Video Playback Error: %1", + "autodismiss": false + }, + + "VIDEO_PLAYBACK_CHANNEL_AUTH_ERROR" : { + "type": "Error", + "title": "Channel Access Denied", + "message": "The active account does not have access to this content channel", + "autodismiss": false + }, + + "VIDEO_CONTENT_AUTH_LEVEL_ERROR" : { + "type": "Error", + "title": "Premium Content - Please Log In", + "message": "Please log in to a premium account to view this content", + "autodismiss": false + }, + + "NETWORK_CONNECTION_ERROR" : { + "type": "Error", + "title": "Network Connection Error", + "message": "Unable to reach the server" + }, + + "LOGOUT_CONFIRMATION" : { + "type": "Dialog", + "title": "Logout", + "message": "Are you sure you would like to logout of FoxPlay?", + "action": "OK", + "dismiss": "Cancel" + }, + + "LOGOUT_SUCCESS" : { + "type": "Success", + "title": "Logout succeeded", + "message": "Logout succeeded" + }, + + "LOGOUT_FAIL" : { + "type": "Error", + "title": "Logout failed", + "message": "Logout failed" + } +} + + diff --git a/build/YouiEngineManifest.xml b/build/YouiEngineManifest.xml index 2c8f697..c4d3a7d 100644 --- a/build/YouiEngineManifest.xml +++ b/build/YouiEngineManifest.xml @@ -4,6 +4,8 @@ + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f6b7008..8f6fce3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -59,6 +59,7 @@ source_group("app" REGULAR_EXPRESSION "app/.*") source_group("bridges" REGULAR_EXPRESSION "bridges/.*") source_group("customviews" REGULAR_EXPRESSION "customviews/.*") source_group("decoder" REGULAR_EXPRESSION "decoder/.*") +source_group("notification" REGULAR_EXPRESSION "notification/.*") source_group("quest" REGULAR_EXPRESSION "quest/.*") source_group("screen" REGULAR_EXPRESSION "screen/.*") source_group("utilities" REGULAR_EXPRESSION "utilities/.*") diff --git a/src/app/AppController.cpp b/src/app/AppController.cpp index 478d3c1..5ee2524 100644 --- a/src/app/AppController.cpp +++ b/src/app/AppController.cpp @@ -10,7 +10,8 @@ const YI_UINT64 APP_INIT_RETRY_TIMER_MS = 5000; AppController::AppController(CYIApp &rApp) : m_rApp(rApp) - , m_NavigationController(m_rApp) + , m_navigationController(m_rApp) + , m_notificationController(m_rApp) { BuildStateMachine(); } @@ -54,6 +55,8 @@ void AppController::ConfigInitStateEntered() { YI_LOGD(TAG, "ConfigInitStateEntered"); + m_notificationController.Init(); + TransitionFromConfigInitToRunning(); } @@ -66,7 +69,7 @@ void AppController::RunningStateEntered() { YI_LOGD(TAG, "RunningStateEntered"); - m_NavigationController.Start(NavigationController::SPLASH); + m_navigationController.Start(NavigationController::BOOK); } void AppController::RunningStateExited() diff --git a/src/app/AppController.h b/src/app/AppController.h index 4dac98b..c2842c3 100644 --- a/src/app/AppController.h +++ b/src/app/AppController.h @@ -1,6 +1,7 @@ #ifndef _APPCONTROLLER_H_ #define _APPCONTROLLER_H_ +#include "notification/NotificationController.h" #include "screen/NavigationController.h" #include @@ -19,8 +20,6 @@ class AppController : public CYISignalHandler private: void BuildStateMachine(); - - void ConfigInitStateEntered(); void ConfigInitStateExited(); void RunningStateEntered(); @@ -34,7 +33,8 @@ class AppController : public CYISignalHandler CYIStateMachine m_StateMachine; CYISignal<> TransitionFromConfigInitToRunning; - NavigationController m_NavigationController; + NavigationController m_navigationController; + NotificationController m_notificationController; YI_DISALLOW_COPY_AND_ASSIGN(AppController); }; diff --git a/src/app/LovecraftApp.cpp b/src/app/LovecraftApp.cpp index a53f565..1610c38 100644 --- a/src/app/LovecraftApp.cpp +++ b/src/app/LovecraftApp.cpp @@ -30,10 +30,6 @@ bool LovecraftApp::UserInit() AddTMXDecoder(); - TestsQuests(); - - //TestLoadingTMX(); - return true; } @@ -115,7 +111,14 @@ void LovecraftApp::SetApplicationPlatform(ApplicationConfiguration &applicationC bool LovecraftApp::UserStart() { - return m_pAppController->Start(); + if (m_pAppController->Start()) + { + TestsQuests(); + + //TestLoadingTMX(); + } + + return true; } void LovecraftApp::UserUpdate() @@ -125,17 +128,8 @@ void LovecraftApp::UserUpdate() void LovecraftApp::TestsQuests() const { - //TMX loading test - tmxparser::TmxReturn error; - tmxparser::TmxMap map; - - // test from file CYIString assetPath = GetAssetsPath(); - CYIString questsPath = assetPath + "resources/" + "Quests.json"; - CYIString levelPath = assetPath + "resources/" + "test_xml_level.tmx"; - - error = tmxparser::parseFromFile(levelPath.GetData(), &map, assetPath.GetData()); QuestManager* questManager = new QuestManager(questsPath); @@ -146,6 +140,17 @@ void LovecraftApp::TestsQuests() const void LovecraftApp::TestLoadingTMX() { + //TMX loading test + tmxparser::TmxReturn error; + tmxparser::TmxMap map; + + // test from file + CYIString assetPath = GetAssetsPath(); + + CYIString levelPath = assetPath + "resources/" + "test_xml_level.tmx"; + + error = tmxparser::parseFromFile(levelPath.GetData(), &map, assetPath.GetData()); + CYIAssetLoader *pAssetLoader = CYIFramework::GetInstance()->GetAssetLoader(); CYISharedPtr pAsset = pAssetLoader->Load(YiGetTypeId(), "drawable/default/test_xml_level.tmx", YI_NULL); @@ -193,11 +198,6 @@ void LovecraftApp::TestQuestProgression(QuestManager* quest_manager) YI_LOGI("LovecraftApp::TestQuestProgression", "After saving the advisor: \n%s", quest_manager->GetAllQuestsDisplayText().GetData()); - //After saving the advisor - quest_manager->ActivateCondition(CYIString("rescue:maincharacter:chiefadvisor")); - - YI_LOGI("LovecraftApp::TestQuestProgression", "After saving the advisor: \n%s", quest_manager->GetAllQuestsDisplayText().GetData()); - //After the scientist transcends quest_manager->ActivateCondition(CYIString("state:head_scientist:transcended")); diff --git a/src/customviews/FullScreenNotificationView.cpp b/src/customviews/FullScreenNotificationView.cpp new file mode 100644 index 0000000..39c155c --- /dev/null +++ b/src/customviews/FullScreenNotificationView.cpp @@ -0,0 +1,66 @@ +#include "customviews/FullScreenNotificationView.h" + +#include "utilities/NodeUtilities.h" + +#include +#include + +const CYIString TAG("FullScreenNotificationView.h"); + +YI_RTTI_DEF1_INST(FullScreenNotificationView, "FullScreenNotificationView", CYISceneView) + +FullScreenNotificationView::FullScreenNotificationView() +{ +}; + +FullScreenNotificationView::~FullScreenNotificationView() +{ +}; + +bool FullScreenNotificationView::Init() +{ + return NotificationView::Init(); +} + + +void FullScreenNotificationView::ConnectButtons() +{ + Utility::GetNode(this, "Btn-Action1")->ButtonReleased.Connect(*this, &FullScreenNotificationView::DoAction); + Utility::GetNode(this, "Btn-Action2")->ButtonReleased.Connect(*this, &FullScreenNotificationView::DoDismiss); +} + +void FullScreenNotificationView::DoAction() +{ + Actioned(this); +} + +void FullScreenNotificationView::DoDismiss() +{ + NotificationView::DoDismiss(); +} + +void FullScreenNotificationView::SetActionButtonText(const CYIString &text) +{ + SetButtonText("Btn-Action1", text); +} + +void FullScreenNotificationView::SetDismissButtonText(const CYIString &text) +{ + SetButtonText("Btn-Action2", text); +} + +void FullScreenNotificationView::SetButtonText(const CYIString &button, const CYIString &text) +{ + CYIPushButtonView *pButton = Utility::GetNode(this, button); + + if(text.IsNotEmpty()) + { + pButton->Show(); + pButton->SetText(text); + Utility::GetNode(pButton, "Placeholder-Title")->SetText(text); + } + else + { + pButton->Hide(); + } +} diff --git a/src/customviews/FullScreenNotificationView.h b/src/customviews/FullScreenNotificationView.h new file mode 100644 index 0000000..ca0766d --- /dev/null +++ b/src/customviews/FullScreenNotificationView.h @@ -0,0 +1,44 @@ +#ifndef _FULLSCREEN_NOTIFICATION_VIEW_H_ +#define _FULLSCREEN_NOTIFICATION_VIEW_H_ + +#include "customviews/NotificationView.h" + +/*! + \Template for a After Effects composition representing a full screen notification. + + Full Screen Notification Template Specification + + | Type | Labels | Property | Description | + | :-------- | :----------------------- | :---------------: | :--------------------------------------------------------------- | + | Marker | In | Required | representing the animations to open the full screen notification | + | Marker | Out | Required | representing the animations to close the full screen notification | + | Node | Btn-Action1 | Required | When pressed, the signal Actioned() is emitted | + | Node | Btn-Action2 | Required | When pressed, the signal Dismissed() is emitted | + */ + +class FullScreenNotificationView : public NotificationView +{ +public: + FullScreenNotificationView(); + virtual ~FullScreenNotificationView(); + + virtual bool Init(); + + void SetActionButtonText(const CYIString &text); + void SetDismissButtonText(const CYIString &text); + + void ConnectButtons(); + + void DoAction(); + void DoDismiss(); + + CYISignal Actioned; + +private: + void SetButtonText(const CYIString &button, const CYIString &text); + + YI_DISALLOW_COPY_AND_ASSIGN(FullScreenNotificationView) + YI_TYPE_DATA +}; + +#endif // _FULLSCREEN_NOTIFICATION_VIEW_H_ diff --git a/src/customviews/NotificationView.cpp b/src/customviews/NotificationView.cpp new file mode 100644 index 0000000..a4d3c00 --- /dev/null +++ b/src/customviews/NotificationView.cpp @@ -0,0 +1,99 @@ +#include "customviews/NotificationView.h" + +#include "utilities/NodeUtilities.h" +#include "utilities/TimelineUtilities.h" + +#include +#include +#include + +const CYIString TAG("NotificationView"); + +YI_RTTI_DEF1_INST(NotificationView, "NotificationView", CYISceneView) + +NotificationView::NotificationView() +{ +} + +NotificationView::~NotificationView() +{ +} + +bool NotificationView::Init() +{ + bool bOK = CYISceneView::Init(); + + if (bOK) + { + CYITimelineGroup *pOffTimeline = TimelineUtilities::RecursiveCreateNodeParallelTimelineGroup(this, "Out"); + CYITimelineGroup *pOnTimeline = TimelineUtilities::RecursiveCreateNodeParallelTimelineGroup(this, "In"); + + m_diplayAnimationController.SetTimelines(pOnTimeline, pOffTimeline, CYIAnimationToggleController::SHARED); + m_diplayAnimationController.ResetToState(CYIAnimationToggleController::OFF); + + pOffTimeline->Completed.Connect(*this, &NotificationView::AnimationdOutEnd); + } + + return bOK; +} + +void NotificationView::SetSceneName(const CYIString &sceneName) +{ + m_sceneName = sceneName; +} + +const CYIString &NotificationView::GetSceneName() const +{ + return m_sceneName; +} + +void NotificationView::SetTitle(const CYIString &text) +{ + SetMessageText("Placeholder-Title", text); +} + +void NotificationView::SetMessage(const CYIString &text) +{ + SetMessageText("Placeholder-Description", text); +} + +void NotificationView::ShowOverlay() +{ + m_diplayAnimationController.ToggleOn(); +} + +void NotificationView::HideOverlay() +{ + m_diplayAnimationController.ToggleOff(); +} + +bool NotificationView::IsOverlayShown() +{ + return m_diplayAnimationController.GetState() == CYIAnimationToggleController::ON; +} + +void NotificationView::DoDismiss() +{ + Dismissed(this); +} + +void NotificationView::AnimationdOutEnd() +{ + AnimationdOutEnded(this); +} + +void NotificationView::SetMessageText(const CYIString &textField, const CYIString &text) +{ + CYISceneView *pMessage = Utility::GetNode(this, "Message", Utility::GET_NODE_FLAG_OPTIONAL); + + if (pMessage != YI_NULL) + { + CYITextSceneNode *pMessagePopup = Utility::GetNode(pMessage, textField); + + if (pMessagePopup != YI_NULL) + { + pMessagePopup->SetText(text); + } + } +} + diff --git a/src/customviews/NotificationView.h b/src/customviews/NotificationView.h new file mode 100644 index 0000000..df8480a --- /dev/null +++ b/src/customviews/NotificationView.h @@ -0,0 +1,54 @@ +#ifndef _NOTOFICATION_VIEW_H_ +#define _NOTOFICATION_VIEW_H_ + +#include +#include + +/*! + \Template for a After Effects composition representing a notification. + Base class for full screen and popup notifications brief + + Notification Template Specification + + | Type | Labels | Property | Description | + | :-------- | :----------------------- | :---------------: | :----------------------------------------------------------- | + | Node | Placeholder-Title | Required | ill contain the notification-specified message title | + | Node | Placeholder-Description | Required | ill contain the notification-specified message description | + */ + +class NotificationView : public CYISceneView +{ +public: + NotificationView(); + virtual ~NotificationView(); + + virtual bool Init(); + + void SetSceneName(const CYIString &sceneName); + const CYIString &GetSceneName() const; + + void SetTitle(const CYIString &text); + void SetMessage(const CYIString &text); + + void ShowOverlay(); + void HideOverlay(); + bool IsOverlayShown(); + + CYISignal Dismissed; + CYISignal AnimationdOutEnded; + +protected: + void DoDismiss(); + void AnimationdOutEnd(); + +private: + void SetMessageText(const CYIString &textField, const CYIString &text); + + CYIString m_sceneName; + CYIAnimationToggleController m_diplayAnimationController; + + YI_DISALLOW_COPY_AND_ASSIGN(NotificationView) + YI_TYPE_DATA +}; + +#endif // _NOTOFICATION_VIEW_H_ \ No newline at end of file diff --git a/src/customviews/PopupNotificationView.cpp b/src/customviews/PopupNotificationView.cpp new file mode 100644 index 0000000..c77621f --- /dev/null +++ b/src/customviews/PopupNotificationView.cpp @@ -0,0 +1,49 @@ +#include "customviews/PopupNotificationView.h" + +#include "utilities/NodeUtilities.h" + +#include +#include + +const CYIString TAG("PopupNotificationView.h"); + +YI_RTTI_DEF1_INST(PopupNotificationView, "PopupNotificationView", CYISceneView) + +PopupNotificationView::PopupNotificationView() +{ +}; + +PopupNotificationView::~PopupNotificationView() +{ +}; + +bool PopupNotificationView::Init() +{ + return NotificationView::Init(); +} + +void PopupNotificationView::SetShortTitle(const CYIString &text) +{ + CYITextSceneNode *pTitle = Utility::GetNode(this, "Placeholder-Title"); + + if (pTitle != YI_NULL) + { + pTitle->SetText(text); + } +} + +void PopupNotificationView::ConnectButtons() +{ + CYIPushButtonView *pCloseButton = Utility::GetNode(this, "Btn-Close", Utility::GET_NODE_FLAG_OPTIONAL); + + if(pCloseButton) + { + pCloseButton->ButtonReleased.Connect(*this, &PopupNotificationView::DoDismiss); + } +} + +void PopupNotificationView::DoDismiss() +{ + NotificationView::DoDismiss(); +} + diff --git a/src/customviews/PopupNotificationView.h b/src/customviews/PopupNotificationView.h new file mode 100644 index 0000000..9cfff8b --- /dev/null +++ b/src/customviews/PopupNotificationView.h @@ -0,0 +1,38 @@ +#ifndef _POPUP_NOTIFICATION_VIEW_H_ +#define _POPUP_NOTIFICATION_VIEW_H_ + +#include "customviews/NotificationView.h" + +/*! + \Template for a After Effects composition representing a popup notification. + + Popup Notification Template Specification + + | Type | Labels | Property | Description | + | :-------- | :----------------------- | :---------------: | :--------------------------------------------------------------- | + | Marker | In | Required | representing the animations to open the full screen notification | + | Marker | Out | Required | representing the animations to close the full screen notification | + | Node | Btn-Close | Required | When pressed, the signal Dismissed() is emitted | + */ + +class PopupNotificationView : public NotificationView +{ +public: + PopupNotificationView(); + virtual ~PopupNotificationView(); + + virtual bool Init(); + + void SetShortTitle(const CYIString &text); + + void ConnectButtons(); + + void DoDismiss(); + +private: + YI_DISALLOW_COPY_AND_ASSIGN(PopupNotificationView) + YI_TYPE_DATA +}; + +#endif /* _POPUP_NOTIFICATION_VIEW_H_ */ + diff --git a/src/list/ListItem.cpp b/src/list/ListItem.cpp new file mode 100644 index 0000000..519dd8c --- /dev/null +++ b/src/list/ListItem.cpp @@ -0,0 +1,156 @@ +#include "list/ListItem.h" + +#include "list/ListViewDelegate.h" +#include "list/ListView.h" + +#include + +static const CYIString TAG = "ListItem"; + +ListItem::ListItem(const CYIString &viewTemplateName) +{ + YI_ASSERT(viewTemplateName.IsNotEmpty(), TAG, "Invalid view template name"); + + SetListItemTemplate(CYIViewTemplate::GetViewTemplate(viewTemplateName)); +} + +ListItem::ListItem(const CYIString &viewTemplateName, YI_INT32 nColumnSpan, YI_INT32 nRowSpan) +{ + YI_ASSERT(viewTemplateName.IsNotEmpty(), TAG, "Invalid view template name"); + YI_ASSERT(nColumnSpan >= WIDTH_AS_COLUMN_SPAN, TAG, "Invalid column span"); + YI_ASSERT(nRowSpan >= HEIGHT_AS_ROW_SPAN, TAG, "Invalid row span"); + + CYISharedPtr pViewTemplate = CYIViewTemplate::GetViewTemplate(viewTemplateName); + + YI_ASSERT(pViewTemplate, TAG, "Invalid view template"); + + SetListItemTemplate(pViewTemplate); + + if (nColumnSpan == WIDTH_AS_COLUMN_SPAN) + { + nColumnSpan = (YI_INT32)pViewTemplate->GetTemplate()->GetWidth(); + } + + if (nRowSpan == HEIGHT_AS_ROW_SPAN) + { + nRowSpan = (YI_INT32)pViewTemplate->GetTemplate()->GetHeight(); + } + + SetCellsRect(YI_RECT_REL(0, 0, nColumnSpan, nRowSpan)); +} + +ListItem::~ListItem() +{ +} + +CYISceneView *ListItem::CreateView(CYISceneManager *pSceneManager) +{ + CYISceneView *pView = CYIListItem::CreateView(pSceneManager); + + SetFocusable(TimelineUtilities::HasViewFocusInTimelines(pView)); + + return pView; +} + +ListView *ListItem::GetListView() const +{ + return YiDynamicCast(CYIListItem::GetListView()); +} + +YI_INT32 ListItem::GetSectionIndex() const +{ + return GetListView()->GetExpandedIndices(GetIndexInList()).first; +} + +YI_INT32 ListItem::GetIndexInSection() const +{ + return GetListView()->GetExpandedIndices(GetIndexInList()).second; +} + +const CYIAny ListItem::GetData() const +{ + return m_data; +} + +void ListItem::SetData(const CYIAny &data) +{ + m_data = data; +} + +void ListItem::OnLoadIn() +{ + CYIListItem::OnLoadIn(); + + ListView *pListView = GetListView(); + ListViewDelegate *pDelegate = YI_NULL; + if (pListView && (pDelegate = pListView->m_pDelegate)) + { + pDelegate->HandleLoadInForListItem(this); + } +} + +void ListItem::OnLoadOut() +{ + CYIListItem::OnLoadOut(); + + ListView *pListView = GetListView(); + ListViewDelegate *pDelegate = YI_NULL; + if (pListView && (pDelegate = pListView->m_pDelegate)) + { + pDelegate->HandleLoadOutForListItem(this); + + if (pDelegate->ShouldDeleteViewOnLoadOutForListItem(this)) + { + delete m_pView; + m_pView = YI_NULL; + } + } +} + +void ListItem::OnStreamIn() +{ + CYIListItem::OnStreamIn(); + + ListView *pListView = GetListView(); + ListViewDelegate *pDelegate = YI_NULL; + if (pListView && (pDelegate = pListView->m_pDelegate)) + { + pDelegate->HandleStreamInForListItem(this); + } +} + +void ListItem::OnStreamOut() +{ + CYIListItem::OnStreamOut(); + + ListView *pListView = GetListView(); + ListViewDelegate *pDelegate = YI_NULL; + if (pListView && (pDelegate = pListView->m_pDelegate)) + { + pDelegate->HandleStreamOutForListItem(this); + } +} + +void ListItem::OnVisibleIn() +{ + CYIListItem::OnVisibleIn(); + + ListView *pListView = GetListView(); + ListViewDelegate *pDelegate = YI_NULL; + if (pListView && (pDelegate = pListView->m_pDelegate)) + { + pDelegate->HandleVisibleInForListItem(this); + } +} + +void ListItem::OnVisibleOut() +{ + CYIListItem::OnVisibleOut(); + + ListView *pListView = GetListView(); + ListViewDelegate *pDelegate = YI_NULL; + if (pListView && (pDelegate = pListView->m_pDelegate)) + { + pDelegate->HandleVisibleOutForListItem(this); + } +} diff --git a/src/list/ListItem.h b/src/list/ListItem.h new file mode 100644 index 0000000..54635b2 --- /dev/null +++ b/src/list/ListItem.h @@ -0,0 +1,80 @@ +#ifndef _LIST_ITEM_H_ +#define _LIST_ITEM_H_ + +#include +#include "list/ListItem.h" + +#include + +class ListView; +class ListViewDelegate; + +class ListItem : public CYIListItem +{ + friend class ListView; + +public: + + enum + { + WIDTH_AS_COLUMN_SPAN = -1, + HEIGHT_AS_ROW_SPAN = -1 + }; + + /*! + \details Constructs a list item using the view template with the given name. + */ + ListItem(const CYIString &viewTemplateName); + + /*! + \details Constructs a list item using the view template with the + given name and spanning the given number of columns and rows. + */ + ListItem(const CYIString &viewTemplateName, YI_INT32 nColumnSpan, YI_INT32 nRowSpan); + + virtual ~ListItem(); + + /*! + \details Returns the item's list. + */ + ListView *GetListView() const; + + /*! + \details Returns the section the item belongs to. + */ + YI_INT32 GetSectionIndex() const; + + /*! + \details Returns the index of the item in the section it belongs to. + */ + YI_INT32 GetIndexInSection() const; + + /*! + \details Returns the data. + */ + const CYIAny GetData() const; + + /*! + \details Sets the data. + */ + void SetData(const CYIAny &data); + +protected: + + CYISceneView *CreateView(CYISceneManager *pSceneManager); + virtual void OnLoadIn(); + virtual void OnLoadOut(); + virtual void OnVisibleIn(); + virtual void OnVisibleOut(); + virtual void OnStreamIn(); + virtual void OnStreamOut(); + +private: + + CYIAny m_data; + + YI_DISALLOW_COPY_AND_ASSIGN(ListItem) +}; + +#endif // _DELEGATING_LIST_ITEM_H_ + diff --git a/src/list/ListView.cpp b/src/list/ListView.cpp new file mode 100644 index 0000000..c6d215f --- /dev/null +++ b/src/list/ListView.cpp @@ -0,0 +1,256 @@ +#include "list/ListView.h" + +#include "list/ListItem.h" +#include "utilities/NodeUtilities.h" + +#include + +static const CYIString TAG = "ListView"; +static const YI_FLOAT s_nScrollThresholdScreenPercentage = 0.03f; // Specifies the vertical scroll threshold by a percentage amount of the screen height + +YI_RTTI_DEF1_INST(ListView, "ListView", CYIListView) + +ListView::ListView() + : m_nColumnCount(1) + , m_pDelegate(YI_NULL) + , m_fStreamRangeFactor(2.0f) + , m_bFocusFirstListItem(false) +{ + AddSection(); + + SetVisibleRangeDisabled(); +} + +ListView::~ListView() +{ + m_pDelegate = YI_NULL; +} + +bool ListView::Init() +{ + if (!CYIListView::Init()) + { + return false; + } + + YI_INT32 nColumnCount = 1; + + if (Utility::GetProperty(this, "columns", nColumnCount) && nColumnCount >= 1) + { + m_nColumnCount = nColumnCount; + } + + m_nScrollThreshold = (YI_INT32)(GetSize().y * s_nScrollThresholdScreenPercentage); + + return true; +} + +ListViewDelegate *ListView::GetDelegate() const +{ + return m_pDelegate; +} + +void ListView::SetDelegate(ListViewDelegate *pDelegate) +{ + m_pDelegate = pDelegate; +} + +bool ListView::IsEmpty() const +{ + return GetListItemCount() == 0; +} + +bool ListView::IsNotEmpty() const +{ + return !IsEmpty(); +} + +YI_INT32 ListView::GetColumnCount() const +{ + return m_nColumnCount; +} + +YI_INT32 ListView::GetSectionCount() const +{ + return static_cast(m_sectionsListItemCount.size()); +} + +YI_INT32 ListView::GetItemCountInSection(YI_INT32 nSectionIndex) const +{ + YI_ASSERT(IsSectionIndexValid(nSectionIndex, ACCESS), TAG, "Invalid section index"); + + return m_sectionsListItemCount.at(nSectionIndex); +} + +ListItem *ListView::GetItemInSection(YI_INT32 nSectionIndex, YI_INT32 nItemIndex) const +{ + YI_ASSERT(IsItemIndexValid(nSectionIndex, nItemIndex, ACCESS), TAG, "Invalid item or section index"); + + return static_cast(GetListItem(GetCollapsedIndex(nSectionIndex, nItemIndex))); +} + +ListItem *ListView::GetFirstItemInSection(YI_INT32 nSectionIndex) const +{ + return GetItemInSection(nSectionIndex, 0); +} + +ListItem *ListView::GetLastItemInSection(YI_INT32 nSectionIndex) const +{ + return GetItemInSection(nSectionIndex, GetItemCountInSection(nSectionIndex) - 1); +} + +void ListView::AddSection() +{ + m_sectionsListItemCount.push_back(0); +} + +void ListView::InsertSection(YI_INT32 nSectionIndex) +{ + YI_ASSERT(IsSectionIndexValid(nSectionIndex, INSERT), TAG, "Invalid section index"); + + m_sectionsListItemCount.insert(m_sectionsListItemCount.begin() + nSectionIndex, 0); +} + +void ListView::ClearSection(YI_INT32 nSectionIndex, bool bAnimate) +{ + YI_ASSERT(IsSectionIndexValid(nSectionIndex, ACCESS), TAG, "Invalid section index"); + + const YI_INT32 nCollapsedIndex = GetCollapsedIndex(nSectionIndex, 0); + + for (YI_INT32 nItemIndex = m_sectionsListItemCount.at(nSectionIndex) - 1; nItemIndex >= 0; --nItemIndex) + { + Remove(nCollapsedIndex + nItemIndex, bAnimate); + } + + m_sectionsListItemCount[nSectionIndex] = 0; +} + +void ListView::RemoveSection(YI_INT32 nSectionIndex, bool bAnimate) +{ + YI_ASSERT(IsSectionIndexValid(nSectionIndex, ACCESS), TAG, "Invalid section index"); + + ClearSection(nSectionIndex, bAnimate); + + m_sectionsListItemCount.erase(m_sectionsListItemCount.begin() + nSectionIndex); +} + +bool ListView::RequestFocus(CYISceneView::FOCUS_DIRECTION eDirection, const CYIAABB &previousFocusRect) +{ + if (eDirection == FOCUS_DOWN && m_bFocusFirstListItem) + { + if (GetListItemCount() > 0) + { + GetFirstVisibleItem()->GetView()->RequestFocus(); + + return true; + } + } + + return CYIListView::RequestFocus(eDirection, previousFocusRect); +} + +void ListView::Add(ListItem *pItem, YI_INT32 nSectionIndex, bool bAnimate) +{ + YI_ASSERT(IsSectionIndexValid(nSectionIndex, ACCESS), TAG, "Invalid section index"); + + SetStreamRangeFactor(pItem, m_fStreamRangeFactor); + + Insert(pItem, nSectionIndex, m_sectionsListItemCount.at(nSectionIndex), bAnimate); +} + +void ListView::Insert(ListItem *pItem, YI_INT32 nSectionIndex, YI_INT32 nItemIndex, bool bAnimate) +{ + YI_ASSERT(IsItemIndexValid(nSectionIndex, nItemIndex, INSERT), TAG, "Invalid item or section index"); + + const YI_INT32 nCollapsedIndex = GetCollapsedIndex(nSectionIndex, nItemIndex); + + CYIListView::Insert(pItem, nCollapsedIndex, bAnimate); + + m_sectionsListItemCount[nSectionIndex] += 1; +} + +void ListView::Remove(YI_INT32 nSectionIndex, YI_INT32 nItemIndex, bool bAnimate) +{ + YI_ASSERT(IsItemIndexValid(nSectionIndex, nItemIndex, ACCESS), TAG, "Invalid item or section index"); + + const YI_INT32 nCollapsedIndex = GetCollapsedIndex(nSectionIndex, nItemIndex); + + CYIListView::Remove(nCollapsedIndex, bAnimate); + + m_sectionsListItemCount[nSectionIndex] -= 1; +} + +bool ListView::IsSectionIndexValid(YI_INT32 nSectionIndex, INDEX_USED_FOR eIndexUsedFor) const +{ + return nSectionIndex >= 0 && (nSectionIndex < GetSectionCount() + (eIndexUsedFor == INSERT ? 1 : 0)); +} + +bool ListView::IsItemIndexValid(YI_INT32 nSectionIndex, YI_INT32 nItemIndex, INDEX_USED_FOR eIndexUsedFor) const +{ + return IsSectionIndexValid(nSectionIndex, ACCESS) && (nItemIndex >= 0 && nItemIndex < m_sectionsListItemCount.at(nSectionIndex) + (eIndexUsedFor == INSERT ? 1 : 0)); +} + +YI_INT32 ListView::GetCollapsedIndex(YI_INT32 nSectionIndex, YI_INT32 nItemIndex) const +{ + YI_INT32 nCollapsedIndex = nItemIndex; + + for (--nSectionIndex; nSectionIndex >= 0; --nSectionIndex) + { + nCollapsedIndex += m_sectionsListItemCount.at(nSectionIndex); + } + return nCollapsedIndex; +} + +std::pair ListView::GetExpandedIndices(YI_INT32 nCollapsedIndex) const +{ + for (YI_INT32 nSectionIndex = 0; nSectionIndex < GetSectionCount(); ++nSectionIndex) + { + nCollapsedIndex -= m_sectionsListItemCount.at(nSectionIndex); + + if (nCollapsedIndex < 0) + { + return std::make_pair(nSectionIndex, m_sectionsListItemCount.at(nSectionIndex) + nCollapsedIndex); + } + } + return std::make_pair(-1, -1); +} + +void ListView::SetStreamRangeFactor(YI_FLOAT fStreamRangeFactor) +{ + if (glm::epsilonNotEqual(m_fStreamRangeFactor, fStreamRangeFactor, glm::epsilon())) + { + m_fStreamRangeFactor = fStreamRangeFactor; + + const YI_INT32 nListItemCount = GetListItemCount(); + + if (nListItemCount > 0) + { + for (YI_INT32 nItemIndex = 0; nItemIndex < nListItemCount; ++nItemIndex) + { + SetStreamRangeFactor(GetListItem(nItemIndex), fStreamRangeFactor); + } + UpdateContents(); + } + } +} + +void ListView::SetStreamRangeFactor(CYIListItem *pItem, YI_FLOAT fStreamRangeFactor) +{ + pItem->SetLoadRangeFactor(fStreamRangeFactor); + pItem->SetStreamingRangeFactor(fStreamRangeFactor); +} + +YI_FLOAT ListView::GetStreamRangeFactor() const +{ + return m_fStreamRangeFactor; +} + +void ListView::SetFocusOnFirstListItem(bool bFocusFirstListItem) +{ + m_bFocusFirstListItem = bFocusFirstListItem; +} + +bool ListView::GetFocusOnFirstListItem() const +{ + return m_bFocusFirstListItem; +} diff --git a/src/list/ListView.h b/src/list/ListView.h new file mode 100644 index 0000000..fc2fa1b --- /dev/null +++ b/src/list/ListView.h @@ -0,0 +1,184 @@ +#ifndef _LIST_VIEW_H_ +#define _LIST_VIEW_H_ + +#include + +class ListItem; +class ListViewDelegate; + +class ListView : public CYIListView +{ + friend class ListItem; + +public: + + ListView(); + virtual ~ListView(); + + /*! + \details Initialize ListView + */ + bool Init(); + + /*! + \details Returns the delegate. + */ + ListViewDelegate *GetDelegate() const; + + /*! + \details Sets the delegate. + */ + void SetDelegate(ListViewDelegate *pDelegate); + + /*! + \details Returns true if the list is empty. + */ + bool IsEmpty() const; + + /*! + \details Returns true if the list is not empty. + */ + bool IsNotEmpty() const; + + /*! + \details Returns the number of columns. + */ + YI_INT32 GetColumnCount() const; + + /*! + \details Returns the number of sections. + */ + YI_INT32 GetSectionCount() const; + + /*! + \details Returns the number of items in the given section. + */ + YI_INT32 GetItemCountInSection(YI_INT32 nSectionIndex) const; + + /*! + \details Returns the item at the given index in the given section. + */ + ListItem *GetItemInSection(YI_INT32 nSectionIndex, YI_INT32 nItemIndex) const; + + /*! + \details Returns the first item in the given section. + */ + ListItem *GetFirstItemInSection(YI_INT32 nSectionIndex) const; + + /*! + \details Returns the last item in the given section. + */ + ListItem *GetLastItemInSection(YI_INT32 nSectionIndex) const; + + /*! + \details Adds a section to the end of the list. + */ + void AddSection(); + + /*! + \details Inserts a section at the given index. + */ + void InsertSection(YI_INT32 nSectionIndex); + + /*! + \details Removes all list items from the section at the given index. + */ + void ClearSection(YI_INT32 nSectionIndex, bool bAnimate); + + /*! + \details Removes the section at the given index. + */ + void RemoveSection(YI_INT32 nSectionIndex, bool bAnimate); + + /*! + \details Adds the given item to the given section. + */ + void Add(ListItem *pItem, YI_INT32 nSectionIndex, bool bAnimate); + + /*! + \details Inserts the given item at the given index in the given section. + */ + void Insert(ListItem *pItem, YI_INT32 nSectionIndex, YI_INT32 nItemIndex, bool bAnimate); + + /*! + \details Removes the item at the given in index in the given section. + */ + void Remove(YI_INT32 nSectionIndex, YI_INT32 nItemIndex, bool bAnimate); + + /*! + \details Sets the stream range factor to the given factor. + */ + void SetStreamRangeFactor(YI_FLOAT fStreamRangeFactor); + + /*! + \details Returns the stream range factor. + */ + YI_FLOAT GetStreamRangeFactor() const; + + /*! + \details Custom focus management so we can handle focusing the first item with certain scenarios. + This new behavior is currently using m_bFocusFirstListItem flag. + Otherwise, the list behaves normally. + */ + virtual bool RequestFocus(CYISceneView::FOCUS_DIRECTION eDirection, const CYIAABB &previousFocusRect); + + /*! + \details This allows to change the default list focus behavior. + When set, m_bFocusFirstListItem will cause the list to focus the first list item instead of the closest item. + */ + void SetFocusOnFirstListItem(bool bFocusFirstListItem); + + /*! + \see SetFocusOnFirstListItem + */ + bool GetFocusOnFirstListItem() const; + +protected: + + /*! + \details Hiding CYIListView::Add in favour of the section based Add. + */ + using CYIListView::Add; + + /*! + \details Hiding CYIListView::Insert in favour of the section based Insert. + */ + using CYIListView::Insert; + + /*! + \details Hiding CYIListView::Remove in favour of the section based Remove. + */ + using CYIListView::Remove; + +private: + + enum INDEX_USED_FOR + { + ACCESS, + INSERT + }; + + static void SetStreamRangeFactor(CYIListItem *pItem, YI_FLOAT fStreamRangeFactor); + bool IsSectionIndexValid(YI_INT32 nSectionIndex, INDEX_USED_FOR eIndexUsedFor) const; + bool IsItemIndexValid(YI_INT32 nSectionIndex, YI_INT32 nItemIndex, INDEX_USED_FOR eIndexUsedFor) const; + YI_INT32 GetCollapsedIndex(YI_INT32 nSectionIndex, YI_INT32 nItemIndex) const; + std::pair GetExpandedIndices(YI_INT32 nCollapsedIndex) const; + + YI_INT32 m_nColumnCount; + + ListViewDelegate *m_pDelegate; + + std::vector m_sectionsListItemCount; + + YI_FLOAT m_fStreamRangeFactor; + +private: + bool m_bFocusFirstListItem; + + YI_DISALLOW_COPY_AND_ASSIGN(ListView) + + YI_TYPE_DATA +}; + +#endif // _LIST_VIEW_H_ + diff --git a/src/list/ListViewDelegate.cpp b/src/list/ListViewDelegate.cpp new file mode 100644 index 0000000..07b9714 --- /dev/null +++ b/src/list/ListViewDelegate.cpp @@ -0,0 +1,38 @@ +#include "list/ListViewDelegate.h" + +ListViewDelegate::ListViewDelegate() +{ +} + +ListViewDelegate::~ListViewDelegate() +{ +} + +void ListViewDelegate::HandleStreamInForListItem(ListItem *) +{ +} + +void ListViewDelegate::HandleStreamOutForListItem(ListItem *) +{ +} + +void ListViewDelegate::HandleLoadInForListItem(ListItem *) +{ +} + +void ListViewDelegate::HandleLoadOutForListItem(ListItem *) +{ +} + +void ListViewDelegate::HandleVisibleInForListItem(ListItem *) +{ +} + +void ListViewDelegate::HandleVisibleOutForListItem(ListItem *) +{ +} + +bool ListViewDelegate::ShouldDeleteViewOnLoadOutForListItem(ListItem *) +{ + return false; +} diff --git a/src/list/ListViewDelegate.h b/src/list/ListViewDelegate.h new file mode 100644 index 0000000..a6924f3 --- /dev/null +++ b/src/list/ListViewDelegate.h @@ -0,0 +1,54 @@ +#ifndef _LIST_VIEW_DELEGATE_H_ +#define _LIST_VIEW_DELEGATE_H_ + +#include +#include + +class ListItem; + +class ListViewDelegate +{ + +public: + ListViewDelegate(); + virtual ~ListViewDelegate(); + + /*! + \details Reimplement to handle stream in for the given list item. + */ + virtual void HandleStreamInForListItem(ListItem *pItem); + + /*! + \details Reimplement to handle stream out for the given list item. + */ + virtual void HandleStreamOutForListItem(ListItem *pItem); + + /*! + \details Reimplement to handle stream in for the given list item. + */ + virtual void HandleLoadInForListItem(ListItem *pItem); + + /*! + \details Reimplement to handle stream out for the given list item. + */ + virtual void HandleLoadOutForListItem(ListItem *pItem); + + /*! + \details Reimplement to handle stream in for the given list item. + */ + virtual void HandleVisibleInForListItem(ListItem *pItem); + + /*! + \details Reimplement to handle stream out for the given list item. + */ + virtual void HandleVisibleOutForListItem(ListItem *pItem); + + /*! + \details Reimplement and return true to delete the list item's view when the item is unloaded. + */ + virtual bool ShouldDeleteViewOnLoadOutForListItem(ListItem *pItem); + +}; + +#endif // _LIST_VIEW_DELEGATE_H_ + diff --git a/src/messages/Message.h b/src/messages/Message.h new file mode 100644 index 0000000..d6c4409 --- /dev/null +++ b/src/messages/Message.h @@ -0,0 +1,75 @@ +#ifndef _MESSAGE_H_ +#define _MESSAGE_H_ + +#include + +template +class Message +{ + +public: + + /*! + \details Constructs a message with the given data. + */ + Message(const DataType &rData); + + /*! + \details Constructs a message with data constructed with the given argument. + */ + template + Message(const ArgType &rArg); + + /*! + \details Constructs a message with data constructed with the given arguments. + */ + template + Message(const Arg1Type &rArg1, const Arg2Type &rArg2); + + /*! + \details Constructs a message with data constructed with the given arguments. + */ + template + Message(const Arg1Type &rArg1, const Arg2Type &rArg2, const Arg3Type &rArg3); + + /*! + \details Destructor. + */ + virtual ~Message(); + + /*! + \details Subscribes the given object's function to this message. + */ + template + static void Subscribe(ObjectType &rObject, void (ObjectType::*pFunction)(CYISharedPtr)); + + /*! + \details Unsubscribes the given object's function from this message. + */ + template + static void Unsubscribe(ObjectType &rObject, void (ObjectType::*pFunction)(CYISharedPtr)); + + /*! + \details Sends this message to any subscribed objects. + */ + void Send(); + + /*! + \details The message's data. + */ + DataType data; + +private: + + /*! + \details Used to deliver message to subscribers. + */ + static CYISignal > SendMessage; + + YI_DISALLOW_COPY_AND_ASSIGN(Message); +}; + +#include "messages/Message_inl.h" + +#endif // _MESSAGE_H_ + diff --git a/src/messages/Message_inl.h b/src/messages/Message_inl.h new file mode 100644 index 0000000..df43524 --- /dev/null +++ b/src/messages/Message_inl.h @@ -0,0 +1,60 @@ +#ifndef _MESSAGE_INL_H_ +#define _MESSAGE_INL_H_ + +template +CYISignal > Message::SendMessage; + +template +Message::Message(const DataType &rData) + : data(rData) +{ +} + +template +template +Message::Message(const ArgType &rArg) : + data(rArg) +{ +} + +template +template +Message::Message(const Arg1Type &rArg1, const Arg2Type &rArg2) : + data(rArg1, rArg2) +{ +} + +template +template +Message::Message(const Arg1Type &rArg1, const Arg2Type &rArg2, const Arg3Type &rArg3) : + data(rArg1, rArg2, rArg3) +{ +} + +template +Message::~Message() +{ +} + +template +template +void Message::Subscribe(ObjectType &rObject, void (ObjectType::*pFunction)(CYISharedPtr)) +{ + SendMessage.Connect(rObject, pFunction); +} + +template +template +void Message::Unsubscribe(ObjectType &rObject, void (ObjectType::*pFunction)(CYISharedPtr)) +{ + SendMessage.Disconnect(rObject, pFunction); +} + +template +void Message::Send() +{ + SendMessage.Emit(CYISharedPtr(new DataType(data))); +} + +#endif // _MESSAGE_INL_H_ + diff --git a/src/notification/Notification.cpp b/src/notification/Notification.cpp new file mode 100644 index 0000000..19686d5 --- /dev/null +++ b/src/notification/Notification.cpp @@ -0,0 +1,120 @@ +#include "notification/Notification.h" + +#include "notification/NotificationModel.h" + +#include + +static const CYIString TAG = "Notification"; + +CYISharedPtr Notification::s_pModel; + +Notification::Notification(NOTIFICATION eNotification) + : m_eNotification(eNotification) + , m_actionRequestDelegate(new CYISignal<>) + , m_dismissRequestDelegate(new CYISignal<>) +{ +} + +void Notification::SetModel(const CYISharedPtr &pNotificationModel) +{ + s_pModel = pNotificationModel; +} + +NOTIFICATION Notification::GetNotificationId() const +{ + return m_eNotification; +} + +NOTIFICATION_TYPE Notification::GetType() const +{ + const CYIString type = GetDataFromModel(NotificationModel::TYPE).Get(); + if (type == "Dialog") + { + return DIALOG_NOTIFICATION_TYPE; + } + else if (type == "Success") + { + return SUCCESS_NOTIFICATION_TYPE; + } + else if (type == "Error") + { + return ERROR_NOTIFICATION_TYPE; + } + return UNKNOWN_NOTIFICATION_TYPE; +} + +CYIAny Notification::GetDataFromModel(NotificationModel::FIELD eField) const +{ + YI_ASSERT(s_pModel, TAG, "Model not initialized"); + + return s_pModel->GetData(m_eNotification, eField); +} + +CYIString Notification::GetTitle() const +{ + return GetDataFromModel(NotificationModel::TITLE).Get().Arg(m_customTitleField); +} + +void Notification::SetCustomTitleField(const CYIString &customTitleField) +{ + m_customTitleField = customTitleField; +} + +void Notification::SetCustomMessageField(const CYIString &customMessageField) +{ + m_customMessageField = customMessageField; +} + +CYIString Notification::GetMessage() const +{ + return GetDataFromModel(NotificationModel::MESSAGE).Get().Arg(m_customMessageField); +} + +CYIString Notification::GetAction() const +{ + return GetDataFromModel(NotificationModel::ACTION).Get(); +} + +CYIString Notification::GetDismiss() const +{ + return GetDataFromModel(NotificationModel::DISMISS).Get(); +} + +bool Notification::ShouldAllowAutoDismiss() const +{ + const CYIAny &autoDismiss = GetDataFromModel(NotificationModel::AUTODISMISS); + + if (!autoDismiss.Empty()) + { + return autoDismiss.Get(); + } + + // Default is to allow auto dismiss + return true; +} + +void Notification::RequestAction() +{ + m_actionRequestDelegate->Emit(); +} + +void Notification::RequestDismiss() +{ + m_dismissRequestDelegate->Emit(); +} + +void Notification::DelegateAction() +{ + if (m_actionDelegate) + { + (*m_actionDelegate)(); + } +} + +void Notification::DelegateDismiss() +{ + if (m_dismissDelegate) + { + (*m_dismissDelegate)(); + } +} diff --git a/src/notification/Notification.h b/src/notification/Notification.h new file mode 100644 index 0000000..7b2129e --- /dev/null +++ b/src/notification/Notification.h @@ -0,0 +1,131 @@ +#ifndef _NOTIFICATION_H_ +#define _NOTIFICATION_H_ + +#include "messages/Message.h" +#include "notification/NotificationModel.h" + +#include +#include + +class NotificationController; + +class Notification +{ + friend class NotificationController; + +public: + + /*! + \details Constructs an error of the given type. + */ + Notification(NOTIFICATION eNotification); + + /*! + \details Sets the model from which error properties are loaded. + */ + static void SetModel(const CYISharedPtr &pNotificationModel); + + /*! + \details Returns the notification identifier. + */ + NOTIFICATION GetNotificationId() const; + + /*! + \details Returns the type of message. + */ + NOTIFICATION_TYPE GetType() const; + + /*! + \details Returns the localized notification title. + */ + CYIString GetTitle() const; + + /*! + \details Returns the localized notification message. + */ + CYIString GetMessage() const; + + /*! + \details Set the custom title field if supported. + */ + void SetCustomTitleField(const CYIString &customTitleField); + + /*! + \details Set the custom message field if supported. + */ + void SetCustomMessageField(const CYIString &customMessageField); + + /*! + \details Returns the action text. + */ + CYIString GetAction() const; + + /*! + \details Returns the dismiss. + */ + CYIString GetDismiss() const; + + /*! + \details Returns if the popup should allow auto-dismiss. + */ + bool ShouldAllowAutoDismiss() const; + + /*! + \details Triggers an action on the notification if it is shown. + */ + void RequestAction(); + + /*! + \details Triggers a dismiss on the notification if it is shown. + */ + void RequestDismiss(); + + /*! + \details Configures the given delegate to be called when an action request is made for this error. + */ + template + void DelegateActionRequestTo(Type &object, void (Type::*pFunction)()); + + /*! + \details Configures the given delegate to be called when a dismiss request is made for this error. + */ + + template + void DelegateDismissRequestTo(Type &object, void (Type::*pFunction)()); + + /*! + \details Configures the given delegate to be called when the error calls for an action. + */ + template + void DelegateActionTo(Type &object, void (Type::*pFunction)()); + + /*! + \details Configures the given delegate to be called when the error calls for a dismiss. + */ + template + void DelegateDismissTo(Type &object, void (Type::*pFunction)()); + +private: + CYIAny GetDataFromModel(NotificationModel::FIELD eField) const; + + void DelegateAction(); + void DelegateDismiss(); + + static CYISharedPtr s_pModel; + + const NOTIFICATION m_eNotification; + + CYIString m_customTitleField; + CYIString m_customMessageField; + + CYISharedPtr > m_actionRequestDelegate; + CYISharedPtr > m_dismissRequestDelegate; + + CYISharedPtr > m_actionDelegate; + CYISharedPtr > m_dismissDelegate; +}; + +#include "notification/Notification_inl.h" + +#endif // _NOTIFICATION_H_ + diff --git a/src/notification/NotificationController.cpp b/src/notification/NotificationController.cpp new file mode 100644 index 0000000..d03db79 --- /dev/null +++ b/src/notification/NotificationController.cpp @@ -0,0 +1,301 @@ +#include "notification/NotificationController.h" + +#include "customviews/FullScreenNotificationView.h" +#include "customviews/PopupNotificationView.h" +#include "notification/Notification.h" +#include "utilities/SceneLayers.h" + +#include +#include +#include +#include + +static const CYIString TAG("NotificationController"); + +static const YI_CHAR *const FULLSCREEN_ERROR_OVERLAY_SCENE_NAME = "FullscreenErrorOverlaySceneName"; +static const YI_CHAR *const POPUP_ERROR_LONG_OVERLAY_SCENE_NAME = "PopupErrorLongOverlaySceneName"; +static const YI_CHAR *const POPUP_SUCCESS_SHORT_OVERLAY_SCENE_NAME = "PopupSuccessShortOverlaySceneName"; +static const YI_INT32 NOTIFICATION_DELAY_MS = 3000; + +static inline CYIString GetErrorJSONPath(CYIApp &app) +{ + return app.GetAssetsPath() + "text/Notifications.json"; +} + +NotificationController::NotificationController(CYIApp &app) + : m_app(app) + , m_pNotificationModel(new NotificationModel(GetErrorJSONPath(app))) + , m_pPopupErrorLongOverlayView(YI_NULL) + , m_pPopupSuccessShortOverlayView(YI_NULL) + , m_pFullScreenOverlayView(YI_NULL) +{ +} + +NotificationController::~NotificationController() +{ +} + +void NotificationController::Init() +{ + LoadNotificationOverlays(); + + m_pNotificationModel->Fetch(); + Notification::SetModel(m_pNotificationModel); + Message::Subscribe(*this, &NotificationController::NotificationMessageReceived); + + m_notificationDelayTimer.SetInterval(NOTIFICATION_DELAY_MS); + m_notificationDelayTimer.TimedOut.Connect(*this, &NotificationController::CloseNotification); + + QuestManager::QuestAvailableSig.Connect(*this, &NotificationController::NotifyQuestAvailable); + QuestManager::QuestAcceptedSig.Connect(*this, &NotificationController::NotifyQuestAccepted); + QuestManager::ObjectiveCompletedSig.Connect(*this, &NotificationController::NotifyObjectiveCompleted); + QuestManager::QuestCompletedSig.Connect(*this, &NotificationController::NotifyQuestCompleted); +} + +void NotificationController::NotifyQuestAvailable(QuestModel *pQuestModel) +{ + Notification questAvailableNotification(QUEST_AVAILABLE); + questAvailableNotification.SetCustomMessageField(pQuestModel->GetDisplayText()); + + Message(questAvailableNotification).Send(); +} + +void NotificationController::NotifyQuestAccepted(QuestModel *pQuestModel) +{ + Notification questAvailableNotification(QUEST_AVAILABLE); + questAvailableNotification.SetCustomMessageField(pQuestModel->GetDisplayText()); + + Message(questAvailableNotification).Send(); +} + +void NotificationController::NotifyObjectiveCompleted(QuestObjectiveModel *pQuestObjectiveModel) +{ + Notification questAvailableNotification(QUEST_AVAILABLE); + questAvailableNotification.SetCustomMessageField(pQuestObjectiveModel->GetDisplayText()); + + Message(questAvailableNotification).Send(); +} + +void NotificationController::NotifyQuestCompleted(QuestModel *pQuestModel) +{ + Notification questAvailableNotification(QUEST_AVAILABLE); + questAvailableNotification.SetCustomMessageField(pQuestModel->GetDisplayText()); + + Message(questAvailableNotification).Send(); +} + +void NotificationController::LoadNotificationOverlays() +{ + m_pFullScreenOverlayView = LoadDialogOverlay(FULLSCREEN_ERROR_OVERLAY_SCENE_NAME, "Notifications_MainComp-Fullscreen-Error.layout"); + m_pPopupErrorLongOverlayView = LoadPopupOverlay(POPUP_ERROR_LONG_OVERLAY_SCENE_NAME, "Notifications_MainComp-Popup-Error-Long.layout"); + m_pPopupSuccessShortOverlayView = LoadPopupOverlay(POPUP_SUCCESS_SHORT_OVERLAY_SCENE_NAME, "Notifications_MainComp-Popup-Success-Short.layout"); +} + +FullScreenNotificationView *NotificationController::LoadDialogOverlay(const CYIString &sceneName, const CYIString &layoutName) +{ + CYISceneManager *pSceneManager = m_app.GetSceneManager(); + + CYISceneView *pSceneView = pSceneManager->LoadScene(layoutName, CYISceneManager::SCALE_RESPONSIVE_LAYOUT, CYISceneManager::V_ALIGN_CENTER, CYISceneManager::H_ALIGN_CENTER); + YI_ASSERT(pSceneView, TAG, "Scene manager failed to load '%s'", layoutName.GetData()); + + FullScreenNotificationView *pDialogOverlay = static_cast(pSceneView); + pDialogOverlay->Actioned.Connect(*this, &NotificationController::OverlayAction); + pDialogOverlay->Dismissed.Connect(*this, &NotificationController::OverlayDismiss); + pDialogOverlay->AnimationdOutEnded.Connect(*this,&NotificationController::OnAnimationOutEnded); + pDialogOverlay->ConnectButtons(); + + pSceneManager->AddScene(sceneName, pDialogOverlay, SceneLayers::LAYER_NOTIFICATIONS, CYISceneManager::LAYER_TRANSPARENT); + pSceneManager->UnstageScene(sceneName); + pDialogOverlay->SetSceneName(sceneName); + + return pDialogOverlay; +} + +PopupNotificationView *NotificationController::LoadPopupOverlay(const CYIString &sceneName, const CYIString &layoutName) +{ + CYISceneManager *pSceneManager = m_app.GetSceneManager(); + + CYISceneView *pSceneView = pSceneManager->LoadScene(layoutName, CYISceneManager::SCALE_RESPONSIVE_LAYOUT, CYISceneManager::V_ALIGN_CENTER, CYISceneManager::H_ALIGN_CENTER); + YI_ASSERT(pSceneView, TAG, "Scene manager failed to load '%s'", layoutName.GetData()); + + PopupNotificationView *pPopupOverlay = static_cast(pSceneView); + pPopupOverlay->Dismissed.Connect(*this, &NotificationController::OverlayDismiss); + pPopupOverlay->AnimationdOutEnded.Connect(*this,&NotificationController::OnAnimationOutEnded); + + pSceneManager->AddScene(sceneName, pPopupOverlay, SceneLayers::LAYER_NOTIFICATIONS, CYISceneManager::LAYER_TRANSPARENT); + pSceneManager->UnstageScene(sceneName); + pPopupOverlay->SetSceneName(sceneName); + + return pPopupOverlay; +} + +void NotificationController::NotificationMessageReceived(CYISharedPtr pNotification) +{ + std::deque >::const_iterator iter = m_notifications.begin(); + std::deque >::const_iterator end = m_notifications.end(); + + // Ignore the error if it has already been queued for display. + for (; iter != end; ++iter) + { + if ((*iter)->GetNotificationId() == pNotification->GetNotificationId()) + { + return; + } + } + + if (m_notifications.empty()) + { + CYIBackButtonHandler::AddListener(this); + } + + m_notifications.push_back(pNotification); + + ShowNextNotification(); +} + +void NotificationController::ShowNextNotification() +{ + if (!IsAnOverlayShown() && m_notifications.size() > 0) + { + CYISharedPtr pNotification = m_notifications.front(); + + switch (pNotification->GetType()) { + case DIALOG_NOTIFICATION_TYPE: + ShowOverlayForDialog(m_pFullScreenOverlayView, pNotification); + break; + + case SUCCESS_NOTIFICATION_TYPE: + ShowOverlayForPopup(m_pPopupSuccessShortOverlayView, pNotification); + break; + + case ERROR_NOTIFICATION_TYPE: + ShowOverlayForPopup(m_pPopupErrorLongOverlayView, pNotification); + break; + + case GENERAL_NOTIFICATION_TYPE: + case UNKNOWN_NOTIFICATION_TYPE: + default: + break; + } + } + else + { + CYIBackButtonHandler::RemoveListener(this); + } +} + +bool NotificationController::IsAnOverlayShown() const +{ + return m_pFullScreenOverlayView->IsOverlayShown() || m_pPopupErrorLongOverlayView->IsOverlayShown() || m_pPopupSuccessShortOverlayView->IsOverlayShown(); +} + +void NotificationController::ShowOverlayForDialog(FullScreenNotificationView *pDialogOverlay, const CYISharedPtr &pNotification) +{ + pDialogOverlay->SetTitle(pNotification->GetTitle()); + pDialogOverlay->SetMessage(pNotification->GetMessage()); + pDialogOverlay->SetActionButtonText(pNotification->GetAction()); + pDialogOverlay->SetDismissButtonText(pNotification->GetDismiss()); + + pNotification->DelegateActionRequestTo(*pDialogOverlay, &FullScreenNotificationView::DoAction); + pNotification->DelegateDismissRequestTo(*pDialogOverlay, &FullScreenNotificationView::DoDismiss); + + m_app.GetSceneManager()->StageScene(pDialogOverlay->GetSceneName()); + pDialogOverlay->ShowOverlay(); +} + +void NotificationController::ShowOverlayForPopup(PopupNotificationView *pPopupOverlay, const CYISharedPtr &pNotification) +{ + pPopupOverlay->SetShortTitle(pNotification->GetTitle()); + pPopupOverlay->SetMessage(pNotification->GetMessage()); + pPopupOverlay->ConnectButtons(); + pNotification->DelegateDismissRequestTo(*pPopupOverlay, &PopupNotificationView::DoDismiss); + + m_app.GetSceneManager()->StageScene(pPopupOverlay->GetSceneName()); + pPopupOverlay->ShowOverlay(); + + if(pNotification->ShouldAllowAutoDismiss()) + { + m_notificationDelayTimer.Start(); + } +} + +void NotificationController::HideOverlay(NotificationView *pNotificationOverlay) +{ + pNotificationOverlay->HideOverlay(); +} + +void NotificationController::OnAnimationOutEnded(NotificationView *pNotificationOverlay) +{ + m_app.GetSceneManager()->UnstageScene(pNotificationOverlay->GetSceneName()); +} + +void NotificationController::OverlayAction(FullScreenNotificationView *pErrorOverlay) +{ + HideOverlay(pErrorOverlay); + + if (m_notifications.size()) + { + m_notifications.front()->DelegateAction(); + m_notifications.pop_front(); + } + + ShowNextNotification(); +} + +void NotificationController::OverlayDismiss(NotificationView *pErrorOverlay) +{ + HideOverlay(pErrorOverlay); + + if (m_notifications.size()) + { + m_notifications.front()->DelegateDismiss(); + m_notifications.pop_front(); + } + + ShowNextNotification(); +} + +void NotificationController::CloseNotification() +{ + m_notificationDelayTimer.Stop(); + + if (m_pPopupSuccessShortOverlayView->IsOverlayShown()) + { + OverlayDismiss(m_pPopupSuccessShortOverlayView); + } + else if (m_pPopupErrorLongOverlayView->IsOverlayShown()) + { + OverlayDismiss(m_pPopupErrorLongOverlayView); + } +} + +bool NotificationController::OnBackButtonPressed() +{ + bool bHandled = false; + + if (m_pFullScreenOverlayView->IsOverlayShown()) + { + OverlayDismiss(m_pFullScreenOverlayView); + bHandled = true; + } + else if (m_pPopupSuccessShortOverlayView->IsOverlayShown()) + { + OverlayDismiss(m_pPopupSuccessShortOverlayView); + bHandled = true; + } + else if (m_pPopupErrorLongOverlayView->IsOverlayShown()) + { + OverlayDismiss(m_pPopupErrorLongOverlayView); + bHandled = true; + } + + return bHandled; +} + +void NotificationController::OnDeepLinkQueued() +{ + if (!m_notifications.empty() && (m_notifications.front()->GetNotificationId() != APP_CONFIGURATION_ERROR)) + { + OverlayDismiss(m_pFullScreenOverlayView); + } +} diff --git a/src/notification/NotificationController.h b/src/notification/NotificationController.h new file mode 100644 index 0000000..5a68f2e --- /dev/null +++ b/src/notification/NotificationController.h @@ -0,0 +1,63 @@ +#ifndef _NOTIFICATION_CONTROLLER_H_ +#define _NOTIFICATION_CONTROLLER_H_ + +#include "notification/NotificationModel.h" + +#include +#include +#include +#include +#include + +class Notification; +class NotificationView; +class FullScreenNotificationView; +class PopupNotificationView; + +class CYIApp; +class CYISceneView; + +class NotificationController : public CYISignalHandler, public CYIBackButtonHandler::Listener +{ +public: + NotificationController(CYIApp &rApp); + virtual ~NotificationController(); + + void Init(); + void NotifyQuestAvailable(QuestModel *); + void NotifyQuestAccepted(QuestModel *); + void NotifyObjectiveCompleted(QuestObjectiveModel *); + void NotifyQuestCompleted(QuestModel *); +private: + void LoadNotificationOverlays(); + FullScreenNotificationView *LoadDialogOverlay(const CYIString &sceneName, const CYIString &layoutName); + PopupNotificationView *LoadPopupOverlay(const CYIString &sceneName, const CYIString &layoutName); + + void ShowNextNotification(); + bool IsAnOverlayShown() const; + void ShowOverlayForDialog(FullScreenNotificationView *pDialogOverlay, const CYISharedPtr &pNotification); + void ShowOverlayForPopup(PopupNotificationView *pDialogOverlay, const CYISharedPtr &pNotification); + void HideOverlay(NotificationView *pDialogOverlay); + void OnAnimationOutEnded(NotificationView *pNotificationOverlay); + + void NotificationMessageReceived(CYISharedPtr pNotification); + void OverlayAction(FullScreenNotificationView *pDialogOverlay); + void OverlayDismiss(NotificationView *pDialogOverlay); + void CloseNotification(); + + virtual bool OnBackButtonPressed(); + void OnDeepLinkQueued(); + + CYIApp &m_app; + CYISharedPtr m_pNotificationModel; + PopupNotificationView *m_pPopupErrorLongOverlayView; + PopupNotificationView *m_pPopupSuccessShortOverlayView; + FullScreenNotificationView *m_pFullScreenOverlayView; + std::deque > m_notifications; + CYITimer m_notificationDelayTimer; + + YI_DISALLOW_COPY_AND_ASSIGN(NotificationController); +}; + +#endif // _NOTIFICATION_CONTROLLER_H_ + diff --git a/src/notification/NotificationModel.cpp b/src/notification/NotificationModel.cpp new file mode 100644 index 0000000..12497b3 --- /dev/null +++ b/src/notification/NotificationModel.cpp @@ -0,0 +1,191 @@ +#include "notification/NotificationModel.h" + +#include +#include + +static const CYIString TAG = "NotificationModel"; + +NOTIFICATION NotificationModel::NotificationFromErrorString(const CYIString &rNotificationString) +{ + static std::map map; + + if (map.empty()) + { + map["QUEST_AVAILABLE"] = QUEST_AVAILABLE; + map["QUEST_ACCEPTED"] = QUEST_ACCEPTED; + map["QUEST_COMPLETED"] = QUEST_COMPLETED; + map["QUEST_OBJECTIVE_COMPLETED"] = QUEST_OBJECTIVE_COMPLETED; + map["INVALID_DEEP_LINK_ERROR"] = INVALID_DEEP_LINK_ERROR; + map["APP_CONFIGURATION_ERROR"] = APP_CONFIGURATION_ERROR; + map["VSTB_SERVER_ERROR"] = VSTB_SERVER_ERROR; + map["VIDEO_PLAYBACK_ERROR"] = VIDEO_PLAYBACK_ERROR; + map["VIDEO_PLAYBACK_CHANNEL_AUTH_ERROR"] = VIDEO_PLAYBACK_CHANNEL_AUTH_ERROR; + map["VIDEO_CONTENT_AUTH_LEVEL_ERROR"] = VIDEO_CONTENT_AUTH_LEVEL_ERROR; + map["NETWORK_CONNECTION_ERROR"] = NETWORK_CONNECTION_ERROR; + map["LOGOUT_CONFIRMATION"] = LOGOUT_CONFIRMATION; + map["LOGOUT_SUCCESS"] = LOGOUT_SUCCESS; + map["LOGOUT_FAIL"] = LOGOUT_FAIL; + } + + const std::map::const_iterator iter = map.find(rNotificationString); + YI_ASSERT(iter != map.end(), TAG, "Error string does not match a known error"); + + return iter->second; +} + +NotificationModel::FIELD NotificationModel::FieldFromFieldString(const CYIString &rFieldString) +{ + static std::map map; + + if (map.empty()) + { + map["type"] = TYPE; + map["title"] = TITLE; + map["message"] = MESSAGE; + map["action"] = ACTION; + map["dismiss"] = DISMISS; + map["autodismiss"] = AUTODISMISS; + } + + const std::map::const_iterator iter = map.find(rFieldString); + YI_ASSERT(iter != map.end(), TAG, "Field string does not match a known field"); + + return iter->second; +} + +CYIAny NotificationModel::DataForFieldFromValue(FIELD eField, const yi::rapidjson::Value &rValue) +{ + switch (eField) + { + case TYPE: + case TITLE: + case MESSAGE: + case ACTION: + case DISMISS: + return CYIString(rValue.GetString()); + case AUTODISMISS: + return rValue.GetBool(); + } + + return CYIAny(); +} + +NotificationModel::NotificationModel(const CYIString &rJSONPath) + : CYIAbstractDataModel(0, 0) + , m_JSONPath(rJSONPath) + , m_bHasFetched(false) +{ +} + +NotificationModel::~NotificationModel() +{ +} + +CYIAny NotificationModel::GetData(NOTIFICATION eNotification, FIELD eField) const +{ + const CYIAny data = GetItemData(GetIndex(eNotification, eField)); + + switch (eField) + { + case TYPE: + case AUTODISMISS: + break; + case TITLE: + case MESSAGE: + case ACTION: + case DISMISS: + return YiTranslate(data.Get()); + } + + return data; +} + +void NotificationModel::SetData(NOTIFICATION eNotification, FIELD eField, const CYIAny &rData) +{ + const YI_INT32 nRowCount = GetRowCount(); + if (nRowCount <= eNotification) + { + InsertRows(nRowCount, static_cast(eNotification) - nRowCount + 1); + } + + const YI_INT32 nColumnCount = GetColumnCount(); + if (nColumnCount <= eField) + { + InsertColumns(nColumnCount, static_cast(eField) - nColumnCount + 1); + } + + SetItemData(GetIndex(eNotification, eField), rData); +} + +void NotificationModel::Fetch() +{ + if (!m_bHasFetched) + { + std::FILE *pFile = std::fopen(m_JSONPath.GetData(), "rb"); + YI_ASSERT(pFile, TAG, "Could not open %s", m_JSONPath.GetData()); + + std::string string; + std::fseek(pFile, 0, SEEK_END); + string.resize(static_cast(std::ftell(pFile))); + std::fseek(pFile, 0, SEEK_SET); + std::fread(&string[0], 1, string.size(), pFile); + std::fclose(pFile); + + ParseErrors(string); + + m_bHasFetched = true; + } +} + +void NotificationModel::ParseErrors(const CYIString &rJSONString) +{ + CYIParsingError error; + yi::rapidjson::Document *pDocument = CYIRapidJSONUtility::CreateDocumentFromString(rJSONString, error); + YI_ASSERT(!error.HasError(), TAG, "Could not parse: %s", error.GetParsingErrorMessage().GetData()); + + yi::rapidjson::Value::ConstMemberIterator iter = pDocument->MemberBegin(); + yi::rapidjson::Value::ConstMemberIterator end = pDocument->MemberEnd(); + + for (; iter != end; ++iter) + { + ParseError(iter->name.GetString(), iter->value); + } + + delete pDocument; +} + +void NotificationModel::ParseError(const CYIString &rNotification, const yi::rapidjson::Value &rValue) +{ + const NOTIFICATION eNotification = NotificationFromErrorString(rNotification); + + yi::rapidjson::Value::ConstMemberIterator iter = rValue.MemberBegin(); + yi::rapidjson::Value::ConstMemberIterator end = rValue.MemberEnd(); + + const CYIString type = rValue["type"].GetString(); + + bool bCorrectTypeName = ((type == "Dialog") || (type == "Success") || (type == "Error")); + YI_ASSERT(bCorrectTypeName, TAG, "Incorrect type name: %s", type.GetData()); + + bool bIsDialogNotificationType = (type == "Dialog"); + + for (; iter != end; ++iter) + { + const FIELD eField = FieldFromFieldString(iter->name.GetString()); + const CYIAny data = DataForFieldFromValue(eField, iter->value); + + bool bInvalidField = !bIsDialogNotificationType && (eField == ACTION || eField == DISMISS); + YI_ASSERT(!bInvalidField, TAG, "Invalid field"); + + SetData(eNotification, eField, data); + } + + YI_ASSERT(!GetData(eNotification, NotificationModel::TYPE).Empty(), TAG, "Type field is not found"); + YI_ASSERT(!GetData(eNotification, NotificationModel::TITLE).Empty(), TAG, "Title field is not found"); + YI_ASSERT(!GetData(eNotification, NotificationModel::MESSAGE).Empty(), TAG, "Message field is not found"); + + if (bIsDialogNotificationType) + { + YI_ASSERT(!GetData(eNotification, NotificationModel::ACTION).Empty(), TAG, "Action field is not found"); + YI_ASSERT(!GetData(eNotification, NotificationModel::DISMISS).Empty(), TAG, "Dismiss field is not found"); + } +} diff --git a/src/notification/NotificationModel.h b/src/notification/NotificationModel.h new file mode 100644 index 0000000..9b2346d --- /dev/null +++ b/src/notification/NotificationModel.h @@ -0,0 +1,47 @@ +#ifndef _NOTIFICATION_MODEL_H_ +#define _NOTIFICATION_MODEL_H_ + +#include "notification/Notifications.h" + +#include +#include + +class NotificationModel : public CYIAbstractDataModel +{ + +public: + enum FIELD + { + TYPE, // CYIString + TITLE, // CYIString + MESSAGE, // CYIString + ACTION, // CYIString + DISMISS, // CYIString + AUTODISMISS // bool + }; + + NotificationModel(const CYIString &rJSONPath); + virtual ~NotificationModel(); + + void Fetch(); + + CYIAny GetData(NOTIFICATION eNotification, FIELD eField) const; + +private: + void SetData(NOTIFICATION eNotification, FIELD eField, const CYIAny &rData); + + void ParseErrors(const CYIString &rJSONString); + void ParseError(const CYIString &rError, const yi::rapidjson::Value &rValue); + + static NOTIFICATION NotificationFromErrorString(const CYIString &rNotificationString); + static FIELD FieldFromFieldString(const CYIString &rFieldString); + static CYIAny DataForFieldFromValue(FIELD eField, const yi::rapidjson::Value &rValue); + + const CYIString m_JSONPath; + bool m_bHasFetched; + + YI_DISALLOW_COPY_AND_ASSIGN(NotificationModel); +}; + +#endif // _NOTIFICATION_MODEL_H_ + diff --git a/src/notification/Notification_inl.h b/src/notification/Notification_inl.h new file mode 100644 index 0000000..22579d8 --- /dev/null +++ b/src/notification/Notification_inl.h @@ -0,0 +1,36 @@ +#ifndef _NOTIFICATION_INL_H_ +#define _NOTIFICATION_INL_H_ + +template +void Notification::DelegateActionRequestTo(Type &object, void (Type::*pFunction)()) +{ + m_actionRequestDelegate->Connect(object, pFunction); +} + +template +void Notification::DelegateDismissRequestTo(Type &object, void (Type::*pFunction)()) +{ + m_dismissRequestDelegate->Connect(object, pFunction); +} + +template +void Notification::DelegateActionTo(Type &object, void (Type::*pFunction)()) +{ + if (!m_actionDelegate) + { + m_actionDelegate = CYISharedPtr >(new CYISignal<>); + } + m_actionDelegate->Connect(object, pFunction); +} + +template +void Notification::DelegateDismissTo(Type &object, void (Type::*pFunction)()) +{ + if (!m_dismissDelegate) + { + m_dismissDelegate = CYISharedPtr >(new CYISignal<>); + } + m_dismissDelegate->Connect(object, pFunction); +} + +#endif // _NOTIFICATION_INL_H_ diff --git a/src/notification/Notifications.h b/src/notification/Notifications.h new file mode 100644 index 0000000..3d3ad8a --- /dev/null +++ b/src/notification/Notifications.h @@ -0,0 +1,32 @@ +#ifndef _NOTIFICATIONS_H_ +#define _NOTIFICATIONS_H_ + +enum NOTIFICATION +{ + QUEST_AVAILABLE, + QUEST_ACCEPTED, + QUEST_COMPLETED, + QUEST_OBJECTIVE_COMPLETED, + INVALID_DEEP_LINK_ERROR, + APP_CONFIGURATION_ERROR, + VSTB_SERVER_ERROR, + VIDEO_PLAYBACK_ERROR, + VIDEO_PLAYBACK_CHANNEL_AUTH_ERROR, + VIDEO_CONTENT_AUTH_LEVEL_ERROR, + NETWORK_CONNECTION_ERROR, + LOGOUT_CONFIRMATION, + LOGOUT_SUCCESS, + LOGOUT_FAIL +}; + +enum NOTIFICATION_TYPE +{ + DIALOG_NOTIFICATION_TYPE, + GENERAL_NOTIFICATION_TYPE, + SUCCESS_NOTIFICATION_TYPE, + ERROR_NOTIFICATION_TYPE, + UNKNOWN_NOTIFICATION_TYPE +}; + +#endif // _NOTIFICATIONS_H_ + diff --git a/src/screen/BookScreenViewController.cpp b/src/screen/BookScreenViewController.cpp new file mode 100644 index 0000000..76900fb --- /dev/null +++ b/src/screen/BookScreenViewController.cpp @@ -0,0 +1,65 @@ +#include "BookScreenViewController.h" + +#include "customviews/TabbedView.h" +#include "screen/TabbedViewController.h" +#include "utilities/NodeUtilities.h" + +#include +#include +#include +#include +#include +#include + +BookScreenViewController::BookScreenViewController(NavigationInterface &navigationInterface, CYIApp &app) : +TabbedScreenViewController(NavigationInterface::SPLASH, "BookScreen", "Book_Main.layout", navigationInterface, app) +, m_tabbedViewController(navigationInterface) +, m_pTabbedView(YI_NULL) +, m_pButtonBarView(YI_NULL) +{ +} + +BookScreenViewController::~BookScreenViewController() +{ +} + +void BookScreenViewController::BuildTimelines() +{ + m_pInTimeline = m_pView->BuildTimelineGroup("In"); + if (m_pInTimeline) + { + SetBeginAnimation(m_pInTimeline.Get(), TimelineHelper::ANIMATE_FORWARD); + } + + m_pOutTimeline = m_pView->BuildTimelineGroup("Out"); + if (m_pOutTimeline) + { + SetEndAnimation(m_pOutTimeline.Get(), TimelineHelper::ANIMATE_FORWARD); + } +} + +void BookScreenViewController::OnInitScreen() +{ + TabbedScreenViewController::OnInitScreen(); + + m_pButtonBarView = Utility::GetNode(m_pView, "ButtonBar", Utility::GET_NODE_FLAG_OPTIONAL); + m_pTabbedView = Utility::GetNode(m_pView, "TabbedView", Utility::GET_NODE_FLAG_OPTIONAL); + + if (m_pTabbedView) + { + m_tabbedViewController.Init(m_pTabbedView); + } +} + +void BookScreenViewController::OnPreloadValidateScreen(CYIBundle) +{ + PreloadValidateSucceeded.Emit(this); +} + +void BookScreenViewController::OnPreloadScreen(CYIBundle bundle, const CYIPersistentStore &stateData) +{ + TabbedScreenViewController::OnPreloadScreen(bundle, stateData); + + PreloadFinished(this); +} + diff --git a/src/screen/BookScreenViewController.h b/src/screen/BookScreenViewController.h new file mode 100644 index 0000000..53f54a3 --- /dev/null +++ b/src/screen/BookScreenViewController.h @@ -0,0 +1,39 @@ +#ifndef _BOOK_SCREEN_VIEW_CONTROLLER_H_ +#define _BOOK_SCREEN_VIEW_CONTROLLER_H_ + +#include "customviews/ButtonBarView.h" +#include "screen/TabbedScreenViewController.h" + +#include +#include + +class TabbedView; +class ButtonBarView; +class CYITimelineGroup; + +class BookScreenViewController : public TabbedScreenViewController +{ +public: + BookScreenViewController(NavigationInterface &navigationInterface, CYIApp &app); + virtual ~BookScreenViewController(); + +protected: + virtual void OnInitScreen(); + virtual void OnPreloadValidateScreen(CYIBundle); + virtual void OnPreloadScreen(CYIBundle bundle, const CYIPersistentStore &stateData); + + virtual void BuildTimelines(); + +private: + CYIScopedPtr m_pInTimeline; + CYIScopedPtr m_pOutTimeline; + + TabbedViewController m_tabbedViewController; + TabbedView *m_pTabbedView; + ButtonBarView *m_pButtonBarView; + + YI_DISALLOW_COPY_AND_ASSIGN(BookScreenViewController) +}; + +#endif + diff --git a/src/screen/NavigationController.cpp b/src/screen/NavigationController.cpp index fcd2d59..af6e9fd 100644 --- a/src/screen/NavigationController.cpp +++ b/src/screen/NavigationController.cpp @@ -89,6 +89,9 @@ std::vector NavigationContro case SPLASH: screenHistory.push_back(TransitionBundleFor(CreateScreenViewController(SPLASH))); break; + case BOOK: + screenHistory.push_back(TransitionBundleFor(CreateScreenViewController(BOOK))); + break; } return screenHistory; diff --git a/src/screen/NavigationInterface.h b/src/screen/NavigationInterface.h index 5c44116..013c44c 100644 --- a/src/screen/NavigationInterface.h +++ b/src/screen/NavigationInterface.h @@ -10,7 +10,8 @@ class NavigationInterface : public CYISignalHandler public: enum SCREEN_ID { - SPLASH + SPLASH, + BOOK }; static const CYIString ASSET_PACKAGE_BUNDLE_KEY; diff --git a/src/screen/ScreenViewController.cpp b/src/screen/ScreenViewController.cpp index 8b44bec..f60fdb8 100644 --- a/src/screen/ScreenViewController.cpp +++ b/src/screen/ScreenViewController.cpp @@ -3,6 +3,8 @@ //#include "player/PlayerScreenViewController.h" #include "screen/ScreenViewController.h" #include "screen/SplashScreenViewController.h" +#include "screen/BookScreenViewController.h" + //#include "screen/ContentScreenViewController.h" //#include "screen/HomeLanderScreenViewController.h" //#include "screen/LoginScreenViewController.h" @@ -38,6 +40,8 @@ ScreenViewController *ScreenViewController::Create(NavigationInterface::SCREEN_I { case NavigationInterface::SPLASH: return new SplashScreenViewController(navigationController, app); + case NavigationInterface::BOOK: + return new BookScreenViewController(navigationController, app); } return YI_NULL; diff --git a/src/screen/SplashScreenViewController.cpp b/src/screen/SplashScreenViewController.cpp index 5c5ad36..380c6ba 100644 --- a/src/screen/SplashScreenViewController.cpp +++ b/src/screen/SplashScreenViewController.cpp @@ -9,25 +9,7 @@ #include #include -/* -// Load a layout file which will be the root scene view. -CYISceneView *pSceneViewMain = GetSceneManager()->LoadScene("MainNav_Main.layout", CYISceneManager::SCALE_STRETCH, CYISceneManager::V_ALIGN_CENTER, CYISceneManager::H_ALIGN_CENTER); - -if(!pSceneViewMain) -{ -YI_LOGE("LovecraftApp::UserInit", "Loading scene has failed"); -return false; -} - -pSceneViewMain->GetInTimeline()->StartForward(); - -// Add the scene view to the scene manager. -GetSceneManager()->AddScene("MainComp", pSceneViewMain, 0, CYISceneManager::LAYER_OPAQUE); -*/ - - SplashScreenViewController::SplashScreenViewController(NavigationInterface &navigationInterface, CYIApp &app) : - //TabbedScreenViewController(NavigationInterface::SPLASH, "SplashScreen", "Splash_Main.layout", navigationInterface, app) TabbedScreenViewController(NavigationInterface::SPLASH, "SplashScreen", "MainNav_Main.layout", navigationInterface, app) , m_tabbedViewController(navigationInterface) , m_pTabbedView(YI_NULL) diff --git a/src/utilities/NodeUtilities.h b/src/utilities/NodeUtilities.h index 42fb6f1..2e1e4f0 100644 --- a/src/utilities/NodeUtilities.h +++ b/src/utilities/NodeUtilities.h @@ -18,13 +18,8 @@ namespace Utility { enum GET_NODE_FLAG { - GET_NODE_FLAG_MANDATORY=0, GET_NODE_FLAG_OPTIONAL - }; - - enum test - { - BLAH, - BLAH2 + GET_NODE_FLAG_MANDATORY=0, + GET_NODE_FLAG_OPTIONAL }; const CYIString TAG("Utility"); diff --git a/src/utilities/TimelineUtilities.cpp b/src/utilities/TimelineUtilities.cpp index 1230c01..0e2dc2d 100644 --- a/src/utilities/TimelineUtilities.cpp +++ b/src/utilities/TimelineUtilities.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include static const CYIString TAG = "TimelineUtilities"; @@ -30,10 +31,10 @@ PropertyAnimationDefinition::PropertyAnimationDefinition(YI_NODE_PROPERTY_TYPE p { } -CYIAbstractTimeline *TimelineUtilities::RecursiveCreateNodeParallelTimelineGroup(CYISceneNode *pNode, CYIString markerName, YI_UINT64 timelineOffsetInms) +CYITimelineGroup *TimelineUtilities::RecursiveCreateNodeParallelTimelineGroup(CYISceneNode *pNode, CYIString markerName, YI_UINT64 nTimelineOffsetInms) { CYITimelineGroup *pGroup = new CYIParallelTimelineGroup(); - RecursiveBuildNodeParallelTimelineGroup(pGroup, pNode, markerName, timelineOffsetInms); + RecursiveBuildNodeParallelTimelineGroup(pGroup, pNode, markerName, nTimelineOffsetInms); pGroup->Finalize(); if (pGroup->GetTimelineCount() == 0) @@ -44,10 +45,20 @@ CYIAbstractTimeline *TimelineUtilities::RecursiveCreateNodeParallelTimelineGroup return pGroup; } -CYIAbstractTimeline *TimelineUtilities::RecursiveCreateNodeSerialTimelineGroup(CYISceneNode *pNode, CYIString markerName, YI_UINT64 timelineOffsetInms) +bool TimelineUtilities::HasViewFocusInTimelines(CYISceneView *pView) +{ + if (pView) + { + CYIScopedPtr pFocusInTimelineGroup(TimelineUtilities::RecursiveCreateNodeParallelTimelineGroup(pView, "FocusIn")); + return pFocusInTimelineGroup && pFocusInTimelineGroup->GetTimelineCount() > 0; + } + return false; +} + +CYITimelineGroup *TimelineUtilities::RecursiveCreateNodeSerialTimelineGroup(CYISceneNode *pNode, CYIString markerName, YI_UINT64 nTimelineOffsetInms) { CYITimelineGroup *pGroup = new CYISerialTimelineGroup(); - RecursiveBuildSerialTimelineGroup(pGroup, pNode, markerName, timelineOffsetInms); + RecursiveBuildSerialTimelineGroup(pGroup, pNode, markerName, nTimelineOffsetInms); pGroup->Finalize(); if (pGroup->GetTimelineCount() == 0) @@ -58,20 +69,20 @@ CYIAbstractTimeline *TimelineUtilities::RecursiveCreateNodeSerialTimelineGroup(C return pGroup; } -void TimelineUtilities::RecursiveBuildNodeParallelTimelineGroup(CYITimelineGroup *pGroup, CYISceneNode *pNode, CYIString markerName, YI_UINT64 timelineOffsetInms) +void TimelineUtilities::RecursiveBuildNodeParallelTimelineGroup(CYITimelineGroup *pGroup, CYISceneNode *pNode, CYIString markerName, YI_UINT64 nTimelineOffsetInms) { if (pNode || pGroup) { - AddNodeTimelineToGroup(pGroup, pNode, markerName, timelineOffsetInms); + AddNodeTimelineToGroup(pGroup, pNode, markerName, nTimelineOffsetInms); for (YI_UINT32 i = 0; i < pNode->GetChildCount(); i++) { - RecursiveBuildNodeParallelTimelineGroup(pGroup, pNode->GetChild(i), markerName, timelineOffsetInms); + RecursiveBuildNodeParallelTimelineGroup(pGroup, pNode->GetChild(i), markerName, nTimelineOffsetInms); } } } -void TimelineUtilities::AddNodeTimelineToGroup(CYITimelineGroup *pGroup, const CYISceneNode *pNode, const CYIString &markerName, YI_UINT64 timelineOffsetInms) +void TimelineUtilities::AddNodeTimelineToGroup(CYITimelineGroup *pGroup, const CYISceneNode *pNode, const CYIString &markerName, YI_UINT64 nTimelineOffsetInms) { YI_ASSERT(pNode, TAG, "pNode is null"); YI_ASSERT(pGroup, TAG, "pGroup is null"); @@ -81,13 +92,13 @@ void TimelineUtilities::AddNodeTimelineToGroup(CYITimelineGroup *pGroup, const C if (pView) { - CYIAbstractTimeline *pTimeline = GetTimeline(markerName, pView); + CYIAbstractTimeline *pTimeline = GetTimeline(pView, markerName); if (pTimeline) { - if (timelineOffsetInms > 0) + if (nTimelineOffsetInms > 0) { - pGroup->AddTimelineWithOffset(pTimeline, timelineOffsetInms); + pGroup->AddTimelineWithOffset(pTimeline, nTimelineOffsetInms); } else { @@ -97,20 +108,20 @@ void TimelineUtilities::AddNodeTimelineToGroup(CYITimelineGroup *pGroup, const C } } -void TimelineUtilities::RecursiveBuildSerialTimelineGroup(CYITimelineGroup *pGroup, CYISceneNode *pNode, CYIString markerName, YI_UINT64 timelineOffsetInms) +void TimelineUtilities::RecursiveBuildSerialTimelineGroup(CYITimelineGroup *pGroup, CYISceneNode *pNode, CYIString markerName, YI_UINT64 nTimelineOffsetInms) { if (pNode || pGroup) { - AddNodeTimelineToGroup(pGroup, pNode, markerName, timelineOffsetInms); + AddNodeTimelineToGroup(pGroup, pNode, markerName, nTimelineOffsetInms); for (YI_UINT32 i = 0; i < pNode->GetChildCount(); i++) { - RecursiveBuildNodeParallelTimelineGroup(pGroup, pNode->GetChild(i), markerName, timelineOffsetInms); + RecursiveBuildNodeParallelTimelineGroup(pGroup, pNode->GetChild(i), markerName, nTimelineOffsetInms); } } } -CYITimeline *TimelineUtilities::GetTimeline(const CYIString &markerName, CYISceneView *pSceneView) +CYITimeline *TimelineUtilities::GetTimeline(CYISceneView *pSceneView, const CYIString &markerName) { YI_ASSERT(pSceneView, TAG, "pSceneView is null"); YI_ASSERT(!markerName.IsEmpty(), TAG, "markerName is empty"); diff --git a/src/utilities/TimelineUtilities.h b/src/utilities/TimelineUtilities.h index 630da0c..90ebeb1 100644 --- a/src/utilities/TimelineUtilities.h +++ b/src/utilities/TimelineUtilities.h @@ -1,8 +1,8 @@ #ifndef _TIMELINEUTILITIES_H #define _TIMELINEUTILITIES_H +#include #include - #include class CYIAbstractTimeline; @@ -10,7 +10,6 @@ class CYIAnimationToggleController; class CYISceneNode; class CYISceneView; class CYITimeline; -class CYITimelineGroup; /*! * Definition for a property animation that will eventually be used to play an animation on a CYISceneNode @@ -58,15 +57,15 @@ namespace TimelineUtilities * \details Returns one of the engine built in interpolators. */ CYITimeInterpolator *GetTimeInterpolatorFromInterpolatorType(PropertyAnimationDefinition::eTimeInterpolatorType type); - - CYIAbstractTimeline *RecursiveCreateNodeParallelTimelineGroup(CYISceneNode *pNode, CYIString markerName, YI_UINT64 timelineOffsetInms = 0); - CYIAbstractTimeline *RecursiveCreateNodeSerialTimelineGroup(CYISceneNode *pNode, CYIString markerName, YI_UINT64 timelineOffsetInms = 0); - void RecursiveBuildNodeParallelTimelineGroup(CYITimelineGroup *pGroup, CYISceneNode *pNode, CYIString markerName, YI_UINT64 timelineOffsetInms = 0); - void RecursiveBuildSerialTimelineGroup(CYITimelineGroup *pGroup, CYISceneNode *pNode, CYIString markerName, YI_UINT64 timelineOffsetInms = 0); - CYITimeline *GetTimeline(const CYIString &markerName, CYISceneView *pSceneView); - void AddNodeTimelineToGroup(CYITimelineGroup *pGroup, const CYISceneNode *pNode, const CYIString &markerName, YI_UINT64 timelineOffsetInms = 0); + CYITimelineGroup *RecursiveCreateNodeParallelTimelineGroup(CYISceneNode *pNode, CYIString markerName, YI_UINT64 nTimelineOffsetInms = 0); + CYITimelineGroup *RecursiveCreateNodeSerialTimelineGroup(CYISceneNode *pNode, CYIString markerName, YI_UINT64 nTimelineOffsetInms = 0); + void RecursiveBuildNodeParallelTimelineGroup(CYITimelineGroup *pGroup, CYISceneNode *pNode, CYIString markerName, YI_UINT64 nTimelineOffsetInms = 0); + void RecursiveBuildSerialTimelineGroup(CYITimelineGroup *pGroup, CYISceneNode *pNode, CYIString markerName, YI_UINT64 nTimelineOffsetInms = 0); + CYITimeline *GetTimeline(CYISceneView *pSceneView, const CYIString &markerName); + void AddNodeTimelineToGroup(CYITimelineGroup *pGroup, const CYISceneNode *pNode, const CYIString &markerName, YI_UINT64 nTimelineOffsetInms = 0); CYIAnimationToggleController *BuildDirectionAnimationController(CYISceneView *pView, const CYIString &baseName); void StartPropertyAnimation(CYISceneNode *pSceneNode, PropertyAnimationDefinition propertyAnimationDefinition); + bool HasViewFocusInTimelines(CYISceneView *pView); }; #endif