diff --git a/.gitignore b/.gitignore index fcfa202c..144640c7 100644 --- a/.gitignore +++ b/.gitignore @@ -80,3 +80,5 @@ metrics coverage_report coverage +example/macos/Flutter/GeneratedPluginRegistrant.swift +example/devtools_options.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index fd70a111..8d87d8aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,39 @@ +## [2.1.0] +* Updated dependencies +* Support macOS 15 + +## [2.0.9] +### 🛠️ Updated 🛠️ +* Add `expandDisclosureItems` flag to `SidebarItem` to optionally (default not changed) expand disclosure items initially + +## [2.0.8] +### 🛠️ Updated 🛠️ +* Fixed `SidebarItem` text overflowing. + +## [2.0.7] +### 🛠️ Updated 🛠️ +* Made most widgets aware of the user’s accent color and window state by adding respective fields to `MacosThemeData`. +* `MacosCheckbox` has received a facelift to mimic the look and feel of native macOS checkboxes better. + +## [2.0.6] +### 🛠️ Updated 🛠️ +* Implemented value equality for `MacosThemeData`. + +## [2.0.5] +### 🛠️ Fixed 🛠️ +* Fixed `MacosRadioButton` check null value issue. + +## [2.0.4] +### 🔄 Updated 🔄 +* Added `initialTime` parameter to `MacosTimePicker`, allowing to set an initial time for the picker.This provides more customization options for selecting time. + +## [2.0.3] +### 🛠️ Fixed 🛠️ +* Fixed a bug that caused the sidebar to appear darker than intended. + +### 🔄 Updated 🔄 +* `SidebarItems` has now respects the user’s selected accent color and mimics the look of macOS’ sidebar items more closely. + ## [2.0.2] ### 🛠️ Fixed 🛠️ * Fixed images in generated documentation. @@ -10,16 +46,16 @@ ## [2.0.0] ### 🚨 Breaking Changes 🚨 * `macos_ui` has been migrated to utilize [macos_window_utils](https://pub.dev/packages/macos_window_utils) under the hood, which provides the following benefits: - * Window animation smoothness is drastically improved, particularly when miniaturizing and deminiaturizing the application window. - * Some visual artifacts that occurred while the window was being (de)miniaturized (such as the application's shadow going missing) no longer occur. - * The sidebar remains transparent when the app's brightness setting mismatches the OS setting. - * Wallpaper tinting is now supported. - * To migrate an existing application, please refer to the “Modern window look” section in the README. + * Window animation smoothness is drastically improved, particularly when miniaturizing and deminiaturizing the application window. + * Some visual artifacts that occurred while the window was being (de)miniaturized (such as the application's shadow going missing) no longer occur. + * The sidebar remains transparent when the app's brightness setting mismatches the OS setting. + * Wallpaper tinting is now supported. + * To migrate an existing application, please refer to the “Modern window look” section in the README. * Support for Flutter 3.10 and Dart 3 * `PushButton` has been updated to support the `ControlSize` enum. - * The `buttonSize` property has been changed to `controlSize`. - * Buttons can now be any of the following sizes: mini, small, regular, or large. + * The `buttonSize` property has been changed to `controlSize`. + * Buttons can now be any of the following sizes: mini, small, regular, or large. * `PushButton.isSecondary` is now `PushButton.secondary`. * `MacosAlertDialog`: `primaryButton` and `secondaryButton` are now declared to be of type `PushButton`. * `RelevanceIndicator` has been deprecated @@ -30,22 +66,22 @@ * `MacosSwitch` has been completely rewritten and now matches the native macOS switch in appearance and behavior. * A `ControlSize` enum has been introduced, which will allow widgets to more closely match their native counterparts. * `MacosTypography` - * You can now call `MacosTypography.of(context)` as a shorthand for retrieving the typography used in your `MacosTheme`. - * `MacosFontWeight` allows using Apple-specific font weights like `w510`, `w590`, and `w860`. + * You can now call `MacosTypography.of(context)` as a shorthand for retrieving the typography used in your `MacosTheme`. + * `MacosFontWeight` allows using Apple-specific font weights like `w510`, `w590`, and `w860`. * Localization - * Added support for `weekdayAbbreviations` and `monthAbbreviations` to `MacosDatePicker`. - * Added support for `dateFormat` to `MacosDatePicker`. - * Added support for `startWeekOnMonday` to `MacosDatePicker`. + * Added support for `weekdayAbbreviations` and `monthAbbreviations` to `MacosDatePicker`. + * Added support for `dateFormat` to `MacosDatePicker`. + * Added support for `startWeekOnMonday` to `MacosDatePicker`. ### 🔄 Updated 🔄 * `MacosColor` has been updated with some previously missing elements. * `PushButton` - * Now uses the correct `body` text style instead of the incorrect `headline` + * Now uses the correct `body` text style instead of the incorrect `headline` * `PushButton`'s secondary and disabled colors more closely match their native counterparts. * `MacosCheckbox` appearance more closely matches its native counterpart. * `MacosAlertDialog` - * `primaryButton` and `secondaryButton` are now required to have `controlSize`s of `ControlSize.large`. - * Docs now suggest that `appIcon` should be of size 64x64. + * `primaryButton` and `secondaryButton` are now required to have `controlSize`s of `ControlSize.large`. + * Docs now suggest that `appIcon` should be of size 64x64. * `Toolbar` now uses the correct `title3` text style instead of the incorrect `headline` * `MacosTheme` sets the global typography more efficiently * `HelpButton` now sizes itself according to specification @@ -85,9 +121,9 @@ ## [1.11.0] * 🚨 Breaking Changes 🚨 * `ResizablePane` can now be vertically resized - * `ResizablePane.startWidth` has been changed to `ResizablePane.startSize` - * `ResizablePane.minWidth` has been changed to `ResizablePane.minSize` - * `ResizablePane.maxWidth` has been changed to `ResizablePane.maxSize` + * `ResizablePane.startWidth` has been changed to `ResizablePane.startSize` + * `ResizablePane.minWidth` has been changed to `ResizablePane.minSize` + * `ResizablePane.maxWidth` has been changed to `ResizablePane.maxSize` ## [1.10.0] 🚨 Breaking Changes 🚨 @@ -110,8 +146,8 @@ Other changes: ## [1.8.0] 🚨 Breaking Changes 🚨 * `ContentArea.builder` has been changed from a `ScrollableWidgetBuilder` to a `WidgetBuilder` due to -changes in Flutter 3.7. The `MacosScrollbar` widget needs to undergo radical changes in order to achieve the -native macOS scrollbar look and feel in the future, so this will be revisited at that time. + changes in Flutter 3.7. The `MacosScrollbar` widget needs to undergo radical changes in order to achieve the + native macOS scrollbar look and feel in the future, so this will be revisited at that time. Other changes: * Per Flutter 3.7.0: Replace deprecated `MacosTextField.toolbarOptions` with `MacosTextField.contextMenuBuilder` @@ -140,21 +176,21 @@ Other changes: ## [1.7.0] * ✨ New - * `MacosImageIcon` widget. Identical to the `ImageIcon` from `flutter/widgets.dart` except it will obey a -`MacosIconThemeData` instead of an `IconThemeData` - * `SidebarItemSize` enum, which determines the height of sidebar items and the maximum size their `leading` widgets. - * `SidebarItem` now accepts an optional `trailing` widget. + * `MacosImageIcon` widget. Identical to the `ImageIcon` from `flutter/widgets.dart` except it will obey a + `MacosIconThemeData` instead of an `IconThemeData` + * `SidebarItemSize` enum, which determines the height of sidebar items and the maximum size their `leading` widgets. + * `SidebarItem` now accepts an optional `trailing` widget. * 🔄 Updated - * `SidebarItems` now supports `SidebarItemSize` via the `itemSize` property, which defaults to -`SidebarItemSize.medium`. The widget has been updated to manage the item's height, the maximum size of the item's -leading widget, and the font size of the item's label widget according to the given `SidebarItemSize`. - * The example app has been tweaked to use some icons from the SF Symbols 4 Beta via the new `MacosImageIcon` widget. + * `SidebarItems` now supports `SidebarItemSize` via the `itemSize` property, which defaults to + `SidebarItemSize.medium`. The widget has been updated to manage the item's height, the maximum size of the item's + leading widget, and the font size of the item's label widget according to the given `SidebarItemSize`. + * The example app has been tweaked to use some icons from the SF Symbols 4 Beta via the new `MacosImageIcon` widget. ## [1.6.0] * New widgets: `MacosTabView` and `MacosTabView` * BREAKING CHANGE: `Label.yAxis` has been renamed to `Label.crossAxisAlignment` * BREAKING CHANGE: `TooltipTheme` and `TooltipThemeData` have been renamed to `MacosTooltipTheme` and -`MacosTooltipThemeData` + `MacosTooltipThemeData` ## [1.5.1] * Correct the placement of the leading widget in disclosure sidebar items [#268](https://github.com/GroovinChip/macos_ui/issues/268) @@ -174,15 +210,15 @@ leading widget, and the font size of the item's label widget according to the gi ## [1.4.0] * Migration to Flutter 3.0 - * Minimum dart sdk version is now 2.17.0 - * Use new super parameters feature - * Update to `flutter_lints: ^2.0.1` with subsequent fixes - * `MacosScrollbar` API more closely matches its material counterpart + * Minimum dart sdk version is now 2.17.0 + * Use new super parameters feature + * Update to `flutter_lints: ^2.0.1` with subsequent fixes + * `MacosScrollbar` API more closely matches its material counterpart * Update `MacosColor` to more closely match the `Color` class - * Adds `MacosColor.fromARGB` constructor - * Adds `MacosColor.fromRGBO` constructor - * Adds `alphaBlend` function - * Adds `getAlphaFromOpacity` function + * Adds `MacosColor.fromARGB` constructor + * Adds `MacosColor.fromRGBO` constructor + * Adds `alphaBlend` function + * Adds `getAlphaFromOpacity` function ## [1.3.0] * Add a `top` property to `Sidebar` @@ -196,8 +232,8 @@ leading widget, and the font size of the item's label widget according to the gi ## [1.2.0] * Improved styling for `MacosTooltip`: - * Better color and shadows. - * Displays left-aligned, below the mouse cursor. + * Better color and shadows. + * Displays left-aligned, below the mouse cursor. * New widget: `ToolBarDivider` that can be used as a divider (vertical/horizontal line) in the `ToolBar` [#231](https://github.com/GroovinChip/macos_ui/issues/231). * All toolbar widgets can now receive a `tooltipMessage` property to display a `MacosTooltip` when user hovers over them [#232](https://github.com/GroovinChip/macos_ui/issues/232). @@ -206,17 +242,17 @@ leading widget, and the font size of the item's label widget according to the gi ## [1.1.0] * New functionality for `MacosSearchField` - * Shows a list of search results in an overlay below the field - * A result can be selected and customized. + * Shows a list of search results in an overlay below the field + * A result can be selected and customized. * A `MacosOverlayFilter` widget can now be used to apply the blurry "frosted glass" effect on surfaces. * New widget: `CustomToolbarItem` that enables any widget to be used in the `Toolbar`. ## [1.0.1] * Improvements to the graphical `MacosTimePicker` - * Better color gradient on the border - * Better inner shadow - * Minor size adjustments - * API improvements + * Better color gradient on the border + * Better inner shadow + * Minor size adjustments + * API improvements * Throw an exception if `MacosColorWell` is clicked on a non-macOS platform ## [1.0.0+1] @@ -288,9 +324,9 @@ leading widget, and the font size of the item's label widget according to the gi ## [0.10.2] * Updates to `MacosIconButton` and `MacosBackButton`: - * Added a hover effect when mouse moves over the buttons ([#168](https://github.com/GroovinChip/macos_ui/issues/168)) - * Added `hoverColor` property. - * Default shape is now `BoxShape.rectangle` with border radius, as it seems to be the most used in macOS design. + * Added a hover effect when mouse moves over the buttons ([#168](https://github.com/GroovinChip/macos_ui/issues/168)) + * Added `hoverColor` property. + * Default shape is now `BoxShape.rectangle` with border radius, as it seems to be the most used in macOS design. ## [0.10.1] * Added support for transparent sidebar. Please note that changes to `MainFlutterWindow.swift` are required for this to work. [(#175)](https://github.com/GroovinChip/macos_ui/pull/175) @@ -304,7 +340,7 @@ leading widget, and the font size of the item's label widget according to the gi ## [0.9.3] * Update to `PushButton`: - * Added `isSecondary` property + * Added `isSecondary` property ## [0.9.2] * Nearly all `MouseRegion`s have been updated to use `SystemMouseCursors.basic` in order to more closely adhere to Apple norms @@ -312,7 +348,7 @@ leading widget, and the font size of the item's label widget according to the gi ## [0.9.1] * Added top-level theming for `MacosIconButton` - * Introduces the `MacosIconButtonTheme` InheritedTheme and the `MacosIconButtonThemeData` theme class + * Introduces the `MacosIconButtonTheme` InheritedTheme and the `MacosIconButtonThemeData` theme class * Updates `MacosThemeData` and `MacosIconButton` to use the new `MacosIconButtonThemeData` * Removes an unnecessary setting of VisualDensity from `MacosThemeData.dark()` @@ -321,10 +357,10 @@ leading widget, and the font size of the item's label widget according to the gi ## [0.8.2] * Updates to `MacosListTile`: - * Added `leadingWhitespace` property - * Added `onClick` callback - * Added `onLongPress` callback - * Added `mouseCursor` property + * Added `leadingWhitespace` property + * Added `onClick` callback + * Added `onLongPress` callback + * Added `mouseCursor` property ## [0.8.1] * Fix the outer border of `MacosSheet` not having a border radius @@ -386,16 +422,16 @@ leading widget, and the font size of the item's label widget according to the gi ## [0.3.0] * Add `MacosPrefix` to widgets/classes with names that overlap with the material/cupertino libraries: - * `TextField` -> `MacosTextField` - * `Scaffold` -> `MacosTextField` - * `IconButton` -> `MacosIconButton` - * `BackButton` -> `MacosBackButton` - * `Scrollbar` -> `MacosScrollbar` - * `Checkbox` -> `MacosCheckbox` - * `RadioButton` -> `MacosRadioButton` - * `Tooltip` -> `MacosTooltip` - * `Typography` -> `MacosTypography` - * `Switch` -> `MacosSwitch` + * `TextField` -> `MacosTextField` + * `Scaffold` -> `MacosTextField` + * `IconButton` -> `MacosIconButton` + * `BackButton` -> `MacosBackButton` + * `Scrollbar` -> `MacosScrollbar` + * `Checkbox` -> `MacosCheckbox` + * `RadioButton` -> `MacosRadioButton` + * `Tooltip` -> `MacosTooltip` + * `Typography` -> `MacosTypography` + * `Switch` -> `MacosSwitch` ## [0.2.4] * Fix text field prefix icon alignment @@ -409,9 +445,9 @@ leading widget, and the font size of the item's label widget according to the gi ## [0.2.1] * `IconButton` updates: - - The `color` property is now `backgroundColor` - - The widget now takes a `Widget icon` rather than `IconData iconData` for better control over widget properties - - Deprecate and remove internal `foregroundColor` value + - The `color` property is now `backgroundColor` + - The widget now takes a `Widget icon` rather than `IconData iconData` for better control over widget properties + - Deprecate and remove internal `foregroundColor` value ## [0.2.0] * New widget: `BackButton`, `IconButton` @@ -428,9 +464,9 @@ leading widget, and the font size of the item's label widget according to the gi ## [0.1.2] * Updated the theme api - * Properties in `MacosThemeData` and in `Typography` can't be null - * Renamed `DynamicColorX` to `MacosDynamicColor` - * Added the method `lerp` on all theme data classes. + * Properties in `MacosThemeData` and in `Typography` can't be null + * Renamed `DynamicColorX` to `MacosDynamicColor` + * Added the method `lerp` on all theme data classes. ## [0.1.1] * Implemented `Label` ([#61](https://github.com/GroovinChip/macos_ui/issues/61)) @@ -477,12 +513,12 @@ leading widget, and the font size of the item's label widget according to the gi ## [0.0.4] * Major theme refactor that more closely resembles flutter/material and flutter/cupertino - * The `Style` class is now `MacosThemeData` - * `MacosTheme` is now a `StatelessWidget` that returns a private `_InheritedMacosTheme`. - The static `MacosTheme.of(context)` is now defined here. - * `MacosApp` now takes a `theme` and `darkTheme` rather than `style` and `darkStyle`. - Additionally, there are minor changes to the way `MacosApp` is built that more closely - resemble how `MaterialApp` is built. + * The `Style` class is now `MacosThemeData` + * `MacosTheme` is now a `StatelessWidget` that returns a private `_InheritedMacosTheme`. + The static `MacosTheme.of(context)` is now defined here. + * `MacosApp` now takes a `theme` and `darkTheme` rather than `style` and `darkStyle`. + Additionally, there are minor changes to the way `MacosApp` is built that more closely + resemble how `MaterialApp` is built. ## [0.0.3] @@ -498,6 +534,6 @@ leading widget, and the font size of the item's label widget according to the gi ## [0.0.1] * Project creation - * `MacosApp` widget - * Basic `Typography` - * Basic theming via `MacosTheme` and `Style` + * `MacosApp` widget + * Basic `Typography` + * Basic theming via `MacosTheme` and `Style` diff --git a/example/lib/main.dart b/example/lib/main.dart index 193bef1f..cbe02dbc 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -47,8 +47,6 @@ class MacosUIGalleryApp extends StatelessWidget { final appTheme = context.watch(); return MacosApp( title: 'macos_ui Widget Gallery', - theme: MacosThemeData.light(), - darkTheme: MacosThemeData.dark(), themeMode: appTheme.mode, debugShowCheckedModeBanner: false, home: const WidgetGallery(), @@ -223,6 +221,7 @@ class _WidgetGalleryState extends State { label: Text('ResizablePane'), ), ], + expandDisclosureItems: true, ), SidebarItem( leading: MacosImageIcon( diff --git a/example/lib/pages/buttons_page.dart b/example/lib/pages/buttons_page.dart index fd61774f..26952d90 100644 --- a/example/lib/pages/buttons_page.dart +++ b/example/lib/pages/buttons_page.dart @@ -558,11 +558,20 @@ class _ButtonsPageState extends State { const SizedBox(height: 16), const WidgetTextTitle2(widgetName: 'MacosCheckbox'), const SizedBox(height: 8), - MacosCheckbox( - value: switchValue, - onChanged: (value) { - setState(() => switchValue = value); - }, + Row( + children: [ + MacosCheckbox( + value: switchValue, + onChanged: (value) { + setState(() => switchValue = value); + }, + ), + const SizedBox(width: 8), + MacosCheckbox( + value: switchValue, + onChanged: null, + ), + ], ), const SizedBox(height: 16), const WidgetTextTitle2(widgetName: 'MacosRadioButton'), diff --git a/example/macos/Podfile.lock b/example/macos/Podfile.lock index 6aa1d86e..475f42a3 100644 --- a/example/macos/Podfile.lock +++ b/example/macos/Podfile.lock @@ -39,9 +39,9 @@ SPEC CHECKSUMS: FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 macos_ui: 6229a8922cd97bafb7d9636c8eb8dfb0744183ca macos_window_utils: 933f91f64805e2eb91a5bd057cf97cd097276663 - path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8 - url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95 + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + url_launcher_macos: 5f437abeda8c85500ceb03f5c1938a8c5a705399 PODFILE CHECKSUM: ff0a9a3ce75ee73f200ca7e2f47745698c917ef9 -COCOAPODS: 1.12.1 +COCOAPODS: 1.14.3 diff --git a/example/macos/Runner.xcodeproj/project.pbxproj b/example/macos/Runner.xcodeproj/project.pbxproj index 2c562a4e..717c51d9 100644 --- a/example/macos/Runner.xcodeproj/project.pbxproj +++ b/example/macos/Runner.xcodeproj/project.pbxproj @@ -202,7 +202,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 33CC10EC2044A3C60003C045 = { diff --git a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index fb7259e1..5b055a3a 100644 --- a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ Bool { return true diff --git a/example/pubspec.lock b/example/pubspec.lock index 253f08cb..640f7187 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -45,26 +45,26 @@ packages: dependency: transitive description: name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.2" + version: "1.18.0" crypto: dependency: transitive description: name: crypto - sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27 url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.5" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "1.0.8" equatable: dependency: transitive description: @@ -85,18 +85,10 @@ packages: dependency: transitive description: name: ffi - sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 - url: "https://pub.dev" - source: hosted - version: "2.0.2" - file: - dependency: transitive - description: - name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "2.1.3" flutter: dependency: "direct main" description: flutter @@ -106,10 +98,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4" + sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" url: "https://pub.dev" source: hosted - version: "2.0.2" + version: "4.0.0" flutter_test: dependency: "direct dev" description: flutter @@ -124,26 +116,26 @@ packages: dependency: "direct main" description: name: google_fonts - sha256: e20ff62b158b96f392bfc8afe29dee1503c94fbea2cbe8186fd59b756b8ae982 + sha256: b1ac0fe2832c9cc95e5e88b57d627c5e68c223b9657f4b96e1487aa9098c7b82 url: "https://pub.dev" source: hosted - version: "5.1.0" + version: "6.2.1" gradient_borders: dependency: transitive description: name: gradient_borders - sha256: "69eeaff519d145a4c6c213ada1abae386bcc8981a4970d923e478ce7ba19e309" + sha256: b1cd969552c83f458ff755aa68e13a0327d09f06c3f42f471b423b01427f21f8 url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.0.1" http: dependency: transitive description: name: http - sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.2" http_parser: dependency: transitive description: @@ -152,53 +144,77 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + url: "https://pub.dev" + source: hosted + version: "10.0.5" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + url: "https://pub.dev" + source: hosted + version: "3.0.5" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" lints: dependency: transitive description: name: lints - sha256: "6b0206b0bf4f04961fc5438198ccb3a885685cd67d4d4a32cc20ad7f8adbe015" + sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "4.0.0" macos_ui: dependency: "direct main" description: path: ".." relative: true source: path - version: "2.0.2" + version: "2.1.0" macos_window_utils: dependency: transitive description: name: macos_window_utils - sha256: "43a90473f8786f00f07203e6819dab67e032f8896dafa4a6f85fbc71fba32c0b" + sha256: "230be594d26f6dee92c5a1544f4242d25138a5bfb9f185b27f14de3949ef0be8" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.5.0" matcher: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.15.0" nested: dependency: transitive description: @@ -211,90 +227,82 @@ packages: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_provider: dependency: transitive description: name: path_provider - sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2" + sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 url: "https://pub.dev" source: hosted - version: "2.0.15" + version: "2.1.4" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86" + sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7" url: "https://pub.dev" source: hosted - version: "2.0.27" + version: "2.2.10" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "1995d88ec2948dac43edf8fe58eb434d35d22a2940ecee1a9fefcd62beee6eb3" + sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.4.0" path_provider_linux: dependency: transitive description: name: path_provider_linux - sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57 + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 url: "https://pub.dev" source: hosted - version: "2.1.11" + version: "2.2.1" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" url: "https://pub.dev" source: hosted - version: "2.0.6" + version: "2.1.2" path_provider_windows: dependency: transitive description: name: path_provider_windows - sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96" + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.1.7" + version: "2.3.0" platform: dependency: transitive description: name: platform - sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.5" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - process: - dependency: transitive - description: - name: process - sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted - version: "4.2.4" + version: "2.1.8" provider: dependency: "direct main" description: name: provider - sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c url: "https://pub.dev" source: hosted - version: "6.0.5" + version: "6.1.2" sky_engine: dependency: transitive description: flutter @@ -312,18 +320,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -344,10 +352,10 @@ packages: dependency: transitive description: name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.7.2" typed_data: dependency: transitive description: @@ -360,66 +368,66 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: "781bd58a1eb16069412365c98597726cd8810ae27435f04b3b4d3a470bacd61e" + sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3" url: "https://pub.dev" source: hosted - version: "6.1.12" + version: "6.3.0" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "15f5acbf0dce90146a0f5a2c4a002b1814a6303c4c5c075aa2623b2d16156f03" + sha256: e35a698ac302dd68e41f73250bd9517fe3ab5fa4f18fe4647a0872db61bacbab url: "https://pub.dev" source: hosted - version: "6.0.36" + version: "6.3.10" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "9af7ea73259886b92199f9e42c116072f05ff9bea2dcb339ab935dfc957392c2" + sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "6.3.1" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5" + sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.2.0" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "1c4fdc0bfea61a70792ce97157e5cc17260f61abbe4f39354513f39ec6fd73b1" + sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de" url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "3.2.0" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - sha256: bfdfa402f1f3298637d71ca8ecfe840b4696698213d5346e9d12d4ab647ee2ea + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.3.2" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: cc26720eefe98c1b71d85f9dc7ef0cada5132617046369d9dc296b3ecaa5cbb4 + sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" url: "https://pub.dev" source: hosted - version: "2.0.18" + version: "2.3.3" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "7967065dd2b5fccc18c653b97958fdf839c5478c28e767c61ee879f4e7882422" + sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185" url: "https://pub.dev" source: hosted - version: "3.0.7" + version: "3.1.2" vector_math: dependency: transitive description: @@ -428,30 +436,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" - web: + vm_service: dependency: transitive description: - name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + name: vm_service + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "0.1.4-beta" - win32: + version: "14.2.5" + web: dependency: transitive description: - name: win32 - sha256: dfdf0136e0aa7a1b474ea133e67cb0154a0acd2599c4f3ada3b49d38d38793ee + name: web + sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062 url: "https://pub.dev" source: hosted - version: "5.0.5" + version: "1.0.0" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1 + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.0.4" sdks: - dart: ">=3.1.0-185.0.dev <4.0.0" - flutter: ">=3.10.0" + dart: ">=3.5.3 <4.0.0" + flutter: ">=3.24.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 0a008b51..22e45eb8 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -4,23 +4,23 @@ publish_to: 'none' version: 1.0.0+1 environment: - sdk: '>=3.0.0 <4.0.0' + sdk: '>=3.5.3 <4.0.0' dependencies: flutter: sdk: flutter - cupertino_icons: ^1.0.5 + cupertino_icons: ^1.0.8 macos_ui: path: .. - provider: ^6.0.5 - google_fonts: ^5.1.0 - url_launcher: ^6.1.12 + provider: ^6.1.2 + google_fonts: ^6.2.1 + url_launcher: ^6.3.0 dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^2.0.2 + flutter_lints: ^4.0.0 flutter: assets: diff --git a/lib/macos_ui.dart b/lib/macos_ui.dart index 62dcc602..d47a163a 100644 --- a/lib/macos_ui.dart +++ b/lib/macos_ui.dart @@ -88,3 +88,4 @@ export 'src/theme/search_field_theme.dart'; export 'src/theme/time_picker_theme.dart'; export 'src/theme/tooltip_theme.dart'; export 'src/theme/typography.dart'; +export 'src/enums/accent_color.dart'; diff --git a/lib/src/buttons/checkbox.dart b/lib/src/buttons/checkbox.dart index d7f8bcc3..2d21e7c7 100644 --- a/lib/src/buttons/checkbox.dart +++ b/lib/src/buttons/checkbox.dart @@ -1,4 +1,5 @@ import 'package:flutter/rendering.dart'; +import 'package:gradient_borders/gradient_borders.dart'; import 'package:macos_ui/macos_ui.dart'; import 'package:macos_ui/src/library.dart'; @@ -82,92 +83,403 @@ class MacosCheckbox extends StatelessWidget { assert(debugCheckHasMacosTheme(context)); final MacosThemeData theme = MacosTheme.of(context); bool isLight = !theme.brightness.isDark; - return GestureDetector( - onTap: () { - if (value == null || value == false) { - onChanged?.call(true); - } else { - onChanged?.call(false); - } - }, - child: Semantics( - // value == true because [value] can be null - checked: value == true, - label: semanticLabel, - child: Container( - height: size, - width: size, - alignment: Alignment.center, - decoration: isDisabled || value == null || value == true - ? BoxDecoration( - color: MacosDynamicColor.resolve( - isDisabled - ? disabledColor - : activeColor ?? theme.primaryColor, - context, - ), - borderRadius: const BorderRadius.all(Radius.circular(4.0)), - ) - : isLight - ? ShapeDecoration( - gradient: LinearGradient( - begin: const Alignment(0.0, -1.0), - end: const Alignment(0, 0), - colors: [ - Colors.white.withOpacity(0.85), - Colors.white.withOpacity(1.0), - ], - ), - shadows: const [ - BoxShadow( - color: Color(0x3F000000), - blurRadius: 1, - blurStyle: BlurStyle.inner, - offset: Offset(0, 0), - spreadRadius: 0.0, - ), - ], - shape: RoundedRectangleBorder( - side: BorderSide( - width: 0.25, - color: Colors.black.withOpacity(0.35000000596046448), + return StreamBuilder( + stream: AccentColorListener.instance.onChanged, + builder: (context, _) { + return StreamBuilder( + stream: WindowMainStateListener.instance.onChanged, + builder: (context, _) { + final accentColor = + MacosTheme.of(context).accentColor ?? AccentColor.blue; + final isMainWindow = + MacosTheme.of(context).isMainWindow ?? true; + + return GestureDetector( + onTap: () { + if (value == null || value == false) { + onChanged?.call(true); + } else { + onChanged?.call(false); + } + }, + child: Semantics( + // value == true because [value] can be null + checked: value == true, + label: semanticLabel, + child: Container( + height: size, + width: size, + alignment: Alignment.center, + child: SizedBox.expand( + child: _DecoratedContainer( + accentColor: accentColor, + isDisabled: isDisabled, + isLight: isLight, + isMainWindow: isMainWindow, + value: value, + isMixed: isMixed, + theme: theme, + size: size, ), - borderRadius: - const BorderRadius.all(Radius.circular(3.5)), - ), - ) - : ShapeDecoration( - gradient: LinearGradient( - begin: const Alignment(0.0, -1.0), - end: const Alignment(0, 1), - colors: [ - Colors.white.withOpacity(0.14000000059604645), - Colors.white.withOpacity(0.2800000011920929), - ], - ), - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(3)), ), - shadows: const [ - BoxShadow( - color: Color(0x3F000000), - blurRadius: 1, - offset: Offset(0, 0), - spreadRadius: 0, - ), - ], ), + ), + ); + }); + }); + } +} + +/// A widget that builds a decorated checkbox. +class _DecoratedContainer extends StatelessWidget { + const _DecoratedContainer({ + required this.accentColor, + required this.isDisabled, + required this.isLight, + required this.isMainWindow, + required this.value, + required this.isMixed, + required this.theme, + required this.size, + }); + + final AccentColor accentColor; + final bool isDisabled; + final bool isLight; + final bool isMainWindow; + final bool? value; + final bool isMixed; + final MacosThemeData theme; + final double size; + + @override + Widget build(BuildContext context) { + return Container( + decoration: _BoxDecorationBuilder.buildBoxDecoration( + accentColor: accentColor, + isEnabled: !isDisabled, + isDarkModeEnabled: !isLight, + isMainWindow: isMainWindow, + value: value, + ), + child: _CheckboxStack( + value: value, + isDisabled: isDisabled, + isMixed: isMixed, + theme: theme, + isMainWindow: isMainWindow, + size: size, + ), + ); + } +} + +/// A stack containing the checkbox’s inner drop shadow and checkmark icon. +class _CheckboxStack extends StatelessWidget { + const _CheckboxStack({ + required this.value, + required this.isDisabled, + required this.isMixed, + required this.theme, + required this.isMainWindow, + required this.size, + }); + + final bool? value; + final bool isDisabled; + final bool isMixed; + final MacosThemeData theme; + final bool isMainWindow; + final double size; + + @override + Widget build(BuildContext context) { + final icon = value == false + ? null + : isMixed + ? CupertinoIcons.minus + : CupertinoIcons.checkmark; + + return Stack( + children: [ + _InnerDropShadow( + value: value, + isEnabled: !isDisabled, + ), + Center( child: Icon( - isDisabled || value == false - ? null - : isMixed - ? CupertinoIcons.minus - : CupertinoIcons.check_mark, - color: CupertinoColors.white, + icon, + color: _getCheckmarkColor(), size: (size - 3).clamp(0, size), ), ), + ], + ); + } + + _getCheckmarkColor() { + if (isDisabled) { + return const MacosColor.fromRGBO(172, 172, 172, 1.0); + } + + if (theme.brightness.isDark) { + return theme.accentColor == AccentColor.graphite && isMainWindow + ? CupertinoColors.black + : CupertinoColors.white; + } + + if (theme.isMainWindow == false) { + return CupertinoColors.black; + } + + return CupertinoColors.white; + } +} + +/// A widget that paints an inner drop shadow for the checkbox in light mode. +class _InnerDropShadow extends StatelessWidget { + /// The value of the checkbox. + final bool? value; + + /// Whether the checkbox is enabled. + final bool isEnabled; + + /// Creates a widget that paints an inner drop shadow for a checkbox. + const _InnerDropShadow({ + required this.value, + required this.isEnabled, + }); + + @override + Widget build(BuildContext context) { + final theme = MacosTheme.of(context); + + if (theme.brightness.isDark) { + return const SizedBox(); + } + + if (value == true && theme.isMainWindow == true && isEnabled) { + return const SizedBox(); + } + + final color = isEnabled + ? CupertinoColors.white + : const MacosColor.fromRGBO(255, 255, 255, 0.8); + + return SizedBox.expand( + child: Container( + clipBehavior: Clip.antiAlias, + decoration: const BoxDecoration( + color: MacosColor.fromRGBO(0, 0, 0, 0.15), + borderRadius: BorderRadius.all(Radius.circular(3.5)), + ), + child: DecoratedBox( + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(3.5)), + boxShadow: [ + BoxShadow( + color: color, + offset: const Offset(0.0, 0.5), + blurRadius: 1.0, + ), + ], + ), + ), + ), + ); + } +} + +class _BoxDecorationBuilder { + /// Gets the colors to use for the [BoxDecoration]’s gradient based on the + /// provided [accentColor], [isEnabled], and [isDarkModeEnabled] properties. + static List getGradientColors({ + required AccentColor accentColor, + required bool isEnabled, + required bool isDarkModeEnabled, + required bool isMainWindow, + required bool? value, + }) { + final isEnabledFactor = isEnabled || !isDarkModeEnabled ? 1.0 : 0.5; + + final showDisabledCheckbox = !isMainWindow || !isEnabled || value == false; + + if (showDisabledCheckbox) { + return isDarkModeEnabled + ? [ + MacosColor.fromRGBO(74, 74, 74, 1.0 * isEnabledFactor), + MacosColor.fromRGBO(101, 101, 101, 1.0 * isEnabledFactor), + ] + : const [ + MacosColors.transparent, + MacosColors.transparent, + ]; + } + + if (isDarkModeEnabled) { + switch (accentColor) { + case AccentColor.blue: + return [ + MacosColor.fromRGBO(23, 105, 229, 1.0 * isEnabledFactor), + MacosColor.fromRGBO(20, 94, 203, 1.0 * isEnabledFactor), + ]; + + case AccentColor.purple: + return [ + MacosColor.fromRGBO(203, 46, 202, 1.0 * isEnabledFactor), + MacosColor.fromRGBO(182, 40, 182, 1.0 * isEnabledFactor), + ]; + + case AccentColor.pink: + return [ + MacosColor.fromRGBO(229, 75, 145, 1.0 * isEnabledFactor), + MacosColor.fromRGBO(205, 61, 129, 1.0 * isEnabledFactor), + ]; + + case AccentColor.red: + return [ + MacosColor.fromRGBO(237, 64, 68, 1.0 * isEnabledFactor), + MacosColor.fromRGBO(213, 56, 61, 1.0 * isEnabledFactor), + ]; + + case AccentColor.orange: + return [ + MacosColor.fromRGBO(244, 114, 0, 1.0 * isEnabledFactor), + MacosColor.fromRGBO(219, 102, 0, 1.0 * isEnabledFactor), + ]; + + case AccentColor.yellow: + return [ + MacosColor.fromRGBO(233, 176, 4, 1.0 * isEnabledFactor), + MacosColor.fromRGBO(209, 157, 3, 1.0 * isEnabledFactor), + ]; + + case AccentColor.green: + return [ + MacosColor.fromRGBO(75, 177, 45, 1.0 * isEnabledFactor), + MacosColor.fromRGBO(67, 159, 40, 1.0 * isEnabledFactor), + ]; + + case AccentColor.graphite: + return [ + MacosColor.fromRGBO(148, 148, 148, 1.0 * isEnabledFactor), + MacosColor.fromRGBO(148, 148, 148, 1.0 * isEnabledFactor), + ]; + + default: + throw UnimplementedError(); + } + } else { + switch (accentColor) { + case AccentColor.blue: + return [ + MacosColor.fromRGBO(39, 145, 255, 1.0 * isEnabledFactor), + MacosColor.fromRGBO(1, 123, 255, 1.0 * isEnabledFactor), + ]; + + case AccentColor.purple: + return [ + MacosColor.fromRGBO(173, 56, 177, 1.0 * isEnabledFactor), + MacosColor.fromRGBO(159, 19, 163, 1.0 * isEnabledFactor), + ]; + + case AccentColor.pink: + return [ + MacosColor.fromRGBO(237, 102, 165, 1.0 * isEnabledFactor), + MacosColor.fromRGBO(234, 76, 149, 1.0 * isEnabledFactor), + ]; + + case AccentColor.red: + return [ + MacosColor.fromRGBO(225, 60, 66, 1.0 * isEnabledFactor), + MacosColor.fromRGBO(220, 26, 31, 1.0 * isEnabledFactor), + ]; + + case AccentColor.orange: + return [ + MacosColor.fromRGBO(247, 130, 31, 1.0 * isEnabledFactor), + MacosColor.fromRGBO(245, 108, 0, 1.0 * isEnabledFactor), + ]; + + case AccentColor.yellow: + return [ + MacosColor.fromRGBO(242, 189, 32, 1.0 * isEnabledFactor), + MacosColor.fromRGBO(240, 178, 0, 1.0 * isEnabledFactor), + ]; + + case AccentColor.green: + return [ + MacosColor.fromRGBO(90, 185, 59, 1.0 * isEnabledFactor), + MacosColor.fromRGBO(60, 172, 25, 1.0 * isEnabledFactor), + ]; + + case AccentColor.graphite: + return [ + MacosColor.fromRGBO(86, 86, 86, 1.0 * isEnabledFactor), + MacosColor.fromRGBO(55, 55, 55, 1.0 * isEnabledFactor), + ]; + + default: + throw UnimplementedError(); + } + } + } + + /// Builds a [BoxDecoration] for a [MacosPushButton]. + static BoxDecoration buildBoxDecoration({ + required AccentColor accentColor, + required bool isEnabled, + required bool isDarkModeEnabled, + required bool isMainWindow, + required bool? value, + }) { + final isEnabledFactor = isEnabled ? 1.0 : 0.5; + + final List shadows = isDarkModeEnabled + ? const [ + BoxShadow( + color: MacosColor.fromRGBO(0, 0, 0, 0.8), + blurRadius: 0.7, + spreadRadius: -0.5, + offset: Offset(0.0, 0.5), + blurStyle: BlurStyle.outer, + ) + ] + : const []; + + return BoxDecoration( + border: isDarkModeEnabled + ? GradientBoxBorder( + gradient: LinearGradient( + colors: [ + MacosColor.fromRGBO(255, 255, 255, 0.43 * isEnabledFactor), + const MacosColor.fromRGBO(255, 255, 255, 0.0), + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + stops: const [0.0, 0.2], + ), + width: 0.7, + ) + : Border.all( + color: value == false && isEnabled + ? const MacosColor.fromRGBO(0, 0, 0, 0.15) + : const MacosColor.fromRGBO(0, 0, 0, 0.12), + width: 0.5, + ), + gradient: LinearGradient( + colors: getGradientColors( + accentColor: accentColor, + isEnabled: isEnabled, + isDarkModeEnabled: isDarkModeEnabled, + isMainWindow: isMainWindow, + value: value, + ), + begin: Alignment.topCenter, + end: Alignment.bottomCenter, ), + boxShadow: shadows, + borderRadius: const BorderRadius.all(Radius.circular(3.5)), ); } } diff --git a/lib/src/buttons/popup_button.dart b/lib/src/buttons/popup_button.dart index 37c6559b..8082f78c 100644 --- a/lib/src/buttons/popup_button.dart +++ b/lib/src/buttons/popup_button.dart @@ -99,7 +99,7 @@ class _MacosPopupMenuItemButtonState child: GestureDetector( onTap: _handleOnTap, child: Focus( - onKey: (FocusNode node, RawKeyEvent event) { + onKeyEvent: (FocusNode node, KeyEvent event) { if (event.logicalKey == LogicalKeyboardKey.enter) { _handleOnTap(); return KeyEventResult.handled; diff --git a/lib/src/buttons/pulldown_button.dart b/lib/src/buttons/pulldown_button.dart index 91de97a7..37c0e7d1 100644 --- a/lib/src/buttons/pulldown_button.dart +++ b/lib/src/buttons/pulldown_button.dart @@ -94,7 +94,7 @@ class _MacosPulldownMenuItemButtonState child: GestureDetector( onTap: _handleOnTap, child: Focus( - onKey: (FocusNode node, RawKeyEvent event) { + onKeyEvent: (FocusNode node, KeyEvent event) { if (event.logicalKey == LogicalKeyboardKey.enter) { _handleOnTap(); return KeyEventResult.handled; diff --git a/lib/src/buttons/push_button.dart b/lib/src/buttons/push_button.dart index df0cf4fe..e95a9857 100644 --- a/lib/src/buttons/push_button.dart +++ b/lib/src/buttons/push_button.dart @@ -4,7 +4,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; import 'package:gradient_borders/gradient_borders.dart'; import 'package:macos_ui/macos_ui.dart'; -import 'package:macos_ui/src/enums/accent_color.dart'; import 'package:macos_ui/src/library.dart'; const _kMiniButtonSize = Size(26.0, 11.0); @@ -256,8 +255,8 @@ class PushButtonState extends State @visibleForTesting bool buttonHeldDown = false; - AccentColor get _accentColor => - AccentColorListener.instance.currentAccentColor ?? AccentColor.blue; + AccentColor _getAccentColor(BuildContext context) => + MacosTheme.of(context).accentColor ?? AccentColor.blue; BoxDecoration _getBoxDecoration() { // If the window isn’t currently the main window (that is, it is not in @@ -265,7 +264,7 @@ class PushButtonState extends State final isMainWindow = WindowMainStateListener.instance.isMainWindow; return _BoxDecorationBuilder.buildBoxDecoration( - accentColor: _accentColor, + accentColor: _getAccentColor(context), isEnabled: widget.enabled, isDarkModeEnabled: MacosTheme.of(context).brightness.isDark, isSecondary: !isMainWindow || (widget.secondary ?? false), @@ -284,7 +283,7 @@ class PushButtonState extends State return MacosDynamicColor.resolve( widget.color ?? _BoxDecorationBuilder.getGradientColors( - accentColor: _accentColor, + accentColor: _getAccentColor(context), isEnabled: enabled, isDarkModeEnabled: theme.brightness.isDark, isSecondary: isSecondary || !isWindowMain, diff --git a/lib/src/buttons/radio_button.dart b/lib/src/buttons/radio_button.dart index 57097758..eda3de26 100644 --- a/lib/src/buttons/radio_button.dart +++ b/lib/src/buttons/radio_button.dart @@ -91,7 +91,7 @@ class MacosRadioButton extends StatelessWidget { final MacosThemeData theme = MacosTheme.of(context); final isLight = !theme.brightness.isDark; return GestureDetector( - onTap: () => onChanged!(value), + onTap: isDisabled ? null : () => onChanged!(value), child: Semantics( checked: selected, label: semanticLabel, diff --git a/lib/src/layout/sidebar/sidebar_item.dart b/lib/src/layout/sidebar/sidebar_item.dart index 1454ccbd..e2666f20 100644 --- a/lib/src/layout/sidebar/sidebar_item.dart +++ b/lib/src/layout/sidebar/sidebar_item.dart @@ -19,6 +19,7 @@ class SidebarItem with Diagnosticable { this.focusNode, this.semanticLabel, this.disclosureItems, + this.expandDisclosureItems = false, this.trailing, }); @@ -43,7 +44,7 @@ class SidebarItem with Diagnosticable { final Color? unselectedColor; /// The [shape] property specifies the outline (border) of the - /// decoration. The shape must not be null. It's used alonside + /// decoration. The shape must not be null. It's used alongside /// [selectedColor]. final ShapeBorder? shape; @@ -58,6 +59,11 @@ class SidebarItem with Diagnosticable { /// If non-null and [leading] is null, a local animated icon is created final List? disclosureItems; + /// If true, the disclosure items will be expanded otherwise collapsed. + /// + /// Defaults to false. There is no impact if [disclosureItems] is null. + final bool expandDisclosureItems; + /// An optional trailing widget. /// /// Typically a text indicator of a count of items, like in this @@ -77,6 +83,8 @@ class SidebarItem with Diagnosticable { 'disclosure items', disclosureItems, )); + properties.add( + FlagProperty('expandDisclosureItems', value: expandDisclosureItems)); properties.add(DiagnosticsProperty('trailing', trailing)); } } diff --git a/lib/src/layout/sidebar/sidebar_items.dart b/lib/src/layout/sidebar/sidebar_items.dart index 65b3dadb..6000789c 100644 --- a/lib/src/layout/sidebar/sidebar_items.dart +++ b/lib/src/layout/sidebar/sidebar_items.dart @@ -79,7 +79,8 @@ class SidebarItems extends StatelessWidget { /// The color to paint the item when it's selected. /// - /// If null, [MacosThemeData.primaryColor] is used. + /// If null, the color is chosen automatically based on the user’s selected + /// system accent color and whether the sidebar is in the main window. final Color? selectedColor; /// The color to paint the item when it's unselected. @@ -97,6 +98,21 @@ class SidebarItems extends StatelessWidget { /// Defaults to [SystemMouseCursors.basic]. final MouseCursor? cursor; + /// The user’s selected system accent color. + AccentColor _getAccentColor(BuildContext context) => + MacosTheme.of(context).accentColor ?? AccentColor.blue; + + /// Returns the sidebar item’s selected color. + Color _getColor(BuildContext context) { + final isMainWindow = WindowMainStateListener.instance.isMainWindow; + + return _ColorProvider.getSelectedColor( + accentColor: _getAccentColor(context), + isDarkModeEnabled: MacosTheme.of(context).brightness.isDark, + isWindowMain: isMainWindow, + ); + } + List get _allItems { List result = []; for (var element in items) { @@ -117,39 +133,50 @@ class SidebarItems extends StatelessWidget { final theme = MacosTheme.of(context); return MacosIconTheme.merge( data: const MacosIconThemeData(size: 20), - child: _SidebarItemsConfiguration( - selectedColor: selectedColor ?? theme.primaryColor, - unselectedColor: unselectedColor ?? MacosColors.transparent, - shape: shape ?? _defaultShape, - itemSize: itemSize, - child: ListView( - controller: scrollController, - physics: const ClampingScrollPhysics(), - padding: EdgeInsets.all(10.0 - theme.visualDensity.horizontal), - children: List.generate(items.length, (index) { - final item = items[index]; - if (item.disclosureItems != null) { - return MouseRegion( - cursor: cursor!, - child: _DisclosureSidebarItem( - item: item, - selectedItem: _allItems[currentIndex], - onChanged: (item) { - onChanged(_allItems.indexOf(item)); - }, + child: StreamBuilder( + stream: AccentColorListener.instance.onChanged, + builder: (context, _) { + return StreamBuilder( + stream: WindowMainStateListener.instance.onChanged, + builder: (context, _) { + return _SidebarItemsConfiguration( + selectedColor: selectedColor ?? _getColor(context), + unselectedColor: unselectedColor ?? MacosColors.transparent, + shape: shape ?? _defaultShape, + itemSize: itemSize, + child: ListView( + controller: scrollController, + physics: const ClampingScrollPhysics(), + padding: + EdgeInsets.all(10.0 - theme.visualDensity.horizontal), + children: List.generate(items.length, (index) { + final item = items[index]; + if (item.disclosureItems != null) { + return MouseRegion( + cursor: cursor!, + child: _DisclosureSidebarItem( + item: item, + selectedItem: _allItems[currentIndex], + onChanged: (item) { + onChanged(_allItems.indexOf(item)); + }, + ), + ); + } + return MouseRegion( + cursor: cursor!, + child: _SidebarItem( + item: item, + selected: _allItems[currentIndex] == item, + onClick: () => onChanged(_allItems.indexOf(item)), + ), + ); + }), ), ); - } - return MouseRegion( - cursor: cursor!, - child: _SidebarItem( - item: item, - selected: _allItems[currentIndex] == item, - onClick: () => onChanged(_allItems.indexOf(item)), - ), - ); - }), - ), + }, + ); + }, ), ); } @@ -291,11 +318,14 @@ class _SidebarItem extends StatelessWidget { child: item.leading!, ), ), - DefaultTextStyle( - style: labelStyle.copyWith( - color: selected ? textLuminance(selectedColor) : null, + Expanded( + child: DefaultTextStyle( + style: labelStyle.copyWith( + color: selected ? textLuminance(selectedColor) : null, + overflow: TextOverflow.ellipsis, + ), + child: item.label, ), - child: item.label, ), if (hasTrailing) ...[ const Spacer(), @@ -348,8 +378,7 @@ class __DisclosureSidebarItemState extends State<_DisclosureSidebarItem> late AnimationController _controller; late Animation _iconTurns; late Animation _heightFactor; - - bool _isExpanded = false; + late bool _isExpanded; bool get hasLeading => widget.item.leading != null; @@ -359,6 +388,11 @@ class __DisclosureSidebarItemState extends State<_DisclosureSidebarItem> _controller = AnimationController(duration: _kExpand, vsync: this); _heightFactor = _controller.drive(_easeInTween); _iconTurns = _controller.drive(_halfTween.chain(_easeInTween)); + + _isExpanded = widget.item.expandDisclosureItems; + if (_isExpanded) { + _controller.forward(); + } } void _handleTap() { @@ -497,3 +531,74 @@ class __DisclosureSidebarItemState extends State<_DisclosureSidebarItem> ); } } + +class _ColorProvider { + /// Returns the selected color based on the provided parameters. + static Color getSelectedColor({ + required AccentColor accentColor, + required bool isDarkModeEnabled, + required bool isWindowMain, + }) { + if (isDarkModeEnabled) { + if (!isWindowMain) { + return const MacosColor.fromRGBO(76, 78, 65, 1.0); + } + + switch (accentColor) { + case AccentColor.blue: + return const MacosColor.fromRGBO(22, 105, 229, 0.749); + + case AccentColor.purple: + return const MacosColor.fromRGBO(204, 45, 202, 0.749); + + case AccentColor.pink: + return const MacosColor.fromRGBO(229, 74, 145, 0.749); + + case AccentColor.red: + return const MacosColor.fromRGBO(238, 64, 68, 0.749); + + case AccentColor.orange: + return const MacosColor.fromRGBO(244, 114, 0, 0.749); + + case AccentColor.yellow: + return const MacosColor.fromRGBO(233, 176, 0, 0.749); + + case AccentColor.green: + return const MacosColor.fromRGBO(76, 177, 45, 0.749); + + case AccentColor.graphite: + return const MacosColor.fromRGBO(129, 129, 122, 0.824); + } + } + + if (!isWindowMain) { + return const MacosColor.fromRGBO(213, 213, 208, 1.0); + } + + switch (accentColor) { + case AccentColor.blue: + return const MacosColor.fromRGBO(9, 129, 255, 0.749); + + case AccentColor.purple: + return const MacosColor.fromRGBO(162, 28, 165, 0.749); + + case AccentColor.pink: + return const MacosColor.fromRGBO(234, 81, 152, 0.749); + + case AccentColor.red: + return const MacosColor.fromRGBO(220, 32, 40, 0.749); + + case AccentColor.orange: + return const MacosColor.fromRGBO(245, 113, 0, 0.749); + + case AccentColor.yellow: + return const MacosColor.fromRGBO(240, 180, 2, 0.749); + + case AccentColor.green: + return const MacosColor.fromRGBO(66, 174, 33, 0.749); + + case AccentColor.graphite: + return const MacosColor.fromRGBO(174, 174, 167, 0.847); + } + } +} diff --git a/lib/src/layout/toolbar/toolbar_overflow_menu_item.dart b/lib/src/layout/toolbar/toolbar_overflow_menu_item.dart index e92c57c2..952420f9 100644 --- a/lib/src/layout/toolbar/toolbar_overflow_menu_item.dart +++ b/lib/src/layout/toolbar/toolbar_overflow_menu_item.dart @@ -89,7 +89,7 @@ class _ToolbarOverflowMenuItemState extends State { child: GestureDetector( onTap: _handleOnTap, child: Focus( - onKey: (FocusNode node, RawKeyEvent event) { + onKeyEvent: (FocusNode node, KeyEvent event) { if (event.logicalKey == LogicalKeyboardKey.enter) { _handleOnTap(); return KeyEventResult.handled; diff --git a/lib/src/layout/window.dart b/lib/src/layout/window.dart index 85c20417..d28511c0 100644 --- a/lib/src/layout/window.dart +++ b/lib/src/layout/window.dart @@ -265,95 +265,113 @@ class _MacosWindowState extends State { minHeight: height, maxHeight: height, ).normalize(), - child: kIsWeb ? ColoredBox( - color: theme.canvasColor, - child: Column( - children: [ - // If an app is running on macOS, apply - // sidebar.topOffset as needed in order to avoid the - // traffic lights. Otherwise, position the sidebar - // by the top of the application's bounds based on - // the presence of sidebar.top. - if (!kIsWeb && sidebar.topOffset > 0) ...[ - SizedBox(height: sidebar.topOffset), - ] else if (sidebar.top != null) ...[ - const SizedBox(height: 12), - ] else - const SizedBox.shrink(), - if (_sidebarScrollController.hasClients && - _sidebarScrollController.offset > 0.0) - Divider(thickness: 1, height: 1, color: dividerColor), - if (sidebar.top != null && constraints.maxHeight > 81) - Padding( - padding: - const EdgeInsets.symmetric(horizontal: 8.0), - child: sidebar.top!, - ), - Expanded( - child: MacosScrollbar( - controller: _sidebarScrollController, - child: Padding( - padding: sidebar.padding, - child: sidebar.builder( - context, - _sidebarScrollController, + child: kIsWeb + ? ColoredBox( + color: theme.canvasColor, + child: Column( + children: [ + // If an app is running on macOS, apply + // sidebar.topOffset as needed in order to avoid + // the traffic lights. Otherwise, position the + // sidebar by the top of the application's bounds + // based on the presence of sidebar.top. + if (!kIsWeb && sidebar.topOffset > 0) ...[ + SizedBox(height: sidebar.topOffset), + ] else if (sidebar.top != null) ...[ + const SizedBox(height: 12), + ] else + const SizedBox.shrink(), + if (_sidebarScrollController.hasClients && + _sidebarScrollController.offset > 0.0) + Divider( + thickness: 1, + height: 1, + color: dividerColor), + if (sidebar.top != null && + constraints.maxHeight > 81) + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + ), + child: sidebar.top!, + ), + Expanded( + child: MacosScrollbar( + controller: _sidebarScrollController, + child: Padding( + padding: sidebar.padding, + child: sidebar.builder( + context, + _sidebarScrollController, + ), + ), + ), ), - ), - ), - ), - if (sidebar.bottom != null && - constraints.maxHeight > 141) - Padding( - padding: const EdgeInsets.all(16.0), - child: sidebar.bottom!, - ), - ], - ), - ) : TransparentMacOSSidebar( - state: sidebarState, - child: Column( - children: [ - // If an app is running on macOS, apply - // sidebar.topOffset as needed in order to avoid the - // traffic lights. Otherwise, position the sidebar - // by the top of the application's bounds based on - // the presence of sidebar.top. - if (!kIsWeb && sidebar.topOffset > 0) ...[ - SizedBox(height: sidebar.topOffset), - ] else if (sidebar.top != null) ...[ - const SizedBox(height: 12), - ] else - const SizedBox.shrink(), - if (_sidebarScrollController.hasClients && - _sidebarScrollController.offset > 0.0) - Divider(thickness: 1, height: 1, color: dividerColor), - if (sidebar.top != null && constraints.maxHeight > 81) - Padding( - padding: - const EdgeInsets.symmetric(horizontal: 8.0), - child: sidebar.top!, + if (sidebar.bottom != null && + constraints.maxHeight > 141) + Padding( + padding: const EdgeInsets.all(16.0), + child: sidebar.bottom!, + ), + ], ), - Expanded( - child: MacosScrollbar( - controller: _sidebarScrollController, - child: Padding( - padding: sidebar.padding, - child: sidebar.builder( - context, - _sidebarScrollController, - ), + ) + : TransparentMacOSSidebar( + state: sidebarState, + child: DecoratedBox( + decoration: const BoxDecoration( + color: Color.fromRGBO(0, 0, 0, 1.0), + backgroundBlendMode: BlendMode.clear, + ), + child: Column( + children: [ + // If an app is running on macOS, apply + // sidebar.topOffset as needed in order to avoid + // the traffic lights. Otherwise, position the + // sidebar by the top of the application's bounds + // based on the presence of sidebar.top. + if (!kIsWeb && sidebar.topOffset > 0) ...[ + SizedBox(height: sidebar.topOffset), + ] else if (sidebar.top != null) ...[ + const SizedBox(height: 12), + ] else + const SizedBox.shrink(), + if (_sidebarScrollController.hasClients && + _sidebarScrollController.offset > 0.0) + Divider( + thickness: 1, + height: 1, + color: dividerColor), + if (sidebar.top != null && + constraints.maxHeight > 81) + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + ), + child: sidebar.top!, + ), + Expanded( + child: MacosScrollbar( + controller: _sidebarScrollController, + child: Padding( + padding: sidebar.padding, + child: sidebar.builder( + context, + _sidebarScrollController, + ), + ), + ), + ), + if (sidebar.bottom != null && + constraints.maxHeight > 141) + Padding( + padding: const EdgeInsets.all(16.0), + child: sidebar.bottom!, + ), + ], ), ), ), - if (sidebar.bottom != null && - constraints.maxHeight > 141) - Padding( - padding: const EdgeInsets.all(16.0), - child: sidebar.bottom!, - ), - ], - ), - ), ), ), diff --git a/lib/src/library.dart b/lib/src/library.dart index 2273d447..b42ba8e8 100644 --- a/lib/src/library.dart +++ b/lib/src/library.dart @@ -29,7 +29,7 @@ export 'package:flutter/material.dart' TimeOfDay, DayPeriod, FlexibleSpaceBar, - MaterialState; + WidgetState; export 'package:flutter/widgets.dart'; export 'utils/utils.dart'; diff --git a/lib/src/macos_app.dart b/lib/src/macos_app.dart index 459918fb..1589821e 100644 --- a/lib/src/macos_app.dart +++ b/lib/src/macos_app.dart @@ -310,41 +310,65 @@ class _MacosAppState extends State { widget.routerDelegate != null || widget.routerConfig != null; Widget _macosBuilder(BuildContext context, Widget? child) { - final mode = widget.themeMode ?? ThemeMode.system; - final platformBrightness = MediaQuery.platformBrightnessOf(context); - final useDarkTheme = mode == ThemeMode.dark || - (mode == ThemeMode.system && platformBrightness == Brightness.dark); - - late MacosThemeData theme; - if (useDarkTheme) { - theme = widget.darkTheme ?? MacosThemeData.dark(); - } else { - theme = widget.theme ?? MacosThemeData.light(); - } - - return MacosTheme( - data: theme, - child: DefaultTextStyle( - style: TextStyle(color: theme.typography.body.color), - child: widget.builder != null - // See the MaterialApp source code for the explanation for - // wrapping a builder in a builder - ? Builder( - builder: (context) { - // An Overlay is used here because MacosTooltip needs an - // Overlay as an ancestor in the widget tree. - return Overlay( - initialEntries: [ - OverlayEntry( - builder: (context) => widget.builder!(context, child), - ), - ], - ); - }, - ) - : child ?? const SizedBox.shrink(), - ), - ); + return StreamBuilder( + stream: WindowMainStateListener.instance.onChanged, + builder: (context, _) { + return StreamBuilder( + stream: AccentColorListener.instance.onChanged, + builder: (context, _) { + final mode = widget.themeMode ?? ThemeMode.system; + final platformBrightness = + MediaQuery.platformBrightnessOf(context); + final useDarkTheme = mode == ThemeMode.dark || + (mode == ThemeMode.system && + platformBrightness == Brightness.dark); + + final accentColor = + AccentColorListener.instance.currentAccentColor; + final isMainWindow = + WindowMainStateListener.instance.isMainWindow; + + late MacosThemeData theme; + if (useDarkTheme) { + theme = widget.darkTheme ?? + MacosThemeData.dark( + accentColor: accentColor, + isMainWindow: isMainWindow, + ); + } else { + theme = widget.theme ?? + MacosThemeData.light( + accentColor: accentColor, + isMainWindow: isMainWindow, + ); + } + + return MacosTheme( + data: theme, + child: DefaultTextStyle( + style: TextStyle(color: theme.typography.body.color), + child: widget.builder != null + // See the MaterialApp source code for the explanation for + // wrapping a builder in a builder + ? Builder( + builder: (context) { + // An Overlay is used here because MacosTooltip needs an + // Overlay as an ancestor in the widget tree. + return Overlay( + initialEntries: [ + OverlayEntry( + builder: (context) => + widget.builder!(context, child), + ), + ], + ); + }, + ) + : child ?? const SizedBox.shrink(), + ), + ); + }); + }); } Widget _buildMacosApp(BuildContext context) { diff --git a/lib/src/selectors/date_picker.dart b/lib/src/selectors/date_picker.dart index 2b3cd9b0..25515a7d 100644 --- a/lib/src/selectors/date_picker.dart +++ b/lib/src/selectors/date_picker.dart @@ -21,7 +21,7 @@ enum DatePickerStyle { /// {template onDateChanged} /// The action to perform when a new date is selected. /// {endtemplate} -typedef OnDateChanged = Function(DateTime date); +typedef OnDateChanged = void Function(DateTime date); /// {template macosDatePicker} /// A [MacosDatePicker] lets the user choose a date. diff --git a/lib/src/selectors/time_picker.dart b/lib/src/selectors/time_picker.dart index 815b23d5..47b4bb15 100644 --- a/lib/src/selectors/time_picker.dart +++ b/lib/src/selectors/time_picker.dart @@ -20,8 +20,8 @@ enum TimePickerStyle { /// {template onTimeChanged} /// The action to perform when a new time is selected. -/// {endtemplate} -typedef OnTimeChanged = Function(TimeOfDay time); +/// {end-template} +typedef OnTimeChanged = void Function(TimeOfDay time); /// {template macosTimePicker} /// A [MacosTimePicker] lets the user choose a time. @@ -36,15 +36,21 @@ typedef OnTimeChanged = Function(TimeOfDay time); /// /// The [onTimeChanged] callback passes through the user's selected time, and /// must be provided. -/// {endtemplate} +/// {end-template} class MacosTimePicker extends StatefulWidget { /// {@macro macosTimePicker} const MacosTimePicker({ super.key, required this.onTimeChanged, + this.initialTime, this.style = TimePickerStyle.combined, }); + /// Set an initial date for the picker. + /// + /// Defaults to `TimeOfDay.now()`. + final TimeOfDay? initialTime; + /// The [TimePickerStyle] to use. /// /// Defaults to [TimePickerStyle.combined]. @@ -58,7 +64,7 @@ class MacosTimePicker extends StatefulWidget { } class _MacosTimePickerState extends State { - final _initialTime = TimeOfDay.now(); + late final _initialTime = widget.initialTime ?? TimeOfDay.now(); late int _selectedHour; late int _selectedMinute; late DayPeriod _selectedPeriod; diff --git a/lib/src/theme/macos_theme.dart b/lib/src/theme/macos_theme.dart index 0bda4d11..7b51b3a0 100644 --- a/lib/src/theme/macos_theme.dart +++ b/lib/src/theme/macos_theme.dart @@ -1,3 +1,4 @@ +import 'package:equatable/equatable.dart'; import 'package:flutter/foundation.dart'; import 'package:macos_ui/macos_ui.dart'; import 'package:macos_ui/src/library.dart'; @@ -178,7 +179,7 @@ class _InheritedMacosTheme extends InheritedWidget { /// See also: /// /// * [MacosTheme], in which this [MacosThemeData] is inserted. -class MacosThemeData with Diagnosticable { +class MacosThemeData extends Equatable with Diagnosticable { /// Creates a [MacosThemeData] that's used to configure [MacosTheme]. /// /// The [typography] [TextStyle] colors are black if the [brightness] @@ -188,8 +189,8 @@ class MacosThemeData with Diagnosticable { /// /// See also: /// - /// * [MacosThemeData.light], which creates a light blue theme. - /// * [MacosThemeData.dark], which creates a dark blue theme. + /// * [MacosThemeData.light], which creates a light theme. + /// * [MacosThemeData.dark], which creates a dark theme. factory MacosThemeData({ Brightness? brightness, Color? primaryColor, @@ -208,11 +209,17 @@ class MacosThemeData with Diagnosticable { MacosDatePickerThemeData? datePickerTheme, MacosTimePickerThemeData? timePickerTheme, MacosSearchFieldThemeData? searchFieldTheme, + AccentColor? accentColor, + bool? isMainWindow, }) { // ignore: no_leading_underscores_for_local_identifiers final Brightness _brightness = brightness ?? Brightness.light; final bool isDark = _brightness == Brightness.dark; - primaryColor ??= MacosColors.controlAccentColor; + primaryColor ??= _ColorProvider.getPrimaryColor( + accentColor: accentColor ?? AccentColor.blue, + isDarkModeEnabled: isDark, + isWindowMain: isMainWindow ?? true, + ); canvasColor ??= isDark ? const Color.fromRGBO(40, 40, 40, 1.0) @@ -265,16 +272,20 @@ class MacosThemeData with Diagnosticable { visualDensity ??= VisualDensity.adaptivePlatformDensity; iconTheme ??= MacosIconThemeData( - color: isDark - ? CupertinoColors.activeBlue.darkColor - : CupertinoColors.activeBlue.color, + color: _ColorProvider.getActiveColor( + accentColor: accentColor ?? AccentColor.blue, + isDarkModeEnabled: isDark, + isWindowMain: isMainWindow ?? true, + ), size: 20, ); popupButtonTheme ??= MacosPopupButtonThemeData( - highlightColor: isDark - ? CupertinoColors.activeBlue.darkColor - : CupertinoColors.activeBlue.color, + highlightColor: _ColorProvider.getActiveColor( + accentColor: accentColor ?? AccentColor.blue, + isDarkModeEnabled: isDark, + isWindowMain: isMainWindow ?? true, + ), backgroundColor: isDark ? const Color.fromRGBO(255, 255, 255, 0.247) : const Color.fromRGBO(255, 255, 255, 1), @@ -284,9 +295,11 @@ class MacosThemeData with Diagnosticable { ); pulldownButtonTheme ??= MacosPulldownButtonThemeData( - highlightColor: isDark - ? CupertinoColors.activeBlue.darkColor - : CupertinoColors.activeBlue.color, + highlightColor: _ColorProvider.getActiveColor( + accentColor: accentColor ?? AccentColor.blue, + isDarkModeEnabled: isDark, + isWindowMain: isMainWindow ?? true, + ), backgroundColor: isDark ? const Color.fromRGBO(255, 255, 255, 0.247) : const Color.fromRGBO(255, 255, 255, 1), @@ -354,9 +367,11 @@ class MacosThemeData with Diagnosticable { ); searchFieldTheme ??= MacosSearchFieldThemeData( - highlightColor: isDark - ? CupertinoColors.activeBlue.darkColor - : CupertinoColors.activeBlue.color, + highlightColor: _ColorProvider.getActiveColor( + accentColor: accentColor ?? AccentColor.blue, + isDarkModeEnabled: isDark, + isWindowMain: isMainWindow ?? true, + ), resultsBackgroundColor: isDark ? const Color.fromRGBO(30, 30, 30, 1) : const Color.fromRGBO(242, 242, 247, 1), @@ -380,6 +395,8 @@ class MacosThemeData with Diagnosticable { datePickerTheme: datePickerTheme, timePickerTheme: timePickerTheme, searchFieldTheme: searchFieldTheme, + accentColor: accentColor, + isMainWindow: isMainWindow, ); final customizedData = defaultData.copyWith( @@ -399,6 +416,8 @@ class MacosThemeData with Diagnosticable { pulldownButtonTheme: pulldownButtonTheme, datePickerTheme: datePickerTheme, searchFieldTheme: searchFieldTheme, + accentColor: accentColor, + isMainWindow: isMainWindow, ); return defaultData.merge(customizedData); @@ -428,14 +447,31 @@ class MacosThemeData with Diagnosticable { required this.datePickerTheme, required this.timePickerTheme, required this.searchFieldTheme, + required this.accentColor, + required this.isMainWindow, }); /// A default light theme. - factory MacosThemeData.light() => - MacosThemeData(brightness: Brightness.light); + factory MacosThemeData.light({ + AccentColor? accentColor, + bool? isMainWindow, + }) => + MacosThemeData( + brightness: Brightness.light, + accentColor: accentColor, + isMainWindow: isMainWindow, + ); /// A default dark theme. - factory MacosThemeData.dark() => MacosThemeData(brightness: Brightness.dark); + factory MacosThemeData.dark({ + AccentColor? accentColor, + bool? isMainWindow, + }) => + MacosThemeData( + brightness: Brightness.dark, + accentColor: accentColor, + isMainWindow: isMainWindow, + ); /// The default color theme. Same as [ThemeData.light]. /// @@ -504,6 +540,13 @@ class MacosThemeData with Diagnosticable { /// The default style for [MacosSearchField]s below the overall [MacosTheme] final MacosSearchFieldThemeData searchFieldTheme; + /// The accent color to use for the application. + final AccentColor? accentColor; + + /// Whether the app is running in the main (i.e., the currently active) + /// window. + final bool? isMainWindow; + /// Linearly interpolate between two themes. static MacosThemeData lerp(MacosThemeData a, MacosThemeData b, double t) { return MacosThemeData.raw( @@ -551,6 +594,8 @@ class MacosThemeData with Diagnosticable { b.searchFieldTheme, t, ), + accentColor: t < 0.5 ? a.accentColor : b.accentColor, + isMainWindow: t < 0.5 ? a.isMainWindow : b.isMainWindow, ); } @@ -573,6 +618,8 @@ class MacosThemeData with Diagnosticable { MacosDatePickerThemeData? datePickerTheme, MacosTimePickerThemeData? timePickerTheme, MacosSearchFieldThemeData? searchFieldTheme, + AccentColor? accentColor, + bool? isMainWindow, }) { return MacosThemeData.raw( brightness: brightness ?? this.brightness, @@ -592,6 +639,8 @@ class MacosThemeData with Diagnosticable { datePickerTheme: this.datePickerTheme.merge(datePickerTheme), timePickerTheme: this.timePickerTheme.merge(timePickerTheme), searchFieldTheme: this.searchFieldTheme.merge(searchFieldTheme), + accentColor: accentColor ?? this.accentColor, + isMainWindow: isMainWindow ?? this.isMainWindow, ); } @@ -616,6 +665,8 @@ class MacosThemeData with Diagnosticable { datePickerTheme: datePickerTheme.merge(other.datePickerTheme), timePickerTheme: timePickerTheme.merge(other.timePickerTheme), searchFieldTheme: searchFieldTheme.merge(other.searchFieldTheme), + accentColor: other.accentColor, + isMainWindow: other.isMainWindow, ); } @@ -681,7 +732,42 @@ class MacosThemeData with Diagnosticable { searchFieldTheme, ), ); + properties.add( + DiagnosticsProperty( + 'accentColor', + accentColor, + ), + ); + properties.add( + DiagnosticsProperty( + 'isMainWindow', + isMainWindow, + ), + ); } + + @override + List get props => [ + brightness, + primaryColor, + canvasColor, + typography, + pushButtonTheme, + dividerColor, + helpButtonTheme, + tooltipTheme, + visualDensity, + scrollbarTheme, + iconButtonTheme, + iconTheme, + popupButtonTheme, + pulldownButtonTheme, + datePickerTheme, + timePickerTheme, + searchFieldTheme, + accentColor, + isMainWindow, + ]; } /// Brightness extensions @@ -695,3 +781,145 @@ extension BrightnessX on Brightness { return light; } } + +class _ColorProvider { + _ColorProvider._(); + + /// Returns the primary color based on the provided parameters. + static Color getPrimaryColor({ + required AccentColor accentColor, + required bool isDarkModeEnabled, + required bool isWindowMain, + }) { + if (isDarkModeEnabled) { + if (!isWindowMain) { + return const MacosColor.fromRGBO(100, 100, 100, 0.625); + } + + switch (accentColor) { + case AccentColor.blue: + return const MacosColor.fromRGBO(29, 151, 255, 1.0); + + case AccentColor.purple: + return const MacosColor.fromRGBO(204, 118, 207, 1.0); + + case AccentColor.pink: + return const MacosColor.fromRGBO(255, 114, 194, 1.0); + + case AccentColor.red: + return const MacosColor.fromRGBO(225, 118, 124, 1.0); + + case AccentColor.orange: + return const MacosColor.fromRGBO(255, 147, 44, 1.0); + + case AccentColor.yellow: + return const MacosColor.fromRGBO(255, 220, 24, 1.0); + + case AccentColor.green: + return const MacosColor.fromRGBO(114, 202, 87, 1.0); + + case AccentColor.graphite: + return const MacosColor.fromRGBO(152, 152, 152, 1.0); + } + } + + if (!isWindowMain) { + return const MacosColor.fromRGBO(190, 190, 190, 1.0); + } + + switch (accentColor) { + case AccentColor.blue: + return const MacosColor.fromRGBO(0, 88, 224, 1.0); + + case AccentColor.purple: + return const MacosColor.fromRGBO(131, 44, 134, 1.0); + + case AccentColor.pink: + return const MacosColor.fromRGBO(212, 45, 126, 1.0); + + case AccentColor.red: + return const MacosColor.fromRGBO(203, 45, 43, 1.0); + + case AccentColor.orange: + return const MacosColor.fromRGBO(198, 82, 0, 1.0); + + case AccentColor.yellow: + return const MacosColor.fromRGBO(206, 154, 2, 1.0); + + case AccentColor.green: + return const MacosColor.fromRGBO(56, 146, 30, 1.0); + + case AccentColor.graphite: + return const MacosColor.fromRGBO(100, 100, 100, 1.0); + } + } + + /// Returns the active color based on the provided parameters. + static Color getActiveColor({ + required AccentColor accentColor, + required bool isDarkModeEnabled, + required bool isWindowMain, + }) { + if (isDarkModeEnabled) { + if (!isWindowMain) { + return const MacosColor.fromRGBO(76, 78, 65, 1.0); + } + + switch (accentColor) { + case AccentColor.blue: + return const MacosColor.fromRGBO(22, 105, 229, 0.749); + + case AccentColor.purple: + return const MacosColor.fromRGBO(204, 45, 202, 0.749); + + case AccentColor.pink: + return const MacosColor.fromRGBO(229, 74, 145, 0.749); + + case AccentColor.red: + return const MacosColor.fromRGBO(238, 64, 68, 0.749); + + case AccentColor.orange: + return const MacosColor.fromRGBO(244, 114, 0, 0.749); + + case AccentColor.yellow: + return const MacosColor.fromRGBO(233, 176, 0, 0.749); + + case AccentColor.green: + return const MacosColor.fromRGBO(76, 177, 45, 0.749); + + case AccentColor.graphite: + return const MacosColor.fromRGBO(129, 129, 122, 0.824); + } + } + + if (!isWindowMain) { + return const MacosColor.fromRGBO(180, 180, 180, 1.0); + } + + switch (accentColor) { + case AccentColor.blue: + return const MacosColor.fromRGBO(9, 129, 255, 0.749); + + case AccentColor.purple: + return const MacosColor.fromRGBO(162, 28, 165, 0.749); + + case AccentColor.pink: + return const MacosColor.fromRGBO(234, 81, 152, 0.749); + + case AccentColor.red: + return const MacosColor.fromRGBO(220, 32, 40, 0.749); + + case AccentColor.orange: + return const MacosColor.fromRGBO(245, 113, 0, 0.749); + + case AccentColor.yellow: + return const MacosColor.fromRGBO(240, 180, 2, 0.749); + + case AccentColor.green: + return const MacosColor.fromRGBO(66, 174, 33, 0.749); + + case AccentColor.graphite: + return const MacosColor.fromRGBO(174, 174, 167, 0.847); + } + } +} diff --git a/lib/src/theme/typography.dart b/lib/src/theme/typography.dart index 7b2f72a7..462e332e 100644 --- a/lib/src/theme/typography.dart +++ b/lib/src/theme/typography.dart @@ -1,3 +1,4 @@ +import 'package:equatable/equatable.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:macos_ui/src/theme/macos_colors.dart'; @@ -15,7 +16,7 @@ const _kDefaultFontFamily = '.AppleSystemUIFont'; /// * [MacosTheme], for aspects of a macos application that can be globally /// adjusted, such as the primary color. /// * -class MacosTypography with Diagnosticable { +class MacosTypography extends Equatable with Diagnosticable { /// Creates a typography that uses the given values. /// /// Rather than creating a new typography, consider using [MacosTypography.darkOpaque] @@ -297,6 +298,21 @@ class MacosTypography with Diagnosticable { defaultValue: defaultStyle.caption2, )); } + + @override + List get props => [ + body, + callout, + caption1, + caption2, + footnote, + headline, + largeTitle, + subheadline, + title1, + title2, + title3, + ]; } /// The thickness of the glyphs used to draw the text. diff --git a/pubspec.lock b/pubspec.lock index 62a3f534..cf35ae3d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,22 +1,6 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a - url: "https://pub.dev" - source: hosted - version: "61.0.0" - analyzer: - dependency: transitive - description: - name: analyzer - sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 - url: "https://pub.dev" - source: hosted - version: "5.13.0" appkit_ui_element_colors: dependency: "direct main" description: @@ -25,14 +9,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" - args: - dependency: transitive - description: - name: args - sha256: c372bb384f273f0c2a8aaaa226dad84dc27c8519a691b888725dec59518ad53a - url: "https://pub.dev" - source: hosted - version: "2.4.1" async: dependency: transitive description: @@ -69,36 +45,12 @@ packages: dependency: transitive description: name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 - url: "https://pub.dev" - source: hosted - version: "1.17.2" - convert: - dependency: transitive - description: - name: convert - sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" - url: "https://pub.dev" - source: hosted - version: "3.1.1" - coverage: - dependency: transitive - description: - name: coverage - sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097" + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.6.3" - crypto: - dependency: transitive - description: - name: crypto - sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab - url: "https://pub.dev" - source: hosted - version: "3.0.3" + version: "1.18.0" equatable: - dependency: transitive + dependency: "direct main" description: name: equatable sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 @@ -113,14 +65,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" - file: - dependency: transitive - description: - name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" - url: "https://pub.dev" - source: hosted - version: "6.1.4" flutter: dependency: "direct main" description: flutter @@ -130,236 +74,116 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4" + sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" url: "https://pub.dev" source: hosted - version: "2.0.2" + version: "4.0.0" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" - url: "https://pub.dev" - source: hosted - version: "3.2.0" - glob: - dependency: transitive - description: - name: glob - sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c" - url: "https://pub.dev" - source: hosted - version: "2.1.1" gradient_borders: dependency: "direct main" description: name: gradient_borders - sha256: "69eeaff519d145a4c6c213ada1abae386bcc8981a4970d923e478ce7ba19e309" + sha256: b1cd969552c83f458ff755aa68e13a0327d09f06c3f42f471b423b01427f21f8 url: "https://pub.dev" source: hosted - version: "1.0.0" - http_multi_server: + version: "1.0.1" + leak_tracker: dependency: transitive description: - name: http_multi_server - sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + name: leak_tracker + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "3.2.1" - http_parser: + version: "10.0.5" + leak_tracker_flutter_testing: dependency: transitive description: - name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + name: leak_tracker_flutter_testing + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "4.0.2" - io: + version: "3.0.5" + leak_tracker_testing: dependency: transitive description: - name: io - sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "1.0.4" - js: - dependency: transitive - description: - name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 - url: "https://pub.dev" - source: hosted - version: "0.6.7" + version: "3.0.1" lints: dependency: transitive description: name: lints - sha256: "6b0206b0bf4f04961fc5438198ccb3a885685cd67d4d4a32cc20ad7f8adbe015" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - logging: - dependency: transitive - description: - name: logging - sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d" + sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "4.0.0" macos_window_utils: dependency: "direct main" description: name: macos_window_utils - sha256: "43a90473f8786f00f07203e6819dab67e032f8896dafa4a6f85fbc71fba32c0b" + sha256: "230be594d26f6dee92c5a1544f4242d25138a5bfb9f185b27f14de3949ef0be8" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.5.0" matcher: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.9.1" - mime: - dependency: transitive - description: - name: mime - sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e - url: "https://pub.dev" - source: hosted - version: "1.0.4" + version: "1.15.0" mocktail: dependency: "direct dev" description: name: mocktail - sha256: "80a996cd9a69284b3dc521ce185ffe9150cde69767c2d3a0720147d93c0cef53" - url: "https://pub.dev" - source: hosted - version: "0.3.0" - node_preamble: - dependency: transitive - description: - name: node_preamble - sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" - url: "https://pub.dev" - source: hosted - version: "2.0.2" - package_config: - dependency: transitive - description: - name: package_config - sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + sha256: "890df3f9688106f25755f26b1c60589a92b3ab91a22b8b224947ad041bf172d8" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "1.0.4" path: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - sha256: "43798d895c929056255600343db8f049921cbec94d31ec87f1dc5c16c01935dd" - url: "https://pub.dev" - source: hosted - version: "2.1.5" - pool: - dependency: transitive - description: - name: pool - sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" - url: "https://pub.dev" - source: hosted - version: "1.5.1" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - shelf: - dependency: transitive - description: - name: shelf - sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 - url: "https://pub.dev" - source: hosted - version: "1.4.1" - shelf_packages_handler: - dependency: transitive - description: - name: shelf_packages_handler - sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - shelf_static: - dependency: transitive - description: - name: shelf_static - sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted - version: "1.1.2" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" - url: "https://pub.dev" - source: hosted - version: "1.0.4" + version: "2.1.8" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" - source_map_stack_trace: - dependency: transitive - description: - name: source_map_stack_trace - sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - source_maps: - dependency: transitive - description: - name: source_maps - sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" - url: "https://pub.dev" - source: hosted - version: "0.10.12" source_span: dependency: transitive description: @@ -372,18 +196,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -400,38 +224,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.1" - test: - dependency: transitive - description: - name: test - sha256: "13b41f318e2a5751c3169137103b60c584297353d4b1761b66029bae6411fe46" - url: "https://pub.dev" - source: hosted - version: "1.24.3" test_api: dependency: transitive description: name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.6.0" - test_core: - dependency: transitive - description: - name: test_core - sha256: "99806e9e6d95c7b059b7a0fc08f07fc53fabe54a829497f0d9676299f1e8637e" - url: "https://pub.dev" - source: hosted - version: "0.5.3" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c - url: "https://pub.dev" - source: hosted - version: "1.3.2" + version: "0.7.2" vector_math: dependency: transitive description: @@ -444,50 +244,10 @@ packages: dependency: transitive description: name: vm_service - sha256: f3743ca475e0c9ef71df4ba15eb2d7684eecd5c8ba20a462462e4e8b561b2e11 - url: "https://pub.dev" - source: hosted - version: "11.6.0" - watcher: - dependency: transitive - description: - name: watcher - sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - web: - dependency: transitive - description: - name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 - url: "https://pub.dev" - source: hosted - version: "0.1.4-beta" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b - url: "https://pub.dev" - source: hosted - version: "2.4.0" - webkit_inspection_protocol: - dependency: transitive - description: - name: webkit_inspection_protocol - sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - yaml: - dependency: transitive - description: - name: yaml - sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "14.2.5" sdks: - dart: ">=3.1.0-185.0.dev <4.0.0" - flutter: ">=3.10.0" + dart: ">=3.5.3 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/pubspec.yaml b/pubspec.yaml index 8d81c2da..ca5712a3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,25 +1,25 @@ name: macos_ui description: Flutter widgets and themes implementing the current macOS design language. -version: 2.0.2 +version: 2.1.0 homepage: "https://macosui.dev" repository: "https://github.com/GroovinChip/macos_ui" environment: - sdk: ">=3.0.0 <4.0.0" - flutter: ">=3.10.0" + sdk: ">=3.5.3 <4.0.0" dependencies: flutter: sdk: flutter - macos_window_utils: ^1.2.0 - gradient_borders: ^1.0.0 + macos_window_utils: ^1.5.0 + gradient_borders: ^1.0.1 appkit_ui_element_colors: ^1.0.0 + equatable: ^2.0.5 dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^2.0.2 - mocktail: ^0.3.0 + flutter_lints: ^4.0.0 + mocktail: ^1.0.4 flutter: plugin: diff --git a/test/src/theme/macos_theme_test.dart b/test/src/theme/macos_theme_test.dart new file mode 100644 index 00000000..92df987c --- /dev/null +++ b/test/src/theme/macos_theme_test.dart @@ -0,0 +1,49 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:macos_ui/src/library.dart'; +import 'package:macos_ui/src/theme/help_button_theme.dart'; +import 'package:macos_ui/src/theme/macos_colors.dart'; +import 'package:macos_ui/src/theme/macos_theme.dart'; + +void main() { + testWidgets('macos theme MacosThemeData equality 1', (tester) async { + final macosThemeData1 = MacosThemeData(); + final macosThemeData2 = MacosThemeData(); + + expect(macosThemeData1, equals(macosThemeData2)); + }); + + testWidgets('macos theme MacosThemeData equality 2', (tester) async { + final macosThemeData1 = MacosThemeData(brightness: Brightness.dark); + final macosThemeData2 = MacosThemeData(brightness: Brightness.light); + + expect(macosThemeData1, isNot(equals(macosThemeData2))); + }); + + testWidgets('macos theme MacosThemeData equality 3', (tester) async { + final macosThemeData1 = MacosThemeData( + helpButtonTheme: const HelpButtonThemeData( + color: MacosColors.appleRed, + )); + + final macosThemeData2 = MacosThemeData( + helpButtonTheme: const HelpButtonThemeData( + color: MacosColors.appleGreen, + )); + + expect(macosThemeData1, isNot(equals(macosThemeData2))); + }); + + testWidgets('macos theme MacosThemeData equality 4', (tester) async { + final macosThemeData1 = MacosThemeData( + helpButtonTheme: const HelpButtonThemeData( + color: MacosColors.appleRed, + )); + + final macosThemeData2 = MacosThemeData( + helpButtonTheme: const HelpButtonThemeData( + color: MacosColors.appleRed, + )); + + expect(macosThemeData1, equals(macosThemeData2)); + }); +} diff --git a/test/src/theme/typography_test.dart b/test/src/theme/typography_test.dart new file mode 100644 index 00000000..9524a6d2 --- /dev/null +++ b/test/src/theme/typography_test.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('typography equality 1', (tester) async { + final typography1 = Typography(); + final typography2 = Typography(); + + expect(typography1, equals(typography2)); + }); + + testWidgets('typography equality 2', (tester) async { + final typography1 = Typography( + black: const TextTheme(bodyLarge: TextStyle(fontSize: 10)), + ); + final typography2 = Typography( + black: const TextTheme(bodyLarge: TextStyle(fontSize: 12)), + ); + + expect(typography1, isNot(equals(typography2))); + }); + + testWidgets('typography equality 3', (tester) async { + final typography1 = Typography( + englishLike: const TextTheme( + bodyLarge: TextStyle(fontSize: 10), + ), + ); + final typography2 = Typography( + englishLike: const TextTheme( + bodyLarge: TextStyle(fontSize: 10), + ), + ); + + expect(typography1, equals(typography2)); + }); + + testWidgets('typography equality 4', (tester) async { + final typography1 = Typography( + englishLike: const TextTheme( + bodyLarge: TextStyle(fontSize: 10), + ), + ); + final typography2 = Typography( + englishLike: const TextTheme( + bodyLarge: TextStyle(fontSize: 12), + ), + ); + + expect(typography1, isNot(equals(typography2))); + }); + + testWidgets('typography equality 5', (tester) async { + final typography1 = Typography( + englishLike: const TextTheme( + headlineLarge: TextStyle(fontSize: 10), + ), + ); + final typography2 = Typography( + englishLike: const TextTheme( + headlineLarge: TextStyle(fontSize: 12), + ), + ); + + expect(typography1, isNot(equals(typography2))); + }); + + testWidgets('typography equality 6', (tester) async { + final typography1 = Typography( + englishLike: const TextTheme( + headlineLarge: TextStyle(fontSize: 10), + ), + ); + final typography2 = Typography( + englishLike: const TextTheme( + headlineLarge: TextStyle(fontSize: 10), + ), + ); + + expect(typography1, equals(typography2)); + }); +} diff --git a/test/theme/icon_theme_test.dart b/test/theme/icon_theme_test.dart index 79076b18..7efe67fa 100644 --- a/test/theme/icon_theme_test.dart +++ b/test/theme/icon_theme_test.dart @@ -81,7 +81,7 @@ void main() { ); final theme = MacosIconTheme.of(capturedContext); - expect(theme.color, CupertinoColors.activeBlue.color); + expect(theme.color, const MacosColor(0xbe0981ff)); expect(theme.size, 20); }); } diff --git a/test/theme/popup_button_theme_test.dart b/test/theme/popup_button_theme_test.dart index 7cbe6b7a..f704da09 100644 --- a/test/theme/popup_button_theme_test.dart +++ b/test/theme/popup_button_theme_test.dart @@ -96,7 +96,7 @@ void main() { final theme = MacosPopupButtonTheme.of(capturedContext); expect(theme.backgroundColor, const Color(0xffffffff)); - expect(theme.highlightColor, const Color(0xff007aff)); + expect(theme.highlightColor, const MacosColor(0xbe0981ff)); expect(theme.popupColor, const Color(0xfff2f2f7)); }); }); diff --git a/test/theme/pulldown_button_theme_test.dart b/test/theme/pulldown_button_theme_test.dart index 87fc9666..a082b42e 100644 --- a/test/theme/pulldown_button_theme_test.dart +++ b/test/theme/pulldown_button_theme_test.dart @@ -97,7 +97,7 @@ void main() { final theme = MacosPulldownButtonTheme.of(capturedContext); expect(theme.backgroundColor, const Color(0xffffffff)); - expect(theme.highlightColor, const Color(0xff007aff)); + expect(theme.highlightColor, const MacosColor(0xbe0981ff)); expect(theme.pulldownColor, const Color(0xfff2f2f7)); }); }); diff --git a/test/theme/search_field_theme_test.dart b/test/theme/search_field_theme_test.dart index 6f0851b9..39aa577f 100644 --- a/test/theme/search_field_theme_test.dart +++ b/test/theme/search_field_theme_test.dart @@ -80,7 +80,7 @@ void main() { ); final theme = MacosSearchFieldTheme.of(capturedContext); - expect(theme.highlightColor, const Color(0xff007aff)); + expect(theme.highlightColor, const MacosColor(0xbe0981ff)); expect(theme.resultsBackgroundColor, const Color(0xfff2f2f7)); }); });