Repository: RetroAchievements/RAIntegration
Pull request #890 (2022-05-07 03:31:01)

open editor when pressing New with Rich Presence filter
Prevents assertion failure: https://discord.com/channels/310192285306454017/310195377993416714/972280272047443998

If the filter type is All, the picker dialog still only has Achievement and Leaderboard as choices. Since you can only have one Rich Presence script, I felt that having a button for Rich Presence would just be confusing.


Patch:
diff --git a/src/ui/viewmodels/AssetListViewModel.cpp b/src/ui/viewmodels/AssetListViewModel.cpp
index d83f7101..e4ce62c0 100644
--- a/src/ui/viewmodels/AssetListViewModel.cpp
+++ b/src/ui/viewmodels/AssetListViewModel.cpp
@@ -1617,6 +1617,7 @@ void AssetListViewModel::CreateNew()
     }
 
     FilteredAssets().BeginUpdate();
+    bool bUpdateAsset = true;
 
     auto& pGameContext = ra::services::ServiceLocator::GetMutable<ra::data::context::GameContext>();
     ra::data::models::AssetModelBase* pNewAsset = nullptr;
@@ -1632,17 +1633,36 @@ void AssetListViewModel::CreateNew()
             pNewAsset = &pGameContext.Assets().NewLeaderboard();
             break;
 
+        case ra::data::models::AssetType::RichPresence:
+            pNewAsset = pGameContext.Assets().FindRichPresence();
+            if (pNewAsset != nullptr)
+            {
+                bUpdateAsset = false;
+            }
+            else
+            {
+                RA_LOG_INFO("Creating rich presence");
+                auto pRichPresence = std::make_unique<ra::data::models::RichPresenceModel>();
+                pRichPresence->CreateServerCheckpoint();
+                pRichPresence->CreateLocalCheckpoint();
+                pNewAsset = &pGameContext.Assets().Append(std::move(pRichPresence));
+            }
+            break;
+
         default:
             break;
     }
 
     Expects(pNewAsset != nullptr);
 
-    const auto& pUserContext = ra::services::ServiceLocator::GetMutable<ra::data::context::UserContext>();
-    pNewAsset->SetAuthor(ra::Widen(pUserContext.GetDisplayName()));
-    pNewAsset->SetCategory(ra::data::models::AssetCategory::Local);
-    pNewAsset->UpdateServerCheckpoint();
-    pNewAsset->SetNew();
+    if (bUpdateAsset)
+    {
+        const auto& pUserContext = ra::services::ServiceLocator::GetMutable<ra::data::context::UserContext>();
+        pNewAsset->SetAuthor(ra::Widen(pUserContext.GetDisplayName()));
+        pNewAsset->SetCategory(ra::data::models::AssetCategory::Local);
+        pNewAsset->UpdateServerCheckpoint();
+        pNewAsset->SetNew();
+    }
 
     EnsureAppearsInFilteredList(*pNewAsset);
 
diff --git a/src/ui/viewmodels/RichPresenceMonitorViewModel.cpp b/src/ui/viewmodels/RichPresenceMonitorViewModel.cpp
index d836f49d..b1d0631d 100644
--- a/src/ui/viewmodels/RichPresenceMonitorViewModel.cpp
+++ b/src/ui/viewmodels/RichPresenceMonitorViewModel.cpp
@@ -44,8 +44,18 @@ void RichPresenceMonitorViewModel::StartMonitoring()
         case MonitorState::None:
             // not monitoring - start doing so.
             m_nState = MonitorState::Active;
-            UpdateDisplayString();
             m_tRichPresenceFileTime = GetRichPresenceModified();
+            if (m_tRichPresenceFileTime)
+            {
+                auto& pGameContext = ra::services::ServiceLocator::GetMutable<ra::data::context::GameContext>();
+                auto* pRichPresence = pGameContext.Assets().FindRichPresence();
+                if (pRichPresence != nullptr)
+                {
+                    pRichPresence->ReloadRichPresenceScript();
+                    pRichPresence->Activate();
+                }
+            }
+            UpdateDisplayString();
             ScheduleUpdateDisplayString();
             break;
 


Test patch:
diff --git a/tests/ui/viewmodels/AssetListViewModel_Tests.cpp b/tests/ui/viewmodels/AssetListViewModel_Tests.cpp
index 8df44448..e6c55749 100644
--- a/tests/ui/viewmodels/AssetListViewModel_Tests.cpp
+++ b/tests/ui/viewmodels/AssetListViewModel_Tests.cpp
@@ -3290,6 +3290,89 @@ public:
         Assert::IsFalse(bEditorShown);
     }
 
+    TEST_METHOD(TestCreateNewRichPresenceFilterTypeRichPresence)
+    {
+        AssetListViewModelHarness vmAssetList;
+        ra::services::mocks::MockFileSystem mockFileSystem;
+        ra::services::impl::FileLocalStorage storage(mockFileSystem);
+        ra::services::ServiceLocator::ServiceOverride<ra::services::ILocalStorage> storageOverride(&storage);
+
+        vmAssetList.mockUserContext.Initialize("User1", "FOO");
+        vmAssetList.MockGameId(22U);
+        vmAssetList.AddAchievement(AssetCategory::Core, 5, L"Test1", L"Desc1", L"12345", "0xH1234=1");
+        vmAssetList.AddLeaderboard(ra::data::models::AssetCategory::Core, L"Leaderboard1");
+        vmAssetList.SetAssetTypeFilter(ra::data::models::AssetType::RichPresence);
+        vmAssetList.ForceUpdateButtons();
+
+        Assert::AreEqual({ 2U }, vmAssetList.mockGameContext.Assets().Count());
+        Assert::AreEqual({ 0U }, vmAssetList.FilteredAssets().Count());
+
+        Assert::IsTrue(vmAssetList.CanCreate());
+        vmAssetList.CreateNew();
+
+        // new Local rich presence should be created and focused
+        Assert::AreEqual({ 3U }, vmAssetList.mockGameContext.Assets().Count());
+        Assert::AreEqual({ 1U }, vmAssetList.FilteredAssets().Count());
+        Assert::AreEqual(AssetListViewModel::FilterCategory::Local, vmAssetList.GetFilterCategory());
+        Assert::AreEqual(ra::data::models::AssetType::RichPresence, vmAssetList.GetAssetTypeFilter());
+
+        const auto* pAsset = vmAssetList.FilteredAssets().GetItemAt(0);
+        Expects(pAsset != nullptr);
+        Assert::IsTrue(pAsset->IsSelected());
+        Assert::AreEqual(std::wstring(L"Rich Presence"), pAsset->GetLabel());
+        Assert::AreEqual(AssetCategory::Local, pAsset->GetCategory());
+        Assert::AreEqual(AssetState::Inactive, pAsset->GetState());
+        Assert::AreEqual(AssetChanges::New, pAsset->GetChanges());
+        Assert::AreEqual({ 0 }, pAsset->GetId());
+        Assert::AreEqual(0, pAsset->GetPoints());
+
+        // and loaded externally
+        Assert::IsFalse(vmAssetList.mockWindowManager.AssetEditor.IsVisible());
+        Assert::AreEqual(std::string("file://localhost/./RACache/Data/22-Rich.txt"), vmAssetList.mockDesktop.LastOpenedUrl());
+    }
+
+    TEST_METHOD(TestCreateNewRichPresenceFilterTypeRichPresenceExisting)
+    {
+        AssetListViewModelHarness vmAssetList;
+        ra::services::mocks::MockFileSystem mockFileSystem;
+        ra::services::impl::FileLocalStorage storage(mockFileSystem);
+        ra::services::ServiceLocator::ServiceOverride<ra::services::ILocalStorage> storageOverride(&storage);
+
+        vmAssetList.mockUserContext.Initialize("User1", "FOO");
+        vmAssetList.MockGameId(22U);
+        vmAssetList.AddAchievement(AssetCategory::Core, 5, L"Test1", L"Desc1", L"12345", "0xH1234=1");
+        vmAssetList.AddLeaderboard(ra::data::models::AssetCategory::Core, L"Leaderboard1");
+        vmAssetList.AddRichPresence("Display\nTest\n");
+        vmAssetList.SetAssetTypeFilter(ra::data::models::AssetType::RichPresence);
+        vmAssetList.ForceUpdateButtons();
+
+        Assert::AreEqual({ 3U }, vmAssetList.mockGameContext.Assets().Count());
+        Assert::AreEqual({ 1U }, vmAssetList.FilteredAssets().Count());
+
+        Assert::IsTrue(vmAssetList.CanCreate());
+        vmAssetList.CreateNew();
+
+        // existing Local rich presence should be focused
+        Assert::AreEqual({ 3U }, vmAssetList.mockGameContext.Assets().Count());
+        Assert::AreEqual({ 1U }, vmAssetList.FilteredAssets().Count());
+        Assert::AreEqual(AssetListViewModel::FilterCategory::Core, vmAssetList.GetFilterCategory());
+        Assert::AreEqual(ra::data::models::AssetType::RichPresence, vmAssetList.GetAssetTypeFilter());
+
+        const auto* pAsset = vmAssetList.FilteredAssets().GetItemAt(0);
+        Expects(pAsset != nullptr);
+        Assert::IsTrue(pAsset->IsSelected());
+        Assert::AreEqual(std::wstring(L"Rich Presence"), pAsset->GetLabel());
+        Assert::AreEqual(AssetCategory::Core, pAsset->GetCategory());
+        Assert::AreEqual(AssetState::Inactive, pAsset->GetState());
+        Assert::AreEqual(AssetChanges::None, pAsset->GetChanges());
+        Assert::AreEqual({ 0 }, pAsset->GetId());
+        Assert::AreEqual(0, pAsset->GetPoints());
+
+        // and loaded externally
+        Assert::IsFalse(vmAssetList.mockWindowManager.AssetEditor.IsVisible());
+        Assert::AreEqual(std::string("file://localhost/./RACache/Data/22-Rich.txt"), vmAssetList.mockDesktop.LastOpenedUrl());
+    }
+
     TEST_METHOD(TestCloneSingle)
     {
         AssetListViewModelHarness vmAssetList;