diff --git a/auth/.metadata b/auth/.metadata index 42069fa1b..39ee784e4 100644 --- a/auth/.metadata +++ b/auth/.metadata @@ -1,11 +1,11 @@ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # -# This file should be version controlled. +# This file should be version controlled and should not be manually edited. version: - revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 - channel: unknown + revision: "ba393198430278b6595976de84fe170f553cc728" + channel: "[user-branch]" project_type: app @@ -13,17 +13,26 @@ project_type: app migration: platforms: - platform: root - create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 - base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 + create_revision: ba393198430278b6595976de84fe170f553cc728 + base_revision: ba393198430278b6595976de84fe170f553cc728 + - platform: android + create_revision: ba393198430278b6595976de84fe170f553cc728 + base_revision: ba393198430278b6595976de84fe170f553cc728 + - platform: ios + create_revision: ba393198430278b6595976de84fe170f553cc728 + base_revision: ba393198430278b6595976de84fe170f553cc728 - platform: linux - create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 - base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 + create_revision: ba393198430278b6595976de84fe170f553cc728 + base_revision: ba393198430278b6595976de84fe170f553cc728 - platform: macos - create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 - base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 + create_revision: ba393198430278b6595976de84fe170f553cc728 + base_revision: ba393198430278b6595976de84fe170f553cc728 + - platform: web + create_revision: ba393198430278b6595976de84fe170f553cc728 + base_revision: ba393198430278b6595976de84fe170f553cc728 - platform: windows - create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 - base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 + create_revision: ba393198430278b6595976de84fe170f553cc728 + base_revision: ba393198430278b6595976de84fe170f553cc728 # User provided section diff --git a/auth/pubspec.yaml b/auth/pubspec.yaml index 9ce1ed03e..d67a6b836 100644 --- a/auth/pubspec.yaml +++ b/auth/pubspec.yaml @@ -1,6 +1,6 @@ name: ente_auth description: ente two-factor authenticator -version: 2.0.43+243 +version: 2.0.44+244 publish_to: none environment: diff --git a/auth/windows/CMakeLists.txt b/auth/windows/CMakeLists.txt index 4dcccb5fb..46c315972 100644 --- a/auth/windows/CMakeLists.txt +++ b/auth/windows/CMakeLists.txt @@ -1,13 +1,16 @@ +# Project-level configuration. cmake_minimum_required(VERSION 3.14) project(auth LANGUAGES CXX) +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. set(BINARY_NAME "auth") -cmake_policy(SET CMP0063 NEW) +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(VERSION 3.14...3.25) -set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") - -# Configure build options. +# Define build configuration option. get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(IS_MULTICONFIG) set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" @@ -20,7 +23,7 @@ else() "Debug" "Profile" "Release") endif() endif() - +# Define settings for the Profile build mode. set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") @@ -29,7 +32,11 @@ set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") # Use Unicode for all projects. add_definitions(-DUNICODE -D_UNICODE) -# Compilation ui.settings that should be applied to most targets. +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. function(APPLY_STANDARD_SETTINGS TARGET) target_compile_features(${TARGET} PUBLIC cxx_std_17) target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") @@ -38,14 +45,14 @@ function(APPLY_STANDARD_SETTINGS TARGET) target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") endfunction() -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") - # Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") add_subdirectory(${FLUTTER_MANAGED_DIR}) -# Application build +# Application build; see runner/CMakeLists.txt. add_subdirectory("runner") + # Generated plugin build rules, which manage building the plugins and adding # them to the application. include(flutter/generated_plugins.cmake) @@ -80,6 +87,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/auth/windows/flutter/CMakeLists.txt b/auth/windows/flutter/CMakeLists.txt index 4f2af69bb..903f4899d 100644 --- a/auth/windows/flutter/CMakeLists.txt +++ b/auth/windows/flutter/CMakeLists.txt @@ -1,3 +1,4 @@ +# This file controls Flutter-level build steps. It should not be edited. cmake_minimum_required(VERSION 3.14) set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") diff --git a/auth/windows/runner/CMakeLists.txt b/auth/windows/runner/CMakeLists.txt index de2d8916b..394917c05 100644 --- a/auth/windows/runner/CMakeLists.txt +++ b/auth/windows/runner/CMakeLists.txt @@ -1,6 +1,11 @@ cmake_minimum_required(VERSION 3.14) project(runner LANGUAGES CXX) +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. add_executable(${BINARY_NAME} WIN32 "flutter_window.cpp" "main.cpp" @@ -10,8 +15,26 @@ add_executable(${BINARY_NAME} WIN32 "Runner.rc" "runner.exe.manifest" ) + +# Apply the standard set of build settings. This can be removed for applications +# 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. add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/auth/windows/runner/Runner.rc b/auth/windows/runner/Runner.rc index a55299b45..ecf6f65d3 100644 --- a/auth/windows/runner/Runner.rc +++ b/auth/windows/runner/Runner.rc @@ -63,13 +63,13 @@ IDI_APP_ICON ICON "resources\\app_icon.ico" #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 2,0,43,243 +#define VERSION_AS_NUMBER 1,0,0,0 #endif #if defined(FLUTTER_VERSION) #define VERSION_AS_STRING FLUTTER_VERSION #else -#define VERSION_AS_STRING "2.0.43+243" +#define VERSION_AS_STRING "1.0.0" #endif VS_VERSION_INFO VERSIONINFO @@ -93,7 +93,7 @@ BEGIN VALUE "FileDescription", "ente Auth" "\0" VALUE "FileVersion", VERSION_AS_STRING "\0" VALUE "InternalName", "ente Auth" "\0" - VALUE "LegalCopyright", "Copyright (C) 2022 Ente Technologies, Inc.. All rights reserved." "\0" + VALUE "LegalCopyright", "Copyright (C) 2024 Ente Technologies, Inc.. All rights reserved." "\0" VALUE "OriginalFilename", "auth.exe" "\0" VALUE "ProductName", "ente Auth" "\0" VALUE "ProductVersion", VERSION_AS_STRING "\0" diff --git a/auth/windows/runner/flutter_window.cpp b/auth/windows/runner/flutter_window.cpp index b43b9095e..955ee3038 100644 --- a/auth/windows/runner/flutter_window.cpp +++ b/auth/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/auth/windows/runner/main.cpp b/auth/windows/runner/main.cpp index 6960d6b68..2fbc969c5 100644 --- a/auth/windows/runner/main.cpp +++ b/auth/windows/runner/main.cpp @@ -29,7 +29,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"ente Auth", origin, size)) + if (!window.Create(L"ente Auth", origin, size)) { return EXIT_FAILURE; } diff --git a/auth/windows/runner/resource.h b/auth/windows/runner/resource.h index d7b448fc5..66a65d1e4 100644 --- a/auth/windows/runner/resource.h +++ b/auth/windows/runner/resource.h @@ -1,4 +1,4 @@ -// +//{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by Runner.rc // diff --git a/auth/windows/runner/runner.exe.manifest b/auth/windows/runner/runner.exe.manifest index c977c4a42..a42ea7687 100644 --- a/auth/windows/runner/runner.exe.manifest +++ b/auth/windows/runner/runner.exe.manifest @@ -7,7 +7,7 @@ - + diff --git a/auth/windows/runner/utils.cpp b/auth/windows/runner/utils.cpp index d19bdbbcc..b2b08734d 100644 --- a/auth/windows/runner/utils.cpp +++ b/auth/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); - if (target_length == 0) { - return std::string(); - } + -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()) { + 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/auth/windows/runner/win32_window.cpp b/auth/windows/runner/win32_window.cpp index 26c85a0db..feb7acd3b 100644 --- a/auth/windows/runner/win32_window.cpp +++ b/auth/windows/runner/win32_window.cpp @@ -1,15 +1,32 @@ #include "win32_window.h" +#include #include #include "resource.h" -#include "app_links/app_links_plugin_c_api.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; @@ -37,8 +54,8 @@ namespace if (enable_non_client_dpi_scaling != nullptr) { enable_non_client_dpi_scaling(hwnd); - FreeLibrary(user32_module); } + FreeLibrary(user32_module); } } // namespace @@ -49,7 +66,7 @@ class WindowClassRegistrar public: ~WindowClassRegistrar() = default; - // Returns the singleton registar instance. + // Returns the singleton registrar instance. static WindowClassRegistrar *GetInstance() { if (!instance_) @@ -116,14 +133,10 @@ 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) { - if (SendAppLinkToInstance(title)) - { - return false; - } Destroy(); const wchar_t *window_class = @@ -136,18 +149,24 @@ bool Win32Window::CreateAndShow(const std::wstring &title, double scale_factor = dpi / 96.0; HWND window = CreateWindow( - window_class, title.c_str(), - WS_OVERLAPPEDWINDOW, // do not add WS_VISIBLE since the window will be shown later + 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); - if (!window) - { - return false; - } + if (!window) + { + return false; + } - return OnCreate(); + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() +{ + return ShowWindow(window_handle_, SW_SHOWNORMAL); } // static @@ -220,6 +239,10 @@ Win32Window::MessageHandler(HWND hwnd, SetFocus(child_content_); } return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; } return DefWindowProc(window_handle_, message, wparam, lparam); @@ -286,40 +309,19 @@ void Win32Window::OnDestroy() // No-op; provided for subclasses. } -bool Win32Window::SendAppLinkToInstance(const std::wstring &title) +void Win32Window::UpdateTheme(HWND const window) { - // Find our exact window - HWND hwnd = ::FindWindow(kWindowClassName, title.c_str()); + 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 (hwnd) + if (result == ERROR_SUCCESS) { - // Dispatch new link to current window - SendAppLink(hwnd); - - // (Optional) Restore our window to front in same state - WINDOWPLACEMENT place = {sizeof(WINDOWPLACEMENT)}; - GetWindowPlacement(hwnd, &place); - - switch (place.showCmd) - { - case SW_SHOWMAXIMIZED: - ShowWindow(hwnd, SW_SHOWMAXIMIZED); - break; - case SW_SHOWMINIMIZED: - ShowWindow(hwnd, SW_RESTORE); - break; - default: - ShowWindow(hwnd, SW_NORMAL); - break; - } - - SetWindowPos(0, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE); - SetForegroundWindow(hwnd); - // END Restore - - // Window has been found, don't create another one. - return true; + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); } - - return false; -} \ No newline at end of file +} diff --git a/auth/windows/runner/win32_window.h b/auth/windows/runner/win32_window.h index 9d36b0da3..e3745cd06 100644 --- a/auth/windows/runner/win32_window.h +++ b/auth/windows/runner/win32_window.h @@ -31,15 +31,16 @@ public: 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,15 +77,10 @@ protected: private: friend class WindowClassRegistrar; - // Dispatches link if any. - // This method enables our app to be with a single instance too. - // This is mandatory if you want to catch further links in same app. - bool SendAppLinkToInstance(const std::wstring &title); - // 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, @@ -94,6 +90,9 @@ private: // 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.