diff --git a/04-flutter-desktop/fluent_design_app - navigation/.metadata b/04-flutter-desktop/fluent_design_app - navigation/.metadata index d411447..6d28d48 100644 --- a/04-flutter-desktop/fluent_design_app - navigation/.metadata +++ b/04-flutter-desktop/fluent_design_app - navigation/.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: 18a827f3933c19f51862dde3fa472197683249d6 - channel: stable + revision: "ac4e799d237041cf905519190471f657b657155a" + channel: "stable" project_type: app @@ -13,11 +13,11 @@ project_type: app migration: platforms: - platform: root - create_revision: 18a827f3933c19f51862dde3fa472197683249d6 - base_revision: 18a827f3933c19f51862dde3fa472197683249d6 + create_revision: ac4e799d237041cf905519190471f657b657155a + base_revision: ac4e799d237041cf905519190471f657b657155a - platform: windows - create_revision: 18a827f3933c19f51862dde3fa472197683249d6 - base_revision: 18a827f3933c19f51862dde3fa472197683249d6 + create_revision: ac4e799d237041cf905519190471f657b657155a + base_revision: ac4e799d237041cf905519190471f657b657155a # User provided section diff --git a/04-flutter-desktop/fluent_design_app - navigation/lib/main.dart b/04-flutter-desktop/fluent_design_app - navigation/lib/main.dart index 50b147b..5abb8a0 100644 --- a/04-flutter-desktop/fluent_design_app - navigation/lib/main.dart +++ b/04-flutter-desktop/fluent_design_app - navigation/lib/main.dart @@ -11,7 +11,7 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { return FluentApp( title: 'Flutter Demo', - theme: ThemeData( + theme: FluentThemeData( accentColor: Colors.blue, ), home: const HomeScreen(), @@ -42,10 +42,6 @@ class FirstScreen extends StatelessWidget { child: const Text('Normal Button'), onPressed: () {}, ), - TextButton( - child: const Text('Text Button'), - onPressed: () {}, - ), FilledButton( child: const Text('Filled Button'), onPressed: () {}, diff --git a/04-flutter-desktop/fluent_design_app - navigation/pubspec.lock b/04-flutter-desktop/fluent_design_app - navigation/pubspec.lock index b90c34e..851ef37 100644 --- a/04-flutter-desktop/fluent_design_app - navigation/pubspec.lock +++ b/04-flutter-desktop/fluent_design_app - navigation/pubspec.lock @@ -5,58 +5,66 @@ packages: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.13.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "5bbf32bc9e518d41ec49718e2931cd4527292c9b0c6d2dffcf7fe6b9a8a8cf72" + url: "https://pub.dev" source: hosted version: "2.1.0" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.4.0" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.19.1" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" source: hosted version: "1.0.5" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.3" fluent_ui: dependency: "direct main" description: name: fluent_ui - url: "https://pub.dartlang.org" + sha256: "64223237a1d873b426d578d4d8b2703b8f7d9731608a5beb7b9745194568d484" + url: "https://pub.dev" source: hosted - version: "4.0.1" + version: "4.13.0" flutter: dependency: "direct main" description: flutter @@ -66,7 +74,8 @@ packages: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + url: "https://pub.dev" source: hosted version: "2.0.1" flutter_localizations: @@ -83,112 +92,175 @@ packages: dependency: transitive description: name: intl - url: "https://pub.dartlang.org" + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + url: "https://pub.dev" + source: hosted + version: "0.20.2" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" + url: "https://pub.dev" + source: hosted + version: "11.0.2" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" + url: "https://pub.dev" + source: hosted + version: "3.0.10" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" + url: "https://pub.dev" source: hosted - version: "0.17.0" + version: "3.0.2" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: "5cfd6509652ff5e7fe149b6df4859e687fca9048437857cb2e65c8d780f396e3" + url: "https://pub.dev" source: hosted version: "2.0.0" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.17" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" source: hosted - version: "0.1.5" + version: "0.11.1" + math_expressions: + dependency: transitive + description: + name: math_expressions + sha256: "218dc65bed4726562bb31c53d8daa3cc824664b26fb72d77bc592757edf74ba0" + url: "https://pub.dev" + source: hosted + version: "2.7.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.16.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" + url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "6.1.0" recase: dependency: transitive description: name: recase - url: "https://pub.dartlang.org" + sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 + url: "https://pub.dev" source: hosted version: "4.1.0" scroll_pos: dependency: transitive description: name: scroll_pos - url: "https://pub.dartlang.org" + sha256: cebf602b2dd939de6832bb902ffefb574608d1b84f420b82b381a4007d3c1e1b + url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.5.0" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: e3320978e3715725e62f04358fd249c1efe5999297b2c6acd626a817593281b0 + url: "https://pub.dev" source: hosted version: "1.9.0" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.4" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "862015c5db1f3f3c4ea3b94dc2490363a84262994b88902315ed74be1155612f" + url: "https://pub.dev" source: hosted version: "1.1.1" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" + url: "https://pub.dev" source: hosted - version: "0.4.12" + version: "0.7.6" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + url: "https://pub.dev" + source: hosted + version: "2.2.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "15.0.2" sdks: - dart: ">=2.18.2 <3.0.0" - flutter: ">=3.0.0" + dart: ">=3.9.2 <4.0.0" + flutter: ">=3.32.0" diff --git a/04-flutter-desktop/fluent_design_app - navigation/pubspec.yaml b/04-flutter-desktop/fluent_design_app - navigation/pubspec.yaml index 1c84414..ada2324 100644 --- a/04-flutter-desktop/fluent_design_app - navigation/pubspec.yaml +++ b/04-flutter-desktop/fluent_design_app - navigation/pubspec.yaml @@ -1,19 +1,19 @@ name: fluent_design_app description: A new Flutter project. -publish_to: 'none' +publish_to: "none" version: 1.0.0+1 environment: - sdk: '>=2.18.2 <3.0.0' + sdk: ^3.9.2 dependencies: flutter: sdk: flutter cupertino_icons: ^1.0.2 - fluent_ui: ^4.0.1 + fluent_ui: ^4.13.0 dev_dependencies: flutter_test: diff --git a/04-flutter-desktop/fluent_design_app - navigation/windows/CMakeLists.txt b/04-flutter-desktop/fluent_design_app - navigation/windows/CMakeLists.txt index c23cb9e..978452d 100644 --- a/04-flutter-desktop/fluent_design_app - navigation/windows/CMakeLists.txt +++ b/04-flutter-desktop/fluent_design_app - navigation/windows/CMakeLists.txt @@ -8,7 +8,7 @@ set(BINARY_NAME "fluent_design_app") # 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) @@ -52,6 +52,7 @@ add_subdirectory(${FLUTTER_MANAGED_DIR}) # 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) @@ -86,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/04-flutter-desktop/fluent_design_app - navigation/windows/flutter/CMakeLists.txt b/04-flutter-desktop/fluent_design_app - navigation/windows/flutter/CMakeLists.txt index 930d207..903f489 100644 --- a/04-flutter-desktop/fluent_design_app - navigation/windows/flutter/CMakeLists.txt +++ b/04-flutter-desktop/fluent_design_app - navigation/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 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS diff --git a/04-flutter-desktop/fluent_design_app - navigation/windows/runner/CMakeLists.txt b/04-flutter-desktop/fluent_design_app - navigation/windows/runner/CMakeLists.txt index 17411a8..394917c 100644 --- a/04-flutter-desktop/fluent_design_app - navigation/windows/runner/CMakeLists.txt +++ b/04-flutter-desktop/fluent_design_app - navigation/windows/runner/CMakeLists.txt @@ -33,6 +33,7 @@ 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/04-flutter-desktop/fluent_design_app - navigation/windows/runner/Runner.rc b/04-flutter-desktop/fluent_design_app - navigation/windows/runner/Runner.rc index 13e7847..f20f519 100644 --- a/04-flutter-desktop/fluent_design_app - navigation/windows/runner/Runner.rc +++ b/04-flutter-desktop/fluent_design_app - navigation/windows/runner/Runner.rc @@ -89,11 +89,11 @@ BEGIN BEGIN BLOCK "040904e4" BEGIN - VALUE "CompanyName", "com.example" "\0" + VALUE "CompanyName", "com.dicoding" "\0" VALUE "FileDescription", "fluent_design_app" "\0" VALUE "FileVersion", VERSION_AS_STRING "\0" VALUE "InternalName", "fluent_design_app" "\0" - VALUE "LegalCopyright", "Copyright (C) 2022 com.example. All rights reserved." "\0" + VALUE "LegalCopyright", "Copyright (C) 2025 com.dicoding. All rights reserved." "\0" VALUE "OriginalFilename", "fluent_design_app.exe" "\0" VALUE "ProductName", "fluent_design_app" "\0" VALUE "ProductVersion", VERSION_AS_STRING "\0" diff --git a/04-flutter-desktop/fluent_design_app - navigation/windows/runner/flutter_window.cpp b/04-flutter-desktop/fluent_design_app - navigation/windows/runner/flutter_window.cpp index b43b909..955ee30 100644 --- a/04-flutter-desktop/fluent_design_app - navigation/windows/runner/flutter_window.cpp +++ b/04-flutter-desktop/fluent_design_app - navigation/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/04-flutter-desktop/fluent_design_app - navigation/windows/runner/main.cpp b/04-flutter-desktop/fluent_design_app - navigation/windows/runner/main.cpp index 75f31ac..f718645 100644 --- a/04-flutter-desktop/fluent_design_app - navigation/windows/runner/main.cpp +++ b/04-flutter-desktop/fluent_design_app - navigation/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"fluent_design_app", origin, size)) { + if (!window.Create(L"fluent_design_app", origin, size)) { return EXIT_FAILURE; } window.SetQuitOnClose(true); diff --git a/04-flutter-desktop/fluent_design_app - navigation/windows/runner/runner.exe.manifest b/04-flutter-desktop/fluent_design_app - navigation/windows/runner/runner.exe.manifest index a42ea76..153653e 100644 --- a/04-flutter-desktop/fluent_design_app - navigation/windows/runner/runner.exe.manifest +++ b/04-flutter-desktop/fluent_design_app - navigation/windows/runner/runner.exe.manifest @@ -9,12 +9,6 @@ - - - - - - diff --git a/04-flutter-desktop/fluent_design_app - navigation/windows/runner/utils.cpp b/04-flutter-desktop/fluent_design_app - navigation/windows/runner/utils.cpp index f5bf9fa..3a0b465 100644 --- a/04-flutter-desktop/fluent_design_app - navigation/windows/runner/utils.cpp +++ b/04-flutter-desktop/fluent_design_app - navigation/windows/runner/utils.cpp @@ -45,9 +45,11 @@ std::string Utf8FromUtf16(const wchar_t* utf16_string) { if (utf16_string == nullptr) { return std::string(); } - int target_length = ::WideCharToMultiByte( + unsigned 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()) { return utf8_string; @@ -55,8 +57,7 @@ std::string Utf8FromUtf16(const wchar_t* utf16_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/04-flutter-desktop/fluent_design_app - navigation/windows/runner/win32_window.cpp b/04-flutter-desktop/fluent_design_app - navigation/windows/runner/win32_window.cpp index c10f08d..60608d0 100644 --- a/04-flutter-desktop/fluent_design_app - navigation/windows/runner/win32_window.cpp +++ b/04-flutter-desktop/fluent_design_app - navigation/windows/runner/win32_window.cpp @@ -1,13 +1,31 @@ #include "win32_window.h" +#include #include #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/04-flutter-desktop/fluent_design_app - navigation/windows/runner/win32_window.h b/04-flutter-desktop/fluent_design_app - navigation/windows/runner/win32_window.h index 17ba431..e901dde 100644 --- a/04-flutter-desktop/fluent_design_app - navigation/windows/runner/win32_window.h +++ b/04-flutter-desktop/fluent_design_app - navigation/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. diff --git a/04-flutter-desktop/fluent_design_app - widget/.metadata b/04-flutter-desktop/fluent_design_app - widget/.metadata index d411447..6d28d48 100644 --- a/04-flutter-desktop/fluent_design_app - widget/.metadata +++ b/04-flutter-desktop/fluent_design_app - widget/.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: 18a827f3933c19f51862dde3fa472197683249d6 - channel: stable + revision: "ac4e799d237041cf905519190471f657b657155a" + channel: "stable" project_type: app @@ -13,11 +13,11 @@ project_type: app migration: platforms: - platform: root - create_revision: 18a827f3933c19f51862dde3fa472197683249d6 - base_revision: 18a827f3933c19f51862dde3fa472197683249d6 + create_revision: ac4e799d237041cf905519190471f657b657155a + base_revision: ac4e799d237041cf905519190471f657b657155a - platform: windows - create_revision: 18a827f3933c19f51862dde3fa472197683249d6 - base_revision: 18a827f3933c19f51862dde3fa472197683249d6 + create_revision: ac4e799d237041cf905519190471f657b657155a + base_revision: ac4e799d237041cf905519190471f657b657155a # User provided section diff --git a/04-flutter-desktop/fluent_design_app - widget/lib/main.dart b/04-flutter-desktop/fluent_design_app - widget/lib/main.dart index 770b430..f67001c 100644 --- a/04-flutter-desktop/fluent_design_app - widget/lib/main.dart +++ b/04-flutter-desktop/fluent_design_app - widget/lib/main.dart @@ -11,7 +11,7 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { return FluentApp( title: 'Flutter Demo', - theme: ThemeData( + theme: FluentThemeData( accentColor: Colors.blue, ), debugShowCheckedModeBanner: false, @@ -50,10 +50,6 @@ class FirstScreen extends StatelessWidget { ); }, ), - TextButton( - child: const Text('Text Button'), - onPressed: () {}, - ), FilledButton( child: const Text('Filled Button'), onPressed: () {}, @@ -75,8 +71,8 @@ class SecondScreen extends StatelessWidget { Widget build(BuildContext context) { return NavigationView( content: ScaffoldPage( - header: const PageHeader( - title: Text("This is Second Screen"), + header: PageHeader( + title: const Text("This is Second Screen"), leading: IconButton( icon: const Icon(FluentIcons.back), onPressed: () {}, diff --git a/04-flutter-desktop/fluent_design_app - widget/pubspec.lock b/04-flutter-desktop/fluent_design_app - widget/pubspec.lock index b90c34e..851ef37 100644 --- a/04-flutter-desktop/fluent_design_app - widget/pubspec.lock +++ b/04-flutter-desktop/fluent_design_app - widget/pubspec.lock @@ -5,58 +5,66 @@ packages: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.13.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "5bbf32bc9e518d41ec49718e2931cd4527292c9b0c6d2dffcf7fe6b9a8a8cf72" + url: "https://pub.dev" source: hosted version: "2.1.0" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.4.0" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.19.1" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" source: hosted version: "1.0.5" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.3" fluent_ui: dependency: "direct main" description: name: fluent_ui - url: "https://pub.dartlang.org" + sha256: "64223237a1d873b426d578d4d8b2703b8f7d9731608a5beb7b9745194568d484" + url: "https://pub.dev" source: hosted - version: "4.0.1" + version: "4.13.0" flutter: dependency: "direct main" description: flutter @@ -66,7 +74,8 @@ packages: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + url: "https://pub.dev" source: hosted version: "2.0.1" flutter_localizations: @@ -83,112 +92,175 @@ packages: dependency: transitive description: name: intl - url: "https://pub.dartlang.org" + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + url: "https://pub.dev" + source: hosted + version: "0.20.2" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" + url: "https://pub.dev" + source: hosted + version: "11.0.2" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" + url: "https://pub.dev" + source: hosted + version: "3.0.10" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" + url: "https://pub.dev" source: hosted - version: "0.17.0" + version: "3.0.2" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: "5cfd6509652ff5e7fe149b6df4859e687fca9048437857cb2e65c8d780f396e3" + url: "https://pub.dev" source: hosted version: "2.0.0" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.17" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" source: hosted - version: "0.1.5" + version: "0.11.1" + math_expressions: + dependency: transitive + description: + name: math_expressions + sha256: "218dc65bed4726562bb31c53d8daa3cc824664b26fb72d77bc592757edf74ba0" + url: "https://pub.dev" + source: hosted + version: "2.7.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.16.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" + url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "6.1.0" recase: dependency: transitive description: name: recase - url: "https://pub.dartlang.org" + sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 + url: "https://pub.dev" source: hosted version: "4.1.0" scroll_pos: dependency: transitive description: name: scroll_pos - url: "https://pub.dartlang.org" + sha256: cebf602b2dd939de6832bb902ffefb574608d1b84f420b82b381a4007d3c1e1b + url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.5.0" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: e3320978e3715725e62f04358fd249c1efe5999297b2c6acd626a817593281b0 + url: "https://pub.dev" source: hosted version: "1.9.0" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.4" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "862015c5db1f3f3c4ea3b94dc2490363a84262994b88902315ed74be1155612f" + url: "https://pub.dev" source: hosted version: "1.1.1" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" + url: "https://pub.dev" source: hosted - version: "0.4.12" + version: "0.7.6" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + url: "https://pub.dev" + source: hosted + version: "2.2.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "15.0.2" sdks: - dart: ">=2.18.2 <3.0.0" - flutter: ">=3.0.0" + dart: ">=3.9.2 <4.0.0" + flutter: ">=3.32.0" diff --git a/04-flutter-desktop/fluent_design_app - widget/pubspec.yaml b/04-flutter-desktop/fluent_design_app - widget/pubspec.yaml index 1c84414..ada2324 100644 --- a/04-flutter-desktop/fluent_design_app - widget/pubspec.yaml +++ b/04-flutter-desktop/fluent_design_app - widget/pubspec.yaml @@ -1,19 +1,19 @@ name: fluent_design_app description: A new Flutter project. -publish_to: 'none' +publish_to: "none" version: 1.0.0+1 environment: - sdk: '>=2.18.2 <3.0.0' + sdk: ^3.9.2 dependencies: flutter: sdk: flutter cupertino_icons: ^1.0.2 - fluent_ui: ^4.0.1 + fluent_ui: ^4.13.0 dev_dependencies: flutter_test: diff --git a/04-flutter-desktop/fluent_design_app - widget/windows/CMakeLists.txt b/04-flutter-desktop/fluent_design_app - widget/windows/CMakeLists.txt index c23cb9e..978452d 100644 --- a/04-flutter-desktop/fluent_design_app - widget/windows/CMakeLists.txt +++ b/04-flutter-desktop/fluent_design_app - widget/windows/CMakeLists.txt @@ -8,7 +8,7 @@ set(BINARY_NAME "fluent_design_app") # 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) @@ -52,6 +52,7 @@ add_subdirectory(${FLUTTER_MANAGED_DIR}) # 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) @@ -86,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/04-flutter-desktop/fluent_design_app - widget/windows/flutter/CMakeLists.txt b/04-flutter-desktop/fluent_design_app - widget/windows/flutter/CMakeLists.txt index 930d207..903f489 100644 --- a/04-flutter-desktop/fluent_design_app - widget/windows/flutter/CMakeLists.txt +++ b/04-flutter-desktop/fluent_design_app - widget/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 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS diff --git a/04-flutter-desktop/fluent_design_app - widget/windows/runner/CMakeLists.txt b/04-flutter-desktop/fluent_design_app - widget/windows/runner/CMakeLists.txt index 17411a8..394917c 100644 --- a/04-flutter-desktop/fluent_design_app - widget/windows/runner/CMakeLists.txt +++ b/04-flutter-desktop/fluent_design_app - widget/windows/runner/CMakeLists.txt @@ -33,6 +33,7 @@ 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/04-flutter-desktop/fluent_design_app - widget/windows/runner/Runner.rc b/04-flutter-desktop/fluent_design_app - widget/windows/runner/Runner.rc index 13e7847..f20f519 100644 --- a/04-flutter-desktop/fluent_design_app - widget/windows/runner/Runner.rc +++ b/04-flutter-desktop/fluent_design_app - widget/windows/runner/Runner.rc @@ -89,11 +89,11 @@ BEGIN BEGIN BLOCK "040904e4" BEGIN - VALUE "CompanyName", "com.example" "\0" + VALUE "CompanyName", "com.dicoding" "\0" VALUE "FileDescription", "fluent_design_app" "\0" VALUE "FileVersion", VERSION_AS_STRING "\0" VALUE "InternalName", "fluent_design_app" "\0" - VALUE "LegalCopyright", "Copyright (C) 2022 com.example. All rights reserved." "\0" + VALUE "LegalCopyright", "Copyright (C) 2025 com.dicoding. All rights reserved." "\0" VALUE "OriginalFilename", "fluent_design_app.exe" "\0" VALUE "ProductName", "fluent_design_app" "\0" VALUE "ProductVersion", VERSION_AS_STRING "\0" diff --git a/04-flutter-desktop/fluent_design_app - widget/windows/runner/flutter_window.cpp b/04-flutter-desktop/fluent_design_app - widget/windows/runner/flutter_window.cpp index b43b909..955ee30 100644 --- a/04-flutter-desktop/fluent_design_app - widget/windows/runner/flutter_window.cpp +++ b/04-flutter-desktop/fluent_design_app - widget/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/04-flutter-desktop/fluent_design_app - widget/windows/runner/main.cpp b/04-flutter-desktop/fluent_design_app - widget/windows/runner/main.cpp index 75f31ac..f718645 100644 --- a/04-flutter-desktop/fluent_design_app - widget/windows/runner/main.cpp +++ b/04-flutter-desktop/fluent_design_app - widget/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"fluent_design_app", origin, size)) { + if (!window.Create(L"fluent_design_app", origin, size)) { return EXIT_FAILURE; } window.SetQuitOnClose(true); diff --git a/04-flutter-desktop/fluent_design_app - widget/windows/runner/runner.exe.manifest b/04-flutter-desktop/fluent_design_app - widget/windows/runner/runner.exe.manifest index a42ea76..153653e 100644 --- a/04-flutter-desktop/fluent_design_app - widget/windows/runner/runner.exe.manifest +++ b/04-flutter-desktop/fluent_design_app - widget/windows/runner/runner.exe.manifest @@ -9,12 +9,6 @@ - - - - - - diff --git a/04-flutter-desktop/fluent_design_app - widget/windows/runner/utils.cpp b/04-flutter-desktop/fluent_design_app - widget/windows/runner/utils.cpp index f5bf9fa..3a0b465 100644 --- a/04-flutter-desktop/fluent_design_app - widget/windows/runner/utils.cpp +++ b/04-flutter-desktop/fluent_design_app - widget/windows/runner/utils.cpp @@ -45,9 +45,11 @@ std::string Utf8FromUtf16(const wchar_t* utf16_string) { if (utf16_string == nullptr) { return std::string(); } - int target_length = ::WideCharToMultiByte( + unsigned 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()) { return utf8_string; @@ -55,8 +57,7 @@ std::string Utf8FromUtf16(const wchar_t* utf16_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/04-flutter-desktop/fluent_design_app - widget/windows/runner/win32_window.cpp b/04-flutter-desktop/fluent_design_app - widget/windows/runner/win32_window.cpp index c10f08d..60608d0 100644 --- a/04-flutter-desktop/fluent_design_app - widget/windows/runner/win32_window.cpp +++ b/04-flutter-desktop/fluent_design_app - widget/windows/runner/win32_window.cpp @@ -1,13 +1,31 @@ #include "win32_window.h" +#include #include #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/04-flutter-desktop/fluent_design_app - widget/windows/runner/win32_window.h b/04-flutter-desktop/fluent_design_app - widget/windows/runner/win32_window.h index 17ba431..e901dde 100644 --- a/04-flutter-desktop/fluent_design_app - widget/windows/runner/win32_window.h +++ b/04-flutter-desktop/fluent_design_app - widget/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. diff --git a/04-flutter-desktop/macos_theme_app/.gitignore b/04-flutter-desktop/macos_theme_app/.gitignore index 24476c5..6c31954 100644 --- a/04-flutter-desktop/macos_theme_app/.gitignore +++ b/04-flutter-desktop/macos_theme_app/.gitignore @@ -5,9 +5,11 @@ *.swp .DS_Store .atom/ +.build/ .buildlog/ .history .svn/ +.swiftpm/ migrate_working_dir/ # IntelliJ related diff --git a/04-flutter-desktop/macos_theme_app/.metadata b/04-flutter-desktop/macos_theme_app/.metadata index 406b82e..4806319 100644 --- a/04-flutter-desktop/macos_theme_app/.metadata +++ b/04-flutter-desktop/macos_theme_app/.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: 18a827f3933c19f51862dde3fa472197683249d6 - channel: stable + revision: "ac4e799d237041cf905519190471f657b657155a" + channel: "stable" project_type: app @@ -13,11 +13,11 @@ project_type: app migration: platforms: - platform: root - create_revision: 18a827f3933c19f51862dde3fa472197683249d6 - base_revision: 18a827f3933c19f51862dde3fa472197683249d6 - - platform: web - create_revision: 18a827f3933c19f51862dde3fa472197683249d6 - base_revision: 18a827f3933c19f51862dde3fa472197683249d6 + create_revision: ac4e799d237041cf905519190471f657b657155a + base_revision: ac4e799d237041cf905519190471f657b657155a + - platform: macos + create_revision: ac4e799d237041cf905519190471f657b657155a + base_revision: ac4e799d237041cf905519190471f657b657155a # User provided section diff --git a/04-flutter-desktop/macos_theme_app/lib/main.dart b/04-flutter-desktop/macos_theme_app/lib/main.dart index ba54afc..f951e91 100644 --- a/04-flutter-desktop/macos_theme_app/lib/main.dart +++ b/04-flutter-desktop/macos_theme_app/lib/main.dart @@ -42,18 +42,18 @@ class FirstScreen extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ PushButton( - buttonSize: ButtonSize.large, + controlSize: ControlSize.large, onPressed: () {}, child: const Text("Large button"), ), PushButton( - buttonSize: ButtonSize.small, + controlSize: ControlSize.small, onPressed: () {}, child: const Text("Small button"), ), PushButton( - buttonSize: ButtonSize.large, - isSecondary: true, + controlSize: ControlSize.large, + secondary: true, onPressed: () {}, child: const Text("Secondary button"), ), diff --git a/04-flutter-desktop/macos_theme_app/macos/Flutter/Flutter-Debug.xcconfig b/04-flutter-desktop/macos_theme_app/macos/Flutter/Flutter-Debug.xcconfig index c2efd0b..4b81f9b 100644 --- a/04-flutter-desktop/macos_theme_app/macos/Flutter/Flutter-Debug.xcconfig +++ b/04-flutter-desktop/macos_theme_app/macos/Flutter/Flutter-Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/04-flutter-desktop/macos_theme_app/macos/Flutter/Flutter-Release.xcconfig b/04-flutter-desktop/macos_theme_app/macos/Flutter/Flutter-Release.xcconfig index c2efd0b..5caa9d1 100644 --- a/04-flutter-desktop/macos_theme_app/macos/Flutter/Flutter-Release.xcconfig +++ b/04-flutter-desktop/macos_theme_app/macos/Flutter/Flutter-Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/04-flutter-desktop/macos_theme_app/macos/Flutter/GeneratedPluginRegistrant.swift b/04-flutter-desktop/macos_theme_app/macos/Flutter/GeneratedPluginRegistrant.swift index 722b1dd..ed687ee 100644 --- a/04-flutter-desktop/macos_theme_app/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/04-flutter-desktop/macos_theme_app/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,8 +5,12 @@ import FlutterMacOS import Foundation +import appkit_ui_element_colors import macos_ui +import macos_window_utils func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + AppkitUiElementColorsPlugin.register(with: registry.registrar(forPlugin: "AppkitUiElementColorsPlugin")) MacOSUiPlugin.register(with: registry.registrar(forPlugin: "MacOSUiPlugin")) + MacOSWindowUtilsPlugin.register(with: registry.registrar(forPlugin: "MacOSWindowUtilsPlugin")) } diff --git a/04-flutter-desktop/macos_theme_app/macos/Podfile b/04-flutter-desktop/macos_theme_app/macos/Podfile new file mode 100644 index 0000000..ff5ddb3 --- /dev/null +++ b/04-flutter-desktop/macos_theme_app/macos/Podfile @@ -0,0 +1,42 @@ +platform :osx, '10.15' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/04-flutter-desktop/macos_theme_app/macos/Podfile.lock b/04-flutter-desktop/macos_theme_app/macos/Podfile.lock new file mode 100644 index 0000000..041e9c2 --- /dev/null +++ b/04-flutter-desktop/macos_theme_app/macos/Podfile.lock @@ -0,0 +1,34 @@ +PODS: + - appkit_ui_element_colors (1.0.0): + - FlutterMacOS + - FlutterMacOS (1.0.0) + - macos_ui (0.1.0): + - FlutterMacOS + - macos_window_utils (1.0.0): + - FlutterMacOS + +DEPENDENCIES: + - appkit_ui_element_colors (from `Flutter/ephemeral/.symlinks/plugins/appkit_ui_element_colors/macos`) + - FlutterMacOS (from `Flutter/ephemeral`) + - macos_ui (from `Flutter/ephemeral/.symlinks/plugins/macos_ui/macos`) + - macos_window_utils (from `Flutter/ephemeral/.symlinks/plugins/macos_window_utils/macos`) + +EXTERNAL SOURCES: + appkit_ui_element_colors: + :path: Flutter/ephemeral/.symlinks/plugins/appkit_ui_element_colors/macos + FlutterMacOS: + :path: Flutter/ephemeral + macos_ui: + :path: Flutter/ephemeral/.symlinks/plugins/macos_ui/macos + macos_window_utils: + :path: Flutter/ephemeral/.symlinks/plugins/macos_window_utils/macos + +SPEC CHECKSUMS: + appkit_ui_element_colors: bb247a2d02b8313cc47e1b83be48d996034c4001 + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 + macos_ui: 50a2048b7ef82bde42570e2775f50907537a0eeb + macos_window_utils: 721df4da91cb4bde7b2b7b6ae93cdead4851118f + +PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009 + +COCOAPODS: 1.16.2 diff --git a/04-flutter-desktop/macos_theme_app/macos/Runner.xcodeproj/project.pbxproj b/04-flutter-desktop/macos_theme_app/macos/Runner.xcodeproj/project.pbxproj index a9203d3..8fedaf6 100644 --- a/04-flutter-desktop/macos_theme_app/macos/Runner.xcodeproj/project.pbxproj +++ b/04-flutter-desktop/macos_theme_app/macos/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 54; objects = { /* Begin PBXAggregateTarget section */ @@ -21,14 +21,24 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 1F0F8E4956B6DCC3B13E2347 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CB8138BDAF222765A8440A10 /* Pods_RunnerTests.framework */; }; + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + DE658D71687103FF6A686C5F /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9BA4FBDCA7E0A637B2841296 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 33CC10E52044A3C60003C045 /* Project object */; @@ -52,9 +62,12 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0FBC06DD7101D163931ECF65 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* macos_theme_app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "macos_theme_app.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10ED2044A3C60003C045 /* macos_theme_app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = macos_theme_app.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; @@ -67,20 +80,44 @@ 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 966432429FC0C6E9DD2D9D79 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + 9BA4FBDCA7E0A637B2841296 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 9ECE0CCA75AD135EE5B156C9 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + A2E98749D434A75CDAD03508 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + CB8138BDAF222765A8440A10 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D5CD74ACA7A040AE89E616E8 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + EC1A8AEFE9F58228A436EF72 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1F0F8E4956B6DCC3B13E2347 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 33CC10EA2044A3C60003C045 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + DE658D71687103FF6A686C5F /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; 33BA886A226E78AF003329D5 /* Configs */ = { isa = PBXGroup; children = ( @@ -97,8 +134,10 @@ children = ( 33FAB671232836740065AC1E /* Runner */, 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, + E1F13D58D43903AD5D4BD020 /* Pods */, ); sourceTree = ""; }; @@ -106,6 +145,7 @@ isa = PBXGroup; children = ( 33CC10ED2044A3C60003C045 /* macos_theme_app.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, ); name = Products; sourceTree = ""; @@ -148,22 +188,59 @@ D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( + 9BA4FBDCA7E0A637B2841296 /* Pods_Runner.framework */, + CB8138BDAF222765A8440A10 /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; }; + E1F13D58D43903AD5D4BD020 /* Pods */ = { + isa = PBXGroup; + children = ( + 966432429FC0C6E9DD2D9D79 /* Pods-Runner.debug.xcconfig */, + 9ECE0CCA75AD135EE5B156C9 /* Pods-Runner.release.xcconfig */, + 0FBC06DD7101D163931ECF65 /* Pods-Runner.profile.xcconfig */, + D5CD74ACA7A040AE89E616E8 /* Pods-RunnerTests.debug.xcconfig */, + A2E98749D434A75CDAD03508 /* Pods-RunnerTests.release.xcconfig */, + EC1A8AEFE9F58228A436EF72 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 23DEC566EDDFA7D6D51902FE /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 33CC10EC2044A3C60003C045 /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + 78ADFA5C9A096B6895252D7F /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, + 24C3F5C62820B55F286D3C58 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -181,10 +258,15 @@ 33CC10E52044A3C60003C045 /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; 33CC10EC2044A3C60003C045 = { CreatedOnToolsVersion = 9.2; LastSwiftMigration = 1100; @@ -215,12 +297,20 @@ projectRoot = ""; targets = ( 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, 33CC111A2044C6BA0003C045 /* Flutter Assemble */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 33CC10EB2044A3C60003C045 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -233,8 +323,48 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 23DEC566EDDFA7D6D51902FE /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 24C3F5C62820B55F286D3C58 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; 3399D490228B24CF009A79C7 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -270,9 +400,39 @@ shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; + 78ADFA5C9A096B6895252D7F /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 33CC10E92044A3C60003C045 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -286,6 +446,11 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; @@ -306,11 +471,57 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D5CD74ACA7A040AE89E616E8 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.dicoding.macosThemeApp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/macos_theme_app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/macos_theme_app"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A2E98749D434A75CDAD03508 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.dicoding.macosThemeApp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/macos_theme_app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/macos_theme_app"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EC1A8AEFE9F58228A436EF72 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.dicoding.macosThemeApp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/macos_theme_app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/macos_theme_app"; + }; + name = Profile; + }; 338D0CE9231458BD00FA5F75 /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -334,9 +545,11 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -344,7 +557,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -384,6 +597,7 @@ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -407,9 +621,11 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -423,7 +639,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -437,6 +653,7 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -460,9 +677,11 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -470,7 +689,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -536,6 +755,16 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/04-flutter-desktop/macos_theme_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/04-flutter-desktop/macos_theme_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 085e91b..0449c37 100644 --- a/04-flutter-desktop/macos_theme_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/04-flutter-desktop/macos_theme_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ + + + + diff --git a/04-flutter-desktop/macos_theme_app/macos/Runner.xcworkspace/contents.xcworkspacedata b/04-flutter-desktop/macos_theme_app/macos/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..21a3cc1 100644 --- a/04-flutter-desktop/macos_theme_app/macos/Runner.xcworkspace/contents.xcworkspacedata +++ b/04-flutter-desktop/macos_theme_app/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/04-flutter-desktop/macos_theme_app/macos/Runner/AppDelegate.swift b/04-flutter-desktop/macos_theme_app/macos/Runner/AppDelegate.swift index d53ef64..b3c1761 100644 --- a/04-flutter-desktop/macos_theme_app/macos/Runner/AppDelegate.swift +++ b/04-flutter-desktop/macos_theme_app/macos/Runner/AppDelegate.swift @@ -1,9 +1,13 @@ import Cocoa import FlutterMacOS -@NSApplicationMain +@main class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } } diff --git a/04-flutter-desktop/macos_theme_app/macos/Runner/Configs/AppInfo.xcconfig b/04-flutter-desktop/macos_theme_app/macos/Runner/Configs/AppInfo.xcconfig index da7ab6f..49d4b97 100644 --- a/04-flutter-desktop/macos_theme_app/macos/Runner/Configs/AppInfo.xcconfig +++ b/04-flutter-desktop/macos_theme_app/macos/Runner/Configs/AppInfo.xcconfig @@ -8,7 +8,7 @@ PRODUCT_NAME = macos_theme_app // The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = com.example.macosThemeApp +PRODUCT_BUNDLE_IDENTIFIER = com.dicoding.macosThemeApp // The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2022 com.example. All rights reserved. +PRODUCT_COPYRIGHT = Copyright © 2025 com.dicoding. All rights reserved. diff --git a/04-flutter-desktop/macos_theme_app/macos/Runner/MainFlutterWindow.swift b/04-flutter-desktop/macos_theme_app/macos/Runner/MainFlutterWindow.swift index 2722837..3cc05eb 100644 --- a/04-flutter-desktop/macos_theme_app/macos/Runner/MainFlutterWindow.swift +++ b/04-flutter-desktop/macos_theme_app/macos/Runner/MainFlutterWindow.swift @@ -3,7 +3,7 @@ import FlutterMacOS class MainFlutterWindow: NSWindow { override func awakeFromNib() { - let flutterViewController = FlutterViewController.init() + let flutterViewController = FlutterViewController() let windowFrame = self.frame self.contentViewController = flutterViewController self.setFrame(windowFrame, display: true) diff --git a/04-flutter-desktop/macos_theme_app/macos/RunnerTests/RunnerTests.swift b/04-flutter-desktop/macos_theme_app/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..61f3bd1 --- /dev/null +++ b/04-flutter-desktop/macos_theme_app/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/04-flutter-desktop/macos_theme_app/pubspec.lock b/04-flutter-desktop/macos_theme_app/pubspec.lock index 03d8e74..bab7e7d 100644 --- a/04-flutter-desktop/macos_theme_app/pubspec.lock +++ b/04-flutter-desktop/macos_theme_app/pubspec.lock @@ -1,55 +1,78 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + appkit_ui_element_colors: + dependency: transitive + description: + name: appkit_ui_element_colors + sha256: b88a7c35d440fa3ac75222d0e2b7e3259200e531e33b5d2468e358119f3481dc + url: "https://pub.dev" + source: hosted + version: "1.0.1" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.13.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "5bbf32bc9e518d41ec49718e2931cd4527292c9b0c6d2dffcf7fe6b9a8a8cf72" + url: "https://pub.dev" source: hosted version: "2.1.0" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.4.0" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.19.1" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" source: hosted version: "1.0.5" + equatable: + dependency: transitive + description: + name: equatable + sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7" + url: "https://pub.dev" + source: hosted + version: "2.0.7" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.3" flutter: dependency: "direct main" description: flutter @@ -59,7 +82,8 @@ packages: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + url: "https://pub.dev" source: hosted version: "2.0.1" flutter_test: @@ -67,102 +91,171 @@ packages: description: flutter source: sdk version: "0.0.0" + gradient_borders: + dependency: transitive + description: + name: gradient_borders + sha256: "492bc88ab8d88a4117a7f00e525a669b65f19973bea7ee677f9d9de7603bf037" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" + url: "https://pub.dev" + source: hosted + version: "11.0.2" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" + url: "https://pub.dev" + source: hosted + version: "3.0.10" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" + url: "https://pub.dev" + source: hosted + version: "3.0.2" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: "5cfd6509652ff5e7fe149b6df4859e687fca9048437857cb2e65c8d780f396e3" + url: "https://pub.dev" source: hosted version: "2.0.0" macos_ui: dependency: "direct main" description: name: macos_ui - url: "https://pub.dartlang.org" + sha256: "09fb51d65b6a2d328ba5aa429ba0f7aabad5bc770193ea6e49da9f29bf95d835" + url: "https://pub.dev" source: hosted - version: "1.7.5" + version: "2.2.2" + macos_window_utils: + dependency: transitive + description: + name: macos_window_utils + sha256: d4df3501fd32ac0d2d7590cb6a8e4758337d061c8fa0db816fdd636be63a8438 + url: "https://pub.dev" + source: hosted + version: "1.9.0" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.17" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" source: hosted - version: "0.1.5" + version: "0.11.1" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.16.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.9.1" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: e3320978e3715725e62f04358fd249c1efe5999297b2c6acd626a817593281b0 + url: "https://pub.dev" source: hosted version: "1.9.0" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.4" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "862015c5db1f3f3c4ea3b94dc2490363a84262994b88902315ed74be1155612f" + url: "https://pub.dev" source: hosted version: "1.1.1" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" + url: "https://pub.dev" source: hosted - version: "0.4.12" + version: "0.7.6" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + url: "https://pub.dev" + source: hosted + version: "2.2.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "15.0.2" sdks: - dart: ">=2.18.2 <3.0.0" - flutter: ">=1.20.0" + dart: ">=3.9.2 <4.0.0" + flutter: ">=3.35.0" diff --git a/04-flutter-desktop/macos_theme_app/pubspec.yaml b/04-flutter-desktop/macos_theme_app/pubspec.yaml index 63351de..48cfb3a 100644 --- a/04-flutter-desktop/macos_theme_app/pubspec.yaml +++ b/04-flutter-desktop/macos_theme_app/pubspec.yaml @@ -3,7 +3,7 @@ description: A new Flutter project. # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev +publish_to: "none" # Remove this line if you wish to publish to pub.dev # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 @@ -20,7 +20,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: '>=2.18.2 <3.0.0' + sdk: ^3.9.2 # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -32,11 +32,10 @@ dependencies: flutter: sdk: flutter - # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 - macos_ui: ^1.7.5 + macos_ui: ^2.2.2 dev_dependencies: flutter_test: @@ -54,7 +53,6 @@ dev_dependencies: # The following section is specific to Flutter packages. flutter: - # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. diff --git a/04-flutter-desktop/yaru_theme_app/.metadata b/04-flutter-desktop/yaru_theme_app/.metadata index 406b82e..b21e873 100644 --- a/04-flutter-desktop/yaru_theme_app/.metadata +++ b/04-flutter-desktop/yaru_theme_app/.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: 18a827f3933c19f51862dde3fa472197683249d6 - channel: stable + revision: "ac4e799d237041cf905519190471f657b657155a" + channel: "stable" project_type: app @@ -13,11 +13,11 @@ project_type: app migration: platforms: - platform: root - create_revision: 18a827f3933c19f51862dde3fa472197683249d6 - base_revision: 18a827f3933c19f51862dde3fa472197683249d6 - - platform: web - create_revision: 18a827f3933c19f51862dde3fa472197683249d6 - base_revision: 18a827f3933c19f51862dde3fa472197683249d6 + create_revision: ac4e799d237041cf905519190471f657b657155a + base_revision: ac4e799d237041cf905519190471f657b657155a + - platform: linux + create_revision: ac4e799d237041cf905519190471f657b657155a + base_revision: ac4e799d237041cf905519190471f657b657155a # User provided section diff --git a/04-flutter-desktop/yaru_theme_app/lib/main.dart b/04-flutter-desktop/yaru_theme_app/lib/main.dart index 64910be..a0d10b2 100644 --- a/04-flutter-desktop/yaru_theme_app/lib/main.dart +++ b/04-flutter-desktop/yaru_theme_app/lib/main.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; import 'package:yaru/yaru.dart'; -import 'package:yaru_icons/yaru_icons.dart'; -import 'package:yaru_widgets/yaru_widgets.dart'; void main() { runApp(const MyApp()); @@ -30,28 +28,28 @@ class FirstScreen extends StatelessWidget { @override Widget build(BuildContext context) { - return YaruPage( - children: [ - const Text( - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - OutlinedButton( - onPressed: () {}, - child: const Text("Outlined Button"), - ), - TextButton( - onPressed: () {}, - child: const Text("Text Button"), - ), - ElevatedButton( - onPressed: () {}, - child: const Text("Elevated Button"), - ), - ], - ), - ], + return YaruDetailPage( + body: Column( + children: [ + const Text( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + OutlinedButton( + onPressed: () {}, + child: const Text("Outlined Button"), + ), + TextButton(onPressed: () {}, child: const Text("Text Button")), + ElevatedButton( + onPressed: () {}, + child: const Text("Elevated Button"), + ), + ], + ), + ], + ), ); } } @@ -64,10 +62,10 @@ class SecondScreen extends StatelessWidget { return ListView.builder( itemCount: 20, itemBuilder: (context, index) { - return YaruRow( - actionWidget: Icon(YaruIcons.information), - trailingWidget: Text("Item ${index + 1}"), - description: "Subtitle ${index + 1}", + return YaruTile( + trailing: const Icon(YaruIcons.information), + title: Text("Item ${index + 1}"), + subtitle: Text("Subtitle ${index + 1}"), enabled: true, ); }, @@ -81,22 +79,29 @@ class HomeScreen extends StatelessWidget { @override Widget build(BuildContext context) { return YaruMasterDetailPage( - pageItems: [ - YaruPageItem( - titleBuilder: (context) => Text("First Screen"), - builder: (context) => FirstScreen(), - iconData: YaruIcons.document, - ), - YaruPageItem( - titleBuilder: (context) => Text("Second Screen"), - builder: (context) => SecondScreen(), - iconData: YaruIcons.format_ordered_list, - ), - ], - leftPaneWidth: 280, - appBar: AppBar( - title: Text("Yaru Theme App"), - ), + length: 2, + initialIndex: 0, + tileBuilder: (context, index, selected, availableWidth) { + if (index == 0) { + return const YaruMasterTile( + leading: Icon(YaruIcons.document), + title: Text("First Screen"), + ); + } else { + return const YaruMasterTile( + leading: Icon(YaruIcons.ordered_list), + title: Text("Second Screen"), + ); + } + }, + pageBuilder: (context, index) { + if (index == 0) { + return const FirstScreen(); + } else { + return const SecondScreen(); + } + }, + appBar: AppBar(title: const Text("Yaru Theme App")), ); } } diff --git a/04-flutter-desktop/yaru_theme_app/linux/CMakeLists.txt b/04-flutter-desktop/yaru_theme_app/linux/CMakeLists.txt index f3b600f..c6ded72 100644 --- a/04-flutter-desktop/yaru_theme_app/linux/CMakeLists.txt +++ b/04-flutter-desktop/yaru_theme_app/linux/CMakeLists.txt @@ -1,5 +1,5 @@ # Project-level configuration. -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.13) project(runner LANGUAGES CXX) # The name of the executable created for the application. Change this to change @@ -7,7 +7,7 @@ project(runner LANGUAGES CXX) set(BINARY_NAME "yaru_theme_app") # The unique GTK application identifier for this application. See: # https://wiki.gnome.org/HowDoI/ChooseApplicationID -set(APPLICATION_ID "com.example.yaru_theme_app") +set(APPLICATION_ID "com.dicoding.yaru_theme_app") # Explicitly opt in to modern CMake behaviors to avoid warnings with recent # versions of CMake. @@ -54,25 +54,8 @@ add_subdirectory(${FLUTTER_MANAGED_DIR}) find_package(PkgConfig REQUIRED) pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) -add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") - -# Define the application target. To change its name, change BINARY_NAME above, -# 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} - "main.cc" - "my_application.cc" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. -apply_standard_settings(${BINARY_NAME}) - -# Add dependency libraries. Add any application-specific dependencies here. -target_link_libraries(${BINARY_NAME} PRIVATE flutter) -target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") # Run the Flutter tool portions of the build. This must not be removed. add_dependencies(${BINARY_NAME} flutter_assemble) @@ -86,6 +69,7 @@ set_target_properties(${BINARY_NAME} RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" ) + # Generated plugin build rules, which manage building the plugins and adding # them to the application. include(flutter/generated_plugins.cmake) @@ -122,6 +106,12 @@ foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) COMPONENT Runtime) endforeach(bundled_library) +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +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/04-flutter-desktop/yaru_theme_app/linux/flutter/generated_plugin_registrant.cc b/04-flutter-desktop/yaru_theme_app/linux/flutter/generated_plugin_registrant.cc index 6cdf9ac..aba3d1a 100644 --- a/04-flutter-desktop/yaru_theme_app/linux/flutter/generated_plugin_registrant.cc +++ b/04-flutter-desktop/yaru_theme_app/linux/flutter/generated_plugin_registrant.cc @@ -6,10 +6,22 @@ #include "generated_plugin_registrant.h" -#include +#include +#include +#include +#include void fl_register_plugins(FlPluginRegistry* registry) { - g_autoptr(FlPluginRegistrar) yaru_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "YaruPlugin"); - yaru_plugin_register_with_registrar(yaru_registrar); + g_autoptr(FlPluginRegistrar) gtk_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "GtkPlugin"); + gtk_plugin_register_with_registrar(gtk_registrar); + g_autoptr(FlPluginRegistrar) screen_retriever_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverLinuxPlugin"); + screen_retriever_linux_plugin_register_with_registrar(screen_retriever_linux_registrar); + g_autoptr(FlPluginRegistrar) window_manager_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "WindowManagerPlugin"); + window_manager_plugin_register_with_registrar(window_manager_registrar); + g_autoptr(FlPluginRegistrar) yaru_window_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "YaruWindowLinuxPlugin"); + yaru_window_linux_plugin_register_with_registrar(yaru_window_linux_registrar); } diff --git a/04-flutter-desktop/yaru_theme_app/linux/flutter/generated_plugins.cmake b/04-flutter-desktop/yaru_theme_app/linux/flutter/generated_plugins.cmake index 4710751..b4d3d98 100644 --- a/04-flutter-desktop/yaru_theme_app/linux/flutter/generated_plugins.cmake +++ b/04-flutter-desktop/yaru_theme_app/linux/flutter/generated_plugins.cmake @@ -3,7 +3,10 @@ # list(APPEND FLUTTER_PLUGIN_LIST - yaru + gtk + screen_retriever_linux + window_manager + yaru_window_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/04-flutter-desktop/yaru_theme_app/linux/runner/CMakeLists.txt b/04-flutter-desktop/yaru_theme_app/linux/runner/CMakeLists.txt new file mode 100644 index 0000000..e97dabc --- /dev/null +++ b/04-flutter-desktop/yaru_theme_app/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +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} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# 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 application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/04-flutter-desktop/yaru_theme_app/linux/main.cc b/04-flutter-desktop/yaru_theme_app/linux/runner/main.cc similarity index 100% rename from 04-flutter-desktop/yaru_theme_app/linux/main.cc rename to 04-flutter-desktop/yaru_theme_app/linux/runner/main.cc diff --git a/04-flutter-desktop/yaru_theme_app/linux/my_application.cc b/04-flutter-desktop/yaru_theme_app/linux/runner/my_application.cc similarity index 68% rename from 04-flutter-desktop/yaru_theme_app/linux/my_application.cc rename to 04-flutter-desktop/yaru_theme_app/linux/runner/my_application.cc index 9a6f2db..191413a 100644 --- a/04-flutter-desktop/yaru_theme_app/linux/my_application.cc +++ b/04-flutter-desktop/yaru_theme_app/linux/runner/my_application.cc @@ -14,6 +14,12 @@ struct _MyApplication { G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) +// Called when first Flutter frame received. +static void first_frame_cb(MyApplication* self, FlView *view) +{ + gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); +} + // Implements GApplication::activate. static void my_application_activate(GApplication* application) { MyApplication* self = MY_APPLICATION(application); @@ -48,15 +54,23 @@ static void my_application_activate(GApplication* application) { } gtk_window_set_default_size(window, 1280, 720); - gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlDartProject) project = fl_dart_project_new(); fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); FlView* view = fl_view_new(project); + GdkRGBA background_color; + // Background defaults to black, override it here if necessary, e.g. #00000000 for transparent. + gdk_rgba_parse(&background_color, "#000000"); + fl_view_set_background_color(view, &background_color); gtk_widget_show(GTK_WIDGET(view)); gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + // Show the window when Flutter renders. + // Requires the view to be realized so we can start rendering. + g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), self); + gtk_widget_realize(GTK_WIDGET(view)); + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); gtk_widget_grab_focus(GTK_WIDGET(view)); @@ -81,6 +95,24 @@ static gboolean my_application_local_command_line(GApplication* application, gch return TRUE; } +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + // Implements GObject::dispose. static void my_application_dispose(GObject* object) { MyApplication* self = MY_APPLICATION(object); @@ -91,12 +123,20 @@ static void my_application_dispose(GObject* object) { static void my_application_class_init(MyApplicationClass* klass) { G_APPLICATION_CLASS(klass)->activate = my_application_activate; G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; G_OBJECT_CLASS(klass)->dispose = my_application_dispose; } static void my_application_init(MyApplication* self) {} MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + return MY_APPLICATION(g_object_new(my_application_get_type(), "application-id", APPLICATION_ID, "flags", G_APPLICATION_NON_UNIQUE, diff --git a/04-flutter-desktop/yaru_theme_app/linux/my_application.h b/04-flutter-desktop/yaru_theme_app/linux/runner/my_application.h similarity index 100% rename from 04-flutter-desktop/yaru_theme_app/linux/my_application.h rename to 04-flutter-desktop/yaru_theme_app/linux/runner/my_application.h diff --git a/04-flutter-desktop/yaru_theme_app/pubspec.lock b/04-flutter-desktop/yaru_theme_app/pubspec.lock index f2504b2..2f6e929 100644 --- a/04-flutter-desktop/yaru_theme_app/pubspec.lock +++ b/04-flutter-desktop/yaru_theme_app/pubspec.lock @@ -1,55 +1,126 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + animated_vector: + dependency: transitive + description: + name: animated_vector + sha256: f1beb10e6fcfd8bd15abb788e20345def786d1c7391d7c1426bb2a1f2adf2132 + url: "https://pub.dev" + source: hosted + version: "0.2.2" + animated_vector_annotations: + dependency: transitive + description: + name: animated_vector_annotations + sha256: "07c1ea603a2096f7eb6f1c2b8f16c3c330c680843ea78b7782a3217c3c53f979" + url: "https://pub.dev" + source: hosted + version: "0.2.2" + archive: + dependency: transitive + description: + name: archive + sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" + url: "https://pub.dev" + source: hosted + version: "4.0.7" + args: + dependency: transitive + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + assorted_layout_widgets: + dependency: transitive + description: + name: assorted_layout_widgets + sha256: "86c6942f569f7f70bfb03b9cb0ada9bf5aee72264aaefdb0e2be0fbee70cfb06" + url: "https://pub.dev" + source: hosted + version: "11.0.0" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.13.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "5bbf32bc9e518d41ec49718e2931cd4527292c9b0c6d2dffcf7fe6b9a8a8cf72" + url: "https://pub.dev" source: hosted version: "2.1.0" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.4.0" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.19.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf + url: "https://pub.dev" + source: hosted + version: "3.0.7" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" source: hosted version: "1.0.5" + dbus: + dependency: transitive + description: + name: dbus + sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" + url: "https://pub.dev" + source: hosted + version: "0.7.11" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.3" + ffi: + dependency: transitive + description: + name: ffi + sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" + url: "https://pub.dev" + source: hosted + version: "2.1.4" flutter: dependency: "direct main" description: flutter @@ -59,7 +130,8 @@ packages: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + url: "https://pub.dev" source: hosted version: "2.0.1" flutter_test: @@ -67,137 +139,352 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + gsettings: + dependency: transitive + description: + name: gsettings + sha256: "1b0ce661f5436d2db1e51f3c4295a49849f03d304003a7ba177d01e3a858249c" + url: "https://pub.dev" + source: hosted + version: "0.2.8" + gtk: + dependency: transitive + description: + name: gtk + sha256: e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c + url: "https://pub.dev" + source: hosted + version: "2.1.0" + image: + dependency: transitive + description: + name: image + sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928" + url: "https://pub.dev" + source: hosted + version: "4.5.4" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" + url: "https://pub.dev" + source: hosted + version: "11.0.2" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" + url: "https://pub.dev" + source: hosted + version: "3.0.10" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" + url: "https://pub.dev" + source: hosted + version: "3.0.2" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + sha256: "5cfd6509652ff5e7fe149b6df4859e687fca9048437857cb2e65c8d780f396e3" + url: "https://pub.dev" source: hosted version: "2.0.0" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.17" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" source: hosted - version: "0.1.5" + version: "0.11.1" + matrix4_transform: + dependency: transitive + description: + name: matrix4_transform + sha256: "1346e53517e3081d3e8362377be97e285e2bd348855c177eae2a18aa965cafa0" + url: "https://pub.dev" + source: hosted + version: "4.0.1" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.16.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.9.1" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1" + url: "https://pub.dev" + source: hosted + version: "7.0.1" platform: dependency: transitive description: name: platform - url: "https://pub.dartlang.org" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" + source: hosted + version: "3.1.6" + platform_linux: + dependency: transitive + description: + name: platform_linux + sha256: "907b7c6da6ee6eea61cd1266b7bd72e2d5bbf7e85160221e8ac5583a44e7a1c7" + url: "https://pub.dev" + source: hosted + version: "0.1.2+1" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + posix: + dependency: transitive + description: + name: posix + sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61" + url: "https://pub.dev" + source: hosted + version: "6.0.3" + screen_retriever: + dependency: transitive + description: + name: screen_retriever + sha256: "570dbc8e4f70bac451e0efc9c9bb19fa2d6799a11e6ef04f946d7886d2e23d0c" + url: "https://pub.dev" + source: hosted + version: "0.2.0" + screen_retriever_linux: + dependency: transitive + description: + name: screen_retriever_linux + sha256: f7f8120c92ef0784e58491ab664d01efda79a922b025ff286e29aa123ea3dd18 + url: "https://pub.dev" + source: hosted + version: "0.2.0" + screen_retriever_macos: + dependency: transitive + description: + name: screen_retriever_macos + sha256: "71f956e65c97315dd661d71f828708bd97b6d358e776f1a30d5aa7d22d78a149" + url: "https://pub.dev" + source: hosted + version: "0.2.0" + screen_retriever_platform_interface: + dependency: transitive + description: + name: screen_retriever_platform_interface + sha256: ee197f4581ff0d5608587819af40490748e1e39e648d7680ecf95c05197240c0 + url: "https://pub.dev" + source: hosted + version: "0.2.0" + screen_retriever_windows: + dependency: transitive + description: + name: screen_retriever_windows + sha256: "449ee257f03ca98a57288ee526a301a430a344a161f9202b4fcc38576716fe13" + url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "0.2.0" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: e3320978e3715725e62f04358fd249c1efe5999297b2c6acd626a817593281b0 + url: "https://pub.dev" source: hosted version: "1.9.0" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.4" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "862015c5db1f3f3c4ea3b94dc2490363a84262994b88902315ed74be1155612f" + url: "https://pub.dev" source: hosted version: "1.1.1" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" + url: "https://pub.dev" + source: hosted + version: "0.7.6" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" source: hosted - version: "0.4.12" + version: "1.4.0" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + url: "https://pub.dev" + source: hosted + version: "2.2.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" + url: "https://pub.dev" + source: hosted + version: "15.0.2" + window_manager: + dependency: transitive + description: + name: window_manager + sha256: "7eb6d6c4164ec08e1bf978d6e733f3cebe792e2a23fb07cbca25c2872bfdbdcd" + url: "https://pub.dev" + source: hosted + version: "0.5.1" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "1.1.0" + xml: + dependency: transitive + description: + name: xml + sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" + url: "https://pub.dev" + source: hosted + version: "6.6.1" yaru: dependency: "direct main" description: name: yaru - url: "https://pub.dartlang.org" + sha256: "67ac8c3dc52a5d69c049056d5fa40b909973e10b36df3cffeb666de867532d79" + url: "https://pub.dev" source: hosted - version: "0.4.1" - yaru_color_generator: + version: "8.3.0" + yaru_window: dependency: transitive description: - name: yaru_color_generator - url: "https://pub.dartlang.org" + name: yaru_window + sha256: "58539a9abe9901891dadce142c7a5d303920b780dd0f7bd21f076a80adeeb744" + url: "https://pub.dev" source: hosted - version: "0.1.0" - yaru_colors: - dependency: "direct main" + version: "0.2.2" + yaru_window_linux: + dependency: transitive description: - name: yaru_colors - url: "https://pub.dartlang.org" + name: yaru_window_linux + sha256: "885ad0ba5832d350c42862ce02da478599ef550280eb7f6b15285481fcff6f53" + url: "https://pub.dev" source: hosted - version: "0.1.0" - yaru_icons: - dependency: "direct main" + version: "0.2.2" + yaru_window_manager: + dependency: transitive description: - name: yaru_icons - url: "https://pub.dartlang.org" + name: yaru_window_manager + sha256: "6288fd6ccd8bb9d5be56073c6f277e2da08dd38e346507bf88bc9332b08dd180" + url: "https://pub.dev" source: hosted - version: "0.2.5" - yaru_widgets: - dependency: "direct main" + version: "0.1.3" + yaru_window_platform_interface: + dependency: transitive + description: + name: yaru_window_platform_interface + sha256: d514387cc96750112ecf1933b6f12a1912beca199178d00052c0e87a94e232fa + url: "https://pub.dev" + source: hosted + version: "0.1.3" + yaru_window_web: + dependency: transitive description: - name: yaru_widgets - url: "https://pub.dartlang.org" + name: yaru_window_web + sha256: cf4d79e0760fbdcb78d4bbca3b5563f99518629224b9e5611f0ebd592befe1d9 + url: "https://pub.dev" source: hosted - version: "1.1.5" + version: "0.0.4" sdks: - dart: ">=2.18.2 <3.0.0" - flutter: ">=3.3.0" + dart: ">=3.9.2 <4.0.0" + flutter: ">=3.32.0" diff --git a/04-flutter-desktop/yaru_theme_app/pubspec.yaml b/04-flutter-desktop/yaru_theme_app/pubspec.yaml index 064c96c..d3b7db4 100644 --- a/04-flutter-desktop/yaru_theme_app/pubspec.yaml +++ b/04-flutter-desktop/yaru_theme_app/pubspec.yaml @@ -3,7 +3,7 @@ description: A new Flutter project. # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev +publish_to: "none" # Remove this line if you wish to publish to pub.dev # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 @@ -20,7 +20,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: '>=2.18.2 <3.0.0' + sdk: ^3.9.2 # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -32,15 +32,11 @@ dependencies: flutter: sdk: flutter - # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 # /// todo-01-01: add dependency - yaru: ^0.4.1 - yaru_widgets: ^1.1.5 - yaru_icons: ^0.2.5 - yaru_colors: ^0.1.0 + yaru: ^8.3.0 dev_dependencies: flutter_test: @@ -58,7 +54,6 @@ dev_dependencies: # The following section is specific to Flutter packages. flutter: - # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class.