From ee12a4366b6cdb5380674d082a9e77ff45ef1594 Mon Sep 17 00:00:00 2001
From: Michele Maione <mikymaione@hotmail.it>
Date: Wed, 10 Apr 2024 16:09:29 +0200
Subject: [PATCH] build: add Windows github build workflow

---
 .github/workflows/windows.yaml     |  50 ++++++++++++++++++++++++++
 assets/favicon.ico                 | Bin 0 -> 28685 bytes
 pubspec.lock                       |  28 +++++++++++++--
 pubspec.yaml                       |  11 ++++++
 windows/CMakeLists.txt             |   8 ++++-
 windows/flutter/CMakeLists.txt     |   7 +++-
 windows/runner/CMakeLists.txt      |   8 +++++
 windows/runner/Runner.rc           |  10 +++---
 windows/runner/flutter_window.cpp  |  10 ++++++
 windows/runner/main.cpp            |   2 +-
 windows/runner/runner.exe.manifest |   2 +-
 windows/runner/utils.cpp           |   9 ++---
 windows/runner/win32_window.cpp    |  55 +++++++++++++++++++++++++----
 windows/runner/win32_window.h      |  20 ++++++-----
 14 files changed, 191 insertions(+), 29 deletions(-)
 create mode 100644 .github/workflows/windows.yaml
 create mode 100644 assets/favicon.ico

diff --git a/.github/workflows/windows.yaml b/.github/workflows/windows.yaml
new file mode 100644
index 0000000000..5acf0da143
--- /dev/null
+++ b/.github/workflows/windows.yaml
@@ -0,0 +1,50 @@
+name: Release Workflow Windows
+
+on:
+  release:
+    types:
+      - created
+
+concurrency:
+  group: release_workflow
+  cancel-in-progress: true
+
+env:
+  REGISTRY: ghcr.io
+  IMAGE_NAME: ${{ github.repository }}
+
+jobs:
+  build-windows:
+    runs-on: windows-latest
+
+    steps:
+      - uses: actions/checkout@v4
+      - run: cat .github/workflows/versions.env >> $GITHUB_ENV
+
+      - uses: subosito/flutter-action@v2
+        with:
+          flutter-version: ${{ env.FLUTTER_VERSION }}
+          cache: true
+
+      - name: Build Windows App
+        run: |
+          flutter config --enable-windows-desktop
+          flutter build windows --release
+
+      - name: Build iss script
+        run: dart run inno_bundle:build --no-app --release --no-installer
+
+      - name: Output config into github output
+        id: envs
+        # thanks to https://github.com/actions/runner/issues/2224#issuecomment-1289925992
+        run: echo $(dart run inno_bundle:build --envs --no-hf --release) | Out-File -FilePath $Env:GITHUB_OUTPUT -Encoding utf8 -Append
+
+      - name: Build installer
+        uses: Minionguyjpro/Inno-Setup-Action@v1.2.2
+        with:
+          path: ./build/windows/x64/installer/Release/inno-script.iss
+
+      - name: Upload release
+        uses: softprops/action-gh-release@v2
+        with:
+          files: ./build/windows/x64/installer/Release/${{ steps.envs.outputs.APP_NAME_CAMEL_CASE }}-x86_64-${{ steps.envs.outputs.APP_VERSION }}-Installer.exe
diff --git a/assets/favicon.ico b/assets/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..3826006233b90cb2044310f498f4b135382d82f5
GIT binary patch
literal 28685
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

literal 0
HcmV?d00001

diff --git a/pubspec.lock b/pubspec.lock
index 24d0e5a8f8..ea47a9738a 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -433,6 +433,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.9.3+1"
+  fixnum:
+    dependency: transitive
+    description:
+      name: fixnum
+      sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.1.0"
   flutter:
     dependency: "direct main"
     description: flutter
@@ -1000,6 +1008,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "4.6.0"
+  inno_bundle:
+    dependency: "direct dev"
+    description:
+      name: inno_bundle
+      sha256: "05b18d03142bfbaf708f340e007a04d50cc24295195c5ddf9f1c102978878335"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.4.1"
   integration_test:
     dependency: "direct dev"
     description: flutter
@@ -1867,6 +1883,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.10.0"
+  sprintf:
+    dependency: transitive
+    description:
+      name: sprintf
+      sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
+      url: "https://pub.dev"
+    source: hosted
+    version: "7.0.0"
   sqflite:
     dependency: transitive
     description:
@@ -2199,10 +2223,10 @@ packages:
     dependency: transitive
     description:
       name: uuid
-      sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313"
+      sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8"
       url: "https://pub.dev"
     source: hosted
-    version: "3.0.7"
+    version: "4.4.0"
   vector_graphics:
     dependency: transitive
     description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 2c7d589437..f822edd3d9 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -101,6 +101,7 @@ dev_dependencies:
   flutter_test:
     sdk: flutter
   import_sorter: ^4.6.0
+  inno_bundle: ^0.4.1
   integration_test:
     sdk: flutter
   license_checker: ^1.6.0
@@ -149,6 +150,16 @@ msix_config:
   sign_msix: false
   install_certificate: false
 
+inno_bundle:
+  id: 7c872d9b-2c56-56de-b8dc-3763cd082da9 # <-- dart run inno_bundle:id --ns "chat.fluffy.fluffychat"
+  name: FluffyChat
+  publisher: Famedly GmbH
+  admin: false
+  installer_icon: assets/favicon.ico
+  url: https://fluffychat.im
+  support_url: https://github.com/krille-chan/fluffychat/wiki
+  updates_url: https://github.com/krille-chan/fluffychat/releases
+
 dependency_overrides:
   # Until https://github.com/mogol/flutter_secure_storage/issues/616 is fixed
   flutter_secure_storage_linux: 1.1.3
diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt
index 1c2b994514..3964503055 100644
--- a/windows/CMakeLists.txt
+++ b/windows/CMakeLists.txt
@@ -8,7 +8,7 @@ set(BINARY_NAME "fluffychat")
 
 # Explicitly opt in to modern CMake behaviors to avoid warnings with recent
 # versions of CMake.
-cmake_policy(SET CMP0063 NEW)
+cmake_policy(VERSION 3.14...3.25)
 
 # Define build configuration option.
 get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
@@ -86,6 +86,12 @@ if(PLUGIN_BUNDLED_LIBRARIES)
     COMPONENT Runtime)
 endif()
 
+# Copy the native assets provided by the build.dart from all packages.
+set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/")
+install(DIRECTORY "${NATIVE_ASSETS_DIR}"
+   DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
+   COMPONENT Runtime)
+
 # Fully re-copy the assets directory on each build to avoid having stale files
 # from a previous install.
 set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
diff --git a/windows/flutter/CMakeLists.txt b/windows/flutter/CMakeLists.txt
index 930d2071a3..903f4899d6 100644
--- a/windows/flutter/CMakeLists.txt
+++ b/windows/flutter/CMakeLists.txt
@@ -10,6 +10,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake)
 # https://github.com/flutter/flutter/issues/57146.
 set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
 
+# Set fallback configurations for older versions of the flutter tool.
+if (NOT DEFINED FLUTTER_TARGET_PLATFORM)
+  set(FLUTTER_TARGET_PLATFORM "windows-x64")
+endif()
+
 # === Flutter Library ===
 set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
 
@@ -92,7 +97,7 @@ add_custom_command(
   COMMAND ${CMAKE_COMMAND} -E env
     ${FLUTTER_TOOL_ENVIRONMENT}
     "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
-      windows-x64 $<CONFIG>
+      ${FLUTTER_TARGET_PLATFORM} $<CONFIG>
   VERBATIM
 )
 add_custom_target(flutter_assemble DEPENDS
diff --git a/windows/runner/CMakeLists.txt b/windows/runner/CMakeLists.txt
index b9e550fba8..394917c053 100644
--- a/windows/runner/CMakeLists.txt
+++ b/windows/runner/CMakeLists.txt
@@ -20,12 +20,20 @@ add_executable(${BINARY_NAME} WIN32
 # that need different build settings.
 apply_standard_settings(${BINARY_NAME})
 
+# Add preprocessor definitions for the build version.
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}")
+
 # Disable Windows macros that collide with C++ standard library functions.
 target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
 
 # Add dependency libraries and include directories. Add any application-specific
 # dependencies here.
 target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
+target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib")
 target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
 
 # Run the Flutter tool portions of the build. This must not be removed.
diff --git a/windows/runner/Runner.rc b/windows/runner/Runner.rc
index 52aa4877ac..c11941c442 100644
--- a/windows/runner/Runner.rc
+++ b/windows/runner/Runner.rc
@@ -60,14 +60,14 @@ IDI_APP_ICON            ICON                    "resources\\app_icon.ico"
 // Version
 //
 
-#ifdef FLUTTER_BUILD_NUMBER
-#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER
+#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD)
+#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD
 #else
-#define VERSION_AS_NUMBER 1,0,0
+#define VERSION_AS_NUMBER 1,0,0,0
 #endif
 
-#ifdef FLUTTER_BUILD_NAME
-#define VERSION_AS_STRING #FLUTTER_BUILD_NAME
+#if defined(FLUTTER_VERSION)
+#define VERSION_AS_STRING FLUTTER_VERSION
 #else
 #define VERSION_AS_STRING "1.0.0"
 #endif
diff --git a/windows/runner/flutter_window.cpp b/windows/runner/flutter_window.cpp
index b43b9095ea..955ee3038f 100644
--- a/windows/runner/flutter_window.cpp
+++ b/windows/runner/flutter_window.cpp
@@ -26,6 +26,16 @@ bool FlutterWindow::OnCreate() {
   }
   RegisterPlugins(flutter_controller_->engine());
   SetChildContent(flutter_controller_->view()->GetNativeWindow());
+
+  flutter_controller_->engine()->SetNextFrameCallback([&]() {
+    this->Show();
+  });
+
+  // Flutter can complete the first frame before the "show window" callback is
+  // registered. The following call ensures a frame is pending to ensure the
+  // window is shown. It is a no-op if the first frame hasn't completed yet.
+  flutter_controller_->ForceRedraw();
+
   return true;
 }
 
diff --git a/windows/runner/main.cpp b/windows/runner/main.cpp
index 3c2f3ab5e8..af7fea68af 100644
--- a/windows/runner/main.cpp
+++ b/windows/runner/main.cpp
@@ -27,7 +27,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
   FlutterWindow window(project);
   Win32Window::Point origin(10, 10);
   Win32Window::Size size(1280, 720);
-  if (!window.CreateAndShow(L"FluffyChat", origin, size)) {
+  if (!window.Create(L"FluffyChat", origin, size)) {
     return EXIT_FAILURE;
   }
   window.SetQuitOnClose(true);
diff --git a/windows/runner/runner.exe.manifest b/windows/runner/runner.exe.manifest
index c977c4a425..a42ea7687c 100644
--- a/windows/runner/runner.exe.manifest
+++ b/windows/runner/runner.exe.manifest
@@ -7,7 +7,7 @@
   </application>
   <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
     <application>
-      <!-- Windows 10 -->
+      <!-- Windows 10 and Windows 11 -->
       <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
       <!-- Windows 8.1 -->
       <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
diff --git a/windows/runner/utils.cpp b/windows/runner/utils.cpp
index f5bf9fa0f5..b2b08734db 100644
--- a/windows/runner/utils.cpp
+++ b/windows/runner/utils.cpp
@@ -47,16 +47,17 @@ std::string Utf8FromUtf16(const wchar_t* utf16_string) {
   }
   int target_length = ::WideCharToMultiByte(
       CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
-      -1, nullptr, 0, nullptr, nullptr);
+      -1, nullptr, 0, nullptr, nullptr)
+    -1; // remove the trailing null character
+  int input_length = (int)wcslen(utf16_string);
   std::string utf8_string;
-  if (target_length == 0 || target_length > utf8_string.max_size()) {
+  if (target_length <= 0 || target_length > utf8_string.max_size()) {
     return utf8_string;
   }
   utf8_string.resize(target_length);
   int converted_length = ::WideCharToMultiByte(
       CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
-      -1, utf8_string.data(),
-      target_length, nullptr, nullptr);
+      input_length, utf8_string.data(), target_length, nullptr, nullptr);
   if (converted_length == 0) {
     return std::string();
   }
diff --git a/windows/runner/win32_window.cpp b/windows/runner/win32_window.cpp
index c10f08dc7d..60608d0fe5 100644
--- a/windows/runner/win32_window.cpp
+++ b/windows/runner/win32_window.cpp
@@ -1,13 +1,31 @@
 #include "win32_window.h"
 
+#include <dwmapi.h>
 #include <flutter_windows.h>
 
 #include "resource.h"
 
 namespace {
 
+/// Window attribute that enables dark mode window decorations.
+///
+/// Redefined in case the developer's machine has a Windows SDK older than
+/// version 10.0.22000.0.
+/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
+#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
+#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
+#endif
+
 constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW";
 
+/// Registry key for app theme preference.
+///
+/// A value of 0 indicates apps should use dark mode. A non-zero or missing
+/// value indicates apps should use light mode.
+constexpr const wchar_t kGetPreferredBrightnessRegKey[] =
+  L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
+constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme";
+
 // The number of Win32Window objects that currently exist.
 static int g_active_window_count = 0;
 
@@ -31,8 +49,8 @@ void EnableFullDpiSupportIfAvailable(HWND hwnd) {
           GetProcAddress(user32_module, "EnableNonClientDpiScaling"));
   if (enable_non_client_dpi_scaling != nullptr) {
     enable_non_client_dpi_scaling(hwnd);
-    FreeLibrary(user32_module);
   }
+  FreeLibrary(user32_module);
 }
 
 }  // namespace
@@ -42,7 +60,7 @@ class WindowClassRegistrar {
  public:
   ~WindowClassRegistrar() = default;
 
-  // Returns the singleton registar instance.
+  // Returns the singleton registrar instance.
   static WindowClassRegistrar* GetInstance() {
     if (!instance_) {
       instance_ = new WindowClassRegistrar();
@@ -102,9 +120,9 @@ Win32Window::~Win32Window() {
   Destroy();
 }
 
-bool Win32Window::CreateAndShow(const std::wstring& title,
-                                const Point& origin,
-                                const Size& size) {
+bool Win32Window::Create(const std::wstring& title,
+                         const Point& origin,
+                         const Size& size) {
   Destroy();
 
   const wchar_t* window_class =
@@ -117,7 +135,7 @@ bool Win32Window::CreateAndShow(const std::wstring& title,
   double scale_factor = dpi / 96.0;
 
   HWND window = CreateWindow(
-      window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+      window_class, title.c_str(), WS_OVERLAPPEDWINDOW,
       Scale(origin.x, scale_factor), Scale(origin.y, scale_factor),
       Scale(size.width, scale_factor), Scale(size.height, scale_factor),
       nullptr, nullptr, GetModuleHandle(nullptr), this);
@@ -126,9 +144,15 @@ bool Win32Window::CreateAndShow(const std::wstring& title,
     return false;
   }
 
+  UpdateTheme(window);
+
   return OnCreate();
 }
 
+bool Win32Window::Show() {
+  return ShowWindow(window_handle_, SW_SHOWNORMAL);
+}
+
 // static
 LRESULT CALLBACK Win32Window::WndProc(HWND const window,
                                       UINT const message,
@@ -188,6 +212,10 @@ Win32Window::MessageHandler(HWND hwnd,
         SetFocus(child_content_);
       }
       return 0;
+
+    case WM_DWMCOLORIZATIONCOLORCHANGED:
+      UpdateTheme(hwnd);
+      return 0;
   }
 
   return DefWindowProc(window_handle_, message, wparam, lparam);
@@ -243,3 +271,18 @@ bool Win32Window::OnCreate() {
 void Win32Window::OnDestroy() {
   // No-op; provided for subclasses.
 }
+
+void Win32Window::UpdateTheme(HWND const window) {
+  DWORD light_mode;
+  DWORD light_mode_size = sizeof(light_mode);
+  LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey,
+                               kGetPreferredBrightnessRegValue,
+                               RRF_RT_REG_DWORD, nullptr, &light_mode,
+                               &light_mode_size);
+
+  if (result == ERROR_SUCCESS) {
+    BOOL enable_dark_mode = light_mode == 0;
+    DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE,
+                          &enable_dark_mode, sizeof(enable_dark_mode));
+  }
+}
diff --git a/windows/runner/win32_window.h b/windows/runner/win32_window.h
index 17ba431125..e901dde684 100644
--- a/windows/runner/win32_window.h
+++ b/windows/runner/win32_window.h
@@ -28,15 +28,16 @@ class Win32Window {
   Win32Window();
   virtual ~Win32Window();
 
-  // Creates and shows a win32 window with |title| and position and size using
+  // Creates a win32 window with |title| that is positioned and sized using
   // |origin| and |size|. New windows are created on the default monitor. Window
   // sizes are specified to the OS in physical pixels, hence to ensure a
-  // consistent size to will treat the width height passed in to this function
-  // as logical pixels and scale to appropriate for the default monitor. Returns
-  // true if the window was created successfully.
-  bool CreateAndShow(const std::wstring& title,
-                     const Point& origin,
-                     const Size& size);
+  // consistent size this function will scale the inputted width and height as
+  // as appropriate for the default monitor. The window is invisible until
+  // |Show| is called. Returns true if the window was created successfully.
+  bool Create(const std::wstring& title, const Point& origin, const Size& size);
+
+  // Show the current window. Returns true if the window was successfully shown.
+  bool Show();
 
   // Release OS resources associated with window.
   void Destroy();
@@ -76,7 +77,7 @@ class Win32Window {
   // OS callback called by message pump. Handles the WM_NCCREATE message which
   // is passed when the non-client area is being created and enables automatic
   // non-client DPI scaling so that the non-client area automatically
-  // responsponds to changes in DPI. All other messages are handled by
+  // responds to changes in DPI. All other messages are handled by
   // MessageHandler.
   static LRESULT CALLBACK WndProc(HWND const window,
                                   UINT const message,
@@ -86,6 +87,9 @@ class Win32Window {
   // Retrieves a class instance pointer for |window|
   static Win32Window* GetThisFromHandle(HWND const window) noexcept;
 
+  // Update the window frame's theme to match the system theme.
+  static void UpdateTheme(HWND const window);
+
   bool quit_on_close_ = false;
 
   // window handle for top level window.