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