text: // Copyright (c) Microsoft Corporation. All rights reserved.
  // Licensed under the MIT License.
  
  #include "pch.h"
  
  #include "AppThemeModuleUwp.h"
  
  #include <Utils\ValueUtils.h>
  
  #if _MSC_VER <= 1913
  // VC 19 (2015-2017.6) cannot optimize co_await/cppwinrt usage
  #pragma optimize("", off)
  #endif
  
  namespace winrt {
  using namespace Windows::UI::Xaml;
  using namespace Windows::UI::ViewManagement;
  } // namespace winrt
  
  namespace react {
  namespace uwp {
  
  //
  // AppTheme
  //
  
  AppTheme::AppTheme(
      const std::shared_ptr<IReactInstance> &reactInstance,
      const std::shared_ptr<facebook::react::MessageQueueThread>
          &defaultQueueThread)
      : react::windows::AppTheme(),
        m_wkReactInstance(reactInstance),
        m_queueThread(defaultQueueThread) {
    m_currentTheme = winrt::Application::Current().RequestedTheme();
    m_isHighContrast = m_accessibilitySettings.HighContrast();
    m_highContrastColors = getHighContrastColors();
  
    m_highContrastChangedRevoker = m_accessibilitySettings.HighContrastChanged(
        winrt::auto_revoke, [this](const auto &, const auto &) {
          folly::dynamic eventData = folly::dynamic::object(
              "highContrastColors", getHighContrastColors())(
              "isHighContrast", getIsHighContrast());
  
          fireEvent("highContrastChanged", std::move(eventData));
        });
  
    m_colorValuesChangedRevoker = m_uiSettings.ColorValuesChanged(
        winrt::auto_revoke, [this](const auto &, const auto &) {
          m_queueThread->runOnQueue([this]() {
            if (m_currentTheme !=
                    winrt::Application::Current().RequestedTheme() &&
                !m_accessibilitySettings.HighContrast()) {
              m_currentTheme = winrt::Application::Current().RequestedTheme();
  
              folly::dynamic eventData =
                  folly::dynamic::object("currentTheme", getCurrentTheme());
  
              fireEvent("appThemeChanged", std::move(eventData));
            }
          });
        });
  }
  
  AppTheme::~AppTheme() = default;
  
  const std::string AppTheme::getCurrentTheme() {
    return m_currentTheme == winrt::ApplicationTheme::Light ? AppTheme::light
                                                            : AppTheme::dark;
  }
  
  bool AppTheme::getIsHighContrast() {
    return m_accessibilitySettings.HighContrast();
    ;
  }
  
  // Returns the RBG values for the 8 relevant High Contrast elements.
  folly::dynamic AppTheme::getHighContrastColors() {
    winrt::Windows::UI::Color ButtonFaceColor =
        m_uiSettings.UIElementColor(winrt::UIElementType::ButtonFace);
    winrt::Windows::UI::Color ButtonTextColor =
        m_uiSettings.UIElementColor(winrt::UIElementType::ButtonText);
    winrt::Windows::UI::Color GrayTextColor =
        m_uiSettings.UIElementColor(winrt::UIElementType::GrayText);
    winrt::Windows::UI::Color HighlightColor =
        m_uiSettings.UIElementColor(winrt::UIElementType::Highlight);
    winrt::Windows::UI::Color HighlightTextColor =
        m_uiSettings.UIElementColor(winrt::UIElementType::HighlightText);
    winrt::Windows::UI::Color HotlightColor =
        m_uiSettings.UIElementColor(winrt::UIElementType::Hotlight);
    winrt::Windows::UI::Color WindowColor =
        m_uiSettings.UIElementColor(winrt::UIElementType::Window);
    winrt::Windows::UI::Color WindowTextColor =
        m_uiSettings.UIElementColor(winrt::UIElementType::WindowText);
  
    folly::dynamic rbgValues =
        folly::dynamic::object("ButtonFaceColor", formatRGB(ButtonFaceColor))(
            "ButtonTextColor", formatRGB(ButtonTextColor))(
            "GrayTextColor", formatRGB(GrayTextColor))(
            "HighlightColor", formatRGB(HighlightColor))(
            "HighlightTextColor", formatRGB(HighlightTextColor))(
            "HotlightColor", formatRGB(HotlightColor))(
            "WindowColor", formatRGB(WindowColor))(
            "WindowTextColor", formatRGB(WindowTextColor));
    return rbgValues;
  }
  
  std::string AppTheme::formatRGB(winrt::Windows::UI::Color ElementColor) {
    char colorChars[8];
    sprintf_s(
        colorChars,
        "#%02x%02x%02x",
        ElementColor.R,
        ElementColor.G,
        ElementColor.B);
    return colorChars;
  }
  
  void AppTheme::fireEvent(
      std::string const &eventName,
      folly::dynamic &&eventData) {
    if (auto instance = m_wkReactInstance.lock()) {
      instance->CallJsFunction(
          "RCTDeviceEventEmitter",
          "emit",
          folly::dynamic::array(eventName, std::move(eventData)));
    }
  }
  } // namespace uwp
  } // namespace react
  