From 46fd4ce5cc65eb53fdd1e11e9ba1fc5c0d0d95d7 Mon Sep 17 00:00:00 2001
From: Leon Styhre <leon@leonstyhre.com>
Date: Sat, 5 Mar 2022 21:04:22 +0100
Subject: [PATCH] Added GIF animation support to GamelistView.

---
 es-app/src/views/GamelistBase.h   |  1 +
 es-app/src/views/GamelistView.cpp | 44 +++++++++++++++++++++++--------
 es-app/src/views/GamelistView.h   |  1 +
 3 files changed, 35 insertions(+), 11 deletions(-)

diff --git a/es-app/src/views/GamelistBase.h b/es-app/src/views/GamelistBase.h
index b942ec67c..8064d7dfe 100644
--- a/es-app/src/views/GamelistBase.h
+++ b/es-app/src/views/GamelistBase.h
@@ -16,6 +16,7 @@
 #include "Window.h"
 #include "components/BadgeComponent.h"
 #include "components/DateTimeComponent.h"
+#include "components/GIFAnimComponent.h"
 #include "components/LottieAnimComponent.h"
 #include "components/RatingComponent.h"
 #include "components/ScrollableContainer.h"
diff --git a/es-app/src/views/GamelistView.cpp b/es-app/src/views/GamelistView.cpp
index 5e6fa6ab0..b0a4b0990 100644
--- a/es-app/src/views/GamelistView.cpp
+++ b/es-app/src/views/GamelistView.cpp
@@ -67,18 +67,16 @@ void GamelistView::onFileChanged(FileData* file, bool reloadGamelist)
 
 void GamelistView::onShow()
 {
-    // Reset any Lottie animations.
+    // Reset any GIF and Lottie animations.
     for (auto& animation : mLottieAnimComponents)
         animation->resetFileAnimation();
 
-    // Reset any Lottie animations.
-    if (mLegacyMode) {
-        for (auto extra : mThemeExtras)
-            extra->resetFileAnimation();
-    }
+    for (auto& animation : mGIFAnimComponents)
+        animation->resetFileAnimation();
 
     mLastUpdated = nullptr;
     GuiComponent::onShow();
+
     if (mLegacyMode)
         legacyUpdateInfoPanel();
     else
@@ -89,6 +87,9 @@ void GamelistView::onTransition()
 {
     for (auto& animation : mLottieAnimComponents)
         animation->setPauseAnimation(true);
+
+    for (auto& animation : mGIFAnimComponents)
+        animation->setPauseAnimation(true);
 }
 
 void GamelistView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
@@ -125,11 +126,32 @@ void GamelistView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
                 if (mVideoComponents.back()->getThemeImageTypes().size() != 0)
                     mVideoComponents.back()->setScrollHide(true);
             }
-            else if (element.second.type == "animation") {
-                mLottieAnimComponents.push_back(std::make_unique<LottieAnimComponent>());
-                mLottieAnimComponents.back()->setDefaultZIndex(35.0f);
-                mLottieAnimComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
-                addChild(mLottieAnimComponents.back().get());
+            else if (element.second.type == "animation" && element.second.has("path")) {
+                const std::string extension {
+                    Utils::FileSystem::getExtension(element.second.get<std::string>("path"))};
+                if (extension == ".json") {
+                    mLottieAnimComponents.push_back(std::make_unique<LottieAnimComponent>());
+                    mLottieAnimComponents.back()->setDefaultZIndex(35.0f);
+                    mLottieAnimComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
+                    addChild(mLottieAnimComponents.back().get());
+                }
+                else if (extension == ".gif") {
+                    mGIFAnimComponents.push_back(std::make_unique<GIFAnimComponent>());
+                    mGIFAnimComponents.back()->setDefaultZIndex(35.0f);
+                    mGIFAnimComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
+                    addChild(mGIFAnimComponents.back().get());
+                }
+                else if (extension == ".") {
+                    LOG(LogWarning)
+                        << "GamelistView::onThemeChanged(): Invalid theme configuration, "
+                           "animation file extension is missing";
+                }
+                else {
+                    LOG(LogWarning)
+                        << "GamelistView::onThemeChanged(): Invalid theme configuration, "
+                           "animation file extension defined as \""
+                        << extension << "\"";
+                }
             }
             else if (element.second.type == "badges") {
                 mBadgeComponents.push_back(std::make_unique<BadgeComponent>());
diff --git a/es-app/src/views/GamelistView.h b/es-app/src/views/GamelistView.h
index b85bfc521..f47fc0bd8 100644
--- a/es-app/src/views/GamelistView.h
+++ b/es-app/src/views/GamelistView.h
@@ -101,6 +101,7 @@ private:
     std::vector<std::unique_ptr<ImageComponent>> mImageComponents;
     std::vector<std::unique_ptr<VideoFFmpegComponent>> mVideoComponents;
     std::vector<std::unique_ptr<LottieAnimComponent>> mLottieAnimComponents;
+    std::vector<std::unique_ptr<GIFAnimComponent>> mGIFAnimComponents;
     std::vector<std::unique_ptr<BadgeComponent>> mBadgeComponents;
     std::vector<std::unique_ptr<RatingComponent>> mRatingComponents;
     std::vector<std::unique_ptr<ScrollableContainer>> mContainerComponents;