diff --git a/.github/workflows/dart_code_metrics.yaml b/.github/workflows/dart_code_metrics.yaml deleted file mode 100644 index 03336a6a..00000000 --- a/.github/workflows/dart_code_metrics.yaml +++ /dev/null @@ -1,22 +0,0 @@ -name: Dart Code Metrics -on: [pull_request, workflow_dispatch] - -jobs: - dart-code-metrics: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - name: Install Flutter - uses: subosito/flutter-action@v2 - with: - channel: stable - - - name: Set Up DCM - run: flutter pub get - - uses: CQLabs/setup-dcm@v1.0.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - - - run: dcm analyze --ci-key="${{ secrets.DCM_CI_KEY }}" --email="${{ secrets.DCM_EMAIL }}" lib diff --git a/.github/workflows/flutter_analysis.yml b/.github/workflows/flutter_analysis.yml index fba04aa4..5612680f 100644 --- a/.github/workflows/flutter_analysis.yml +++ b/.github/workflows/flutter_analysis.yml @@ -34,3 +34,11 @@ jobs: - name: Analyze code run: flutter analyze --fatal-infos . + + - name: Install DCM + uses: CQLabs/setup-dcm@v2 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Run DCM + run: dcm analyze . diff --git a/.gitignore b/.gitignore index 144640c7..ae5694f1 100644 --- a/.gitignore +++ b/.gitignore @@ -82,3 +82,7 @@ coverage_report coverage example/macos/Flutter/GeneratedPluginRegistrant.swift example/devtools_options.yaml + +# Swift package manager +.build/ +.swiftpm/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d87d8aa..10816f76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,75 @@ +## [2.2.2] +### ๐Ÿ›  Fixed ๐Ÿ›  +- Fixed setState called after dispose issue in MacosPulldownButton. + +## [2.2.1] +### ๐Ÿ”„ Updated ๐Ÿ”„ +* Wrap toolbar items with `MacosToolbarPassthrough` to prevent window move or resize when interacting with toolbar items. + +## [2.2.0+3] +* Address DCM lints: + * Prefer `const BorderRadius.all` + * Sort private members + +## [2.2.0+2] +* Formatter updates + +## [2.2.0+1] +* Support Dart 3.9.2 +* Update dependencies +* Address lints + +## [2.2.0] +### โœจ New โœจ +* Add support for Swift package manager. + +## [2.1.10] +### ๐Ÿ”„ Updated ๐Ÿ”„ +* Make text field cursor color follow the userโ€™s accent color if not explicitly set (thanks, [@driftwoodstudio](https://github.com/driftwoodstudio)). +* Expose the `AccentColorListener` class to macos_ui users. + +## [2.1.9] +### ๐Ÿ› ๏ธ Fixed ๐Ÿ› ๏ธ +* Fix incorrect highlighting and focusing behavior of `_MacosPopupMenuItemButton`. +* Remove scrolling animation from dropdown menus when manipulating the focus with the keyboard to mimic native macOS behavior. + +## [2.1.8] +### ๐Ÿ› ๏ธ Fixed ๐Ÿ› ๏ธ +* Fixed `shownByDefault` not being respected for the left sidebar of the `MacosWindow` (thanks, [@ShayperCool](https://github.com/ShayperCool)). + +## [2.1.7] +### ๐Ÿ”„ Updated ๐Ÿ”„ +* Expose `WindowMainStateListener` and implement `overrideIsMainWindow` method to allow for the windowโ€™s main state to be overridden. + +## [2.1.6] +### ๐Ÿ”„ Updated ๐Ÿ”„ +* add `section` parameter to `SidebarItem` to display an unclickable widget in the sidebar as a section header (thanks, [@whirlun](https://github.com/whirlun)). +* Fix incorrect barrier color when calling `showMacosSheet` when dark mode is enabled. + +## [2.1.5] +### ๐Ÿ›ป Migrated ๐Ÿ›ป +* Migrate to Flutterโ€™s new Color API. + +## [2.1.4] +### ๐Ÿ› ๏ธ Fixed ๐Ÿ› ๏ธ +* Fix incorrect barrier color when calling `showMacosAlertDialog` when dark mode is enabled. + +## [2.1.3] +### ๐Ÿ› ๏ธ Fixed ๐Ÿ› ๏ธ +* Fix `ToolbarOverflowButton` only reacting to every second click. + +## [2.1.2] +### ๐Ÿ› ๏ธ Updated ๐Ÿ› ๏ธ +* Add โ€œOlder macOS versionsโ€ section to README +* Add Flutter version constraints to prevent the following error: + ``` + Package validation found the following error: + * pubspec.yaml allows Flutter SDK version 1.9.x, which does not support the flutter.plugin.platforms key. + Please consider increasing the Flutter SDK requirement to ^1.10.0 (environment.sdk.flutter) + ``` +## [2.1.1] +* Fixed a bug where `MacosPulldownMenuItem` would not show an alert dialog when tapped. + ## [2.1.0] * Updated dependencies * Support macOS 15 diff --git a/README.md b/README.md index 23a54c9a..5e8271f6 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Guides, codelabs, and other documentation can be found at https://macosui.dev ### Flutter channel `macos_ui` is developed against Flutter's `stable` channel. To ensure a smooth development experience with `macos_ui`, you should build your application on Flutter's `stable` channel. -### Platform Compatibility +### ๐Ÿ–ฅ๏ธ Platform Compatibility pub.dev shows that `macos_ui` only supports macOS. This is because `macos_ui` calls some native code, and therefore specifies macOS as a plugin platform in the `pubspec.yaml` file. @@ -33,6 +33,12 @@ The features of `macos_ui` that will _not_ work on platforms other than macOS du * The `MacosColors.controlAccentColor()` function * The `MacosColorWell` widget +### Flutter Compatibility + +Starting with version `2.2.0+1`, `macos_ui` requires Flutter `3.35.0` or higher due to a depredation in Flutter 3.35.0. If you use an older Flutter version along with `macos_ui` version `2.2.0+1`, only version `2.2.0` will be available to you when you run `flutter pub get`. + +**We therefore strongly recommend that you use Flutter `3.35.0` or higher if developing with `macos_ui` so that you gain access to the latest features and fixes.** + ### Popups & window resizing Since at this time Flutter does not allow UI elements to overflow the bounds of the window, popups are constrained to @@ -124,6 +130,12 @@ should avoid allowing your application window to be resized below the height of - [MacosColorWell](#macoscolorwell) +
+Older macOS versions + +- [Older macOS versions](#older-macos-versions) +
+ --- ## Contributing @@ -224,7 +236,9 @@ See the documentation for customizations and `ToolBar` examples. ## Modern window look -A new look for macOS apps was introduced in Big Sur (macOS 11). To match that look in your Flutter app, macos_ui relies on [macos_window_utils](https://pub.dev/packages/macos_window_utils), which requires a minimum macOS deployment target of 10.14.6. Therefore, make sure to open the `macos/Runner.xcworkspace` folder of your project using Xcode and search for `Runner.xcodeproj`. Go to `Info` > `Deployment Target` and set the `macOS Deployment Target` to `10.14.6` or above. Then, open your project's `Podfile` (if it doesn't show up in Xcode, you can find it in your project's `macos` directory via VS Code) and set the minimum deployment version in the first line to `10.14.6` or above: +A new look for macOS apps was introduced in Big Sur (macOS 11). To match that look in your Flutter app, macos_ui relies on [macos_window_utils](https://pub.dev/packages/macos_window_utils), which requires a minimum macOS deployment target of 10.14.6. Therefore, make sure to open the `macos/Runner.xcworkspace` folder of your project using Xcode and search for `Runner.xcodeproj`. Go to `Info` > `Deployment Target` and set the `macOS Deployment Target` to `10.14.6` or above. + +It is recommended to enable the Swift Package Manager when using macos_ui. Instructions on how to do that can be found [here](https://docs.flutter.dev/packages-and-plugins/swift-package-manager/for-app-developers#how-to-turn-on-swift-package-manager). Alternatively, macos_ui can also be used with CocoaPods. To do so, it is necessary to open your project's `Podfile` (if it doesn't show up in Xcode, you can find it in your project's `macos` directory via VS Code) and set the minimum deployment version in the first line to `10.14.6` or above: ```podspec platform :osx, '10.14.6' @@ -472,8 +486,8 @@ A checkbox is a type of button that lets the user choose between two opposite st checkbox is considered on when it contains a checkmark and off when it's empty. A checkbox is almost always followed by a title unless it appears in a checklist. [Learn more](https://developer.apple.com/design/human-interface-guidelines/macos/buttons/checkboxes/) -| Unchecked | Checked | Mixed | -| --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------ | +| Unchecked | Checked | Mixed | +| ---------------------------------------------------- | -------------------------------------------------- | ------------------------------------------------ | | ![Unchecked Checkbox](https://imgur.com/Pu4EDAE.png) | ![Checked Checkbox](https://imgur.com/CB3Kmwo.png) | ![Mixed Checkbox](https://imgur.com/T44rV38.png) | Here's an example of how to create a basic checkbox: @@ -1012,3 +1026,55 @@ MacosColorWell( onColorSelected: (color) => debugPrint('$color'), ), ``` + +## Older macOS versions + +If youโ€™re targeting older macOS versions (Monterey and earlier), it is necessary to perform the following steps to make the [macos_window_utils](https://pub.dev/packages/macos_window_utils) plugin, which macos_ui depends on, work correctly: + +Open the `macos/Runner.xcworkspace` folder of your project using Xcode, press โ‡ง + โŒ˜ + O and search for `MainFlutterWindow.swift`. + +Insert `import macos_window_utils` at the top of the file. +Then, replace the code above the `super.awakeFromNib()`-line with the following code: + +```swift +let windowFrame = self.frame +let macOSWindowUtilsViewController = MacOSWindowUtilsViewController() +self.contentViewController = macOSWindowUtilsViewController +self.setFrame(windowFrame, display: true) + +/* Initialize the macos_window_utils plugin */ +MainFlutterWindowManipulator.start(mainFlutterWindow: self) + +RegisterGeneratedPlugins(registry: macOSWindowUtilsViewController.flutterViewController) +``` + +Assuming you're starting with the default configuration, the finished code should look something like this: + +```diff +import Cocoa +import FlutterMacOS ++import macos_window_utils + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { +- let flutterViewController = FlutterViewController.init() +- let windowFrame = self.frame +- self.contentViewController = flutterViewController +- self.setFrame(windowFrame, display: true) + +- RegisterGeneratedPlugins(registry: flutterViewController) + ++ let windowFrame = self.frame ++ let macOSWindowUtilsViewController = MacOSWindowUtilsViewController() ++ self.contentViewController = macOSWindowUtilsViewController ++ self.setFrame(windowFrame, display: true) + ++ /* Initialize the macos_window_utils plugin */ ++ MainFlutterWindowManipulator.start(mainFlutterWindow: self) + ++ RegisterGeneratedPlugins(registry: macOSWindowUtilsViewController.flutterViewController) + + super.awakeFromNib() + } +} +``` \ No newline at end of file diff --git a/example/ios/.gitignore b/example/ios/.gitignore index e96ef602..cd653048 100644 --- a/example/ios/.gitignore +++ b/example/ios/.gitignore @@ -30,3 +30,6 @@ Runner/GeneratedPluginRegistrant.* !default.mode2v3 !default.pbxuser !default.perspectivev3 + +# Flutter related +**/Flutter/ephemeral/ \ No newline at end of file diff --git a/example/lib/main.dart b/example/lib/main.dart index cbe02dbc..8c59a524 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -161,36 +161,47 @@ class _WidgetGalleryState extends State { itemSize: SidebarItemSize.large, items: const [ SidebarItem( - leading: MacosImageIcon( - AssetImage('assets/sf_symbols/button_programmable_2x.png'), - ), - label: Text('Buttons'), - ), - SidebarItem( - leading: MacosImageIcon( - AssetImage( - 'assets/sf_symbols/lines_measurement_horizontal_2x.png', + label: Text('Basic UI Elements'), + section: true, + expandDisclosureItems: true, + disclosureItems: [ + SidebarItem( + leading: MacosImageIcon( + AssetImage( + 'assets/sf_symbols/button_programmable_2x.png', + ), + ), + label: Text('Buttons'), ), - ), - label: Text('Indicators'), - ), - SidebarItem( - leading: MacosImageIcon( - AssetImage( - 'assets/sf_symbols/character_cursor_ibeam_2x.png', + SidebarItem( + leading: MacosImageIcon( + AssetImage( + 'assets/sf_symbols/lines_measurement_horizontal_2x.png', + ), + ), + label: Text('Indicators'), ), - ), - label: Text('Fields'), - ), - SidebarItem( - leading: MacosImageIcon( - AssetImage('assets/sf_symbols/rectangle_3_group_2x.png'), - ), - label: Text('Colors'), - ), - SidebarItem( - leading: MacosIcon(CupertinoIcons.square_on_square), - label: Text('Dialogs & Sheets'), + SidebarItem( + leading: MacosImageIcon( + AssetImage( + 'assets/sf_symbols/character_cursor_ibeam_2x.png', + ), + ), + label: Text('Fields'), + ), + SidebarItem( + leading: MacosImageIcon( + AssetImage( + 'assets/sf_symbols/rectangle_3_group_2x.png', + ), + ), + label: Text('Colors'), + ), + SidebarItem( + leading: MacosIcon(CupertinoIcons.square_on_square), + label: Text('Dialogs & Sheets'), + ), + ], ), SidebarItem( leading: MacosImageIcon( @@ -199,6 +210,7 @@ class _WidgetGalleryState extends State { ), ), label: Text('Layout'), + section: true, disclosureItems: [ SidebarItem( leading: MacosIcon(CupertinoIcons.macwindow), @@ -224,15 +236,23 @@ class _WidgetGalleryState extends State { expandDisclosureItems: true, ), SidebarItem( - leading: MacosImageIcon( - AssetImage( - 'assets/sf_symbols/filemenu_and_selection_2x.png'), - ), - label: Text('Selectors'), - ), - SidebarItem( - leading: MacosIcon(CupertinoIcons.textformat_size), - label: Text('Typography'), + label: Text('Additional UI Elements'), + section: true, + expandDisclosureItems: true, + disclosureItems: [ + SidebarItem( + leading: MacosImageIcon( + AssetImage( + 'assets/sf_symbols/filemenu_and_selection_2x.png', + ), + ), + label: Text('Selectors'), + ), + SidebarItem( + leading: MacosIcon(CupertinoIcons.textformat_size), + label: Text('Typography'), + ), + ], ), ], ); @@ -249,9 +269,7 @@ class _WidgetGalleryState extends State { maxWidth: 300, shownByDefault: false, builder: (context, _) { - return const Center( - child: Text('End Sidebar'), - ); + return const Center(child: Text('End Sidebar')); }, ), child: [ diff --git a/example/lib/pages/buttons_page.dart b/example/lib/pages/buttons_page.dart index 26952d90..72d74a20 100644 --- a/example/lib/pages/buttons_page.dart +++ b/example/lib/pages/buttons_page.dart @@ -52,9 +52,7 @@ class _ButtonsPageState extends State { ToolBarIconButton( label: 'Toggle End Sidebar', tooltipMessage: 'Toggle End Sidebar', - icon: const MacosIcon( - CupertinoIcons.sidebar_right, - ), + icon: const MacosIcon(CupertinoIcons.sidebar_right), onPressed: () => MacosWindowScope.of(context).toggleEndSidebar(), showLabel: false, ), @@ -71,10 +69,7 @@ class _ButtonsPageState extends State { children: [ const WidgetTextTitle1(widgetName: 'PushButton'), Divider(color: MacosTheme.of(context).dividerColor), - Text( - 'Primary', - style: MacosTypography.of(context).title2, - ), + Text('Primary', style: MacosTypography.of(context).title2), Row( children: [ PushButton( @@ -115,7 +110,7 @@ class _ButtonsPageState extends State { startSize: 200, windowBreakpoint: 700, resizableSide: ResizableSide.left, - builder: (_, __) { + builder: (_, _) { return const Center( child: Text('Resizable Pane'), ); @@ -159,7 +154,7 @@ class _ButtonsPageState extends State { startSize: 200, windowBreakpoint: 700, resizableSide: ResizableSide.left, - builder: (_, __) { + builder: (_, _) { return const Center( child: Text('Resizable Pane'), ); @@ -203,7 +198,7 @@ class _ButtonsPageState extends State { startSize: 200, windowBreakpoint: 700, resizableSide: ResizableSide.left, - builder: (_, __) { + builder: (_, _) { return const Center( child: Text('Resizable Pane'), ); @@ -247,10 +242,7 @@ class _ButtonsPageState extends State { ], ), const SizedBox(height: 16), - Text( - 'Secondary', - style: MacosTypography.of(context).title2, - ), + Text('Secondary', style: MacosTypography.of(context).title2), Row( children: [ PushButton( @@ -293,7 +285,7 @@ class _ButtonsPageState extends State { startSize: 200, windowBreakpoint: 700, resizableSide: ResizableSide.left, - builder: (_, __) { + builder: (_, _) { return const Center( child: Text('Resizable Pane'), ); @@ -338,7 +330,7 @@ class _ButtonsPageState extends State { startSize: 200, windowBreakpoint: 700, resizableSide: ResizableSide.left, - builder: (_, __) { + builder: (_, _) { return const Center( child: Text('Resizable Pane'), ); @@ -383,7 +375,7 @@ class _ButtonsPageState extends State { startSize: 200, windowBreakpoint: 700, resizableSide: ResizableSide.left, - builder: (_, __) { + builder: (_, _) { return const Center( child: Text('Resizable Pane'), ); @@ -449,9 +441,7 @@ class _ButtonsPageState extends State { fillColor: Colors.transparent, ), const SizedBox(width: 16.0), - MacosBackButton( - onPressed: () => debugPrint('click'), - ), + MacosBackButton(onPressed: () => debugPrint('click')), ], ), const SizedBox(height: 20), @@ -477,26 +467,20 @@ class _ButtonsPageState extends State { Row( children: [ MacosIconButton( - icon: const MacosIcon( - CupertinoIcons.star_fill, - ), + icon: const MacosIcon(CupertinoIcons.star_fill), shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(7), onPressed: () {}, ), const SizedBox(width: 8), const MacosIconButton( - icon: MacosIcon( - CupertinoIcons.plus_app, - ), + icon: MacosIcon(CupertinoIcons.plus_app), shape: BoxShape.circle, //onPressed: () {}, ), const SizedBox(width: 8), MacosIconButton( - icon: const MacosIcon( - CupertinoIcons.minus_square, - ), + icon: const MacosIcon(CupertinoIcons.minus_square), backgroundColor: Colors.transparent, onPressed: () {}, ), @@ -567,10 +551,7 @@ class _ButtonsPageState extends State { }, ), const SizedBox(width: 8), - MacosCheckbox( - value: switchValue, - onChanged: null, - ), + MacosCheckbox(value: switchValue, onChanged: null), ], ), const SizedBox(height: 16), @@ -732,11 +713,12 @@ class _ButtonsPageState extends State { }, items: ['One', 'Two', 'Three', 'Four'] .map>((String value) { - return MacosPopupMenuItem( - value: value, - child: Text(value), - ); - }).toList(), + return MacosPopupMenuItem( + value: value, + child: Text(value), + ); + }) + .toList(), ), const SizedBox(width: 20), MacosPopupButton( @@ -752,8 +734,9 @@ class _ButtonsPageState extends State { onChanged: (String? newValue) { setState(() => languagePopupValue = newValue!); }, - items: languages - .map>((String value) { + items: languages.map>(( + String value, + ) { return MacosPopupMenuItem( value: value, child: Text(value), @@ -825,5 +808,5 @@ const languages = [ 'Polish', 'Ukrainian', 'Romanian', - 'Dutch' + 'Dutch', ]; diff --git a/example/lib/pages/colors_page.dart b/example/lib/pages/colors_page.dart index 6eb3eac8..5af39b82 100644 --- a/example/lib/pages/colors_page.dart +++ b/example/lib/pages/colors_page.dart @@ -50,9 +50,7 @@ class _ColorsPageState extends State { children: [ const MacosTooltip( message: 'System Red', - child: ColorBox( - color: MacosColors.systemRedColor, - ), + child: ColorBox(color: MacosColors.systemRedColor), ), MacosTooltip( message: 'System Red Dark', @@ -62,9 +60,7 @@ class _ColorsPageState extends State { ), const MacosTooltip( message: 'System Green', - child: ColorBox( - color: MacosColors.systemGreenColor, - ), + child: ColorBox(color: MacosColors.systemGreenColor), ), MacosTooltip( message: 'System Green Dark', @@ -74,9 +70,7 @@ class _ColorsPageState extends State { ), const MacosTooltip( message: 'System Blue', - child: ColorBox( - color: MacosColors.systemBlueColor, - ), + child: ColorBox(color: MacosColors.systemBlueColor), ), MacosTooltip( message: 'System Blue Dark', @@ -86,9 +80,7 @@ class _ColorsPageState extends State { ), const MacosTooltip( message: 'System Orange', - child: ColorBox( - color: MacosColors.systemOrangeColor, - ), + child: ColorBox(color: MacosColors.systemOrangeColor), ), MacosTooltip( message: 'System Orange Dark', @@ -98,9 +90,7 @@ class _ColorsPageState extends State { ), const MacosTooltip( message: 'System Yellow', - child: ColorBox( - color: MacosColors.systemYellowColor, - ), + child: ColorBox(color: MacosColors.systemYellowColor), ), MacosTooltip( message: 'System Yellow Dark', @@ -110,9 +100,7 @@ class _ColorsPageState extends State { ), const MacosTooltip( message: 'System Brown', - child: ColorBox( - color: MacosColors.systemBrownColor, - ), + child: ColorBox(color: MacosColors.systemBrownColor), ), MacosTooltip( message: 'System Brown Dark', @@ -122,9 +110,7 @@ class _ColorsPageState extends State { ), const MacosTooltip( message: 'System Pink', - child: ColorBox( - color: MacosColors.systemPinkColor, - ), + child: ColorBox(color: MacosColors.systemPinkColor), ), MacosTooltip( message: 'System Pink Dark', @@ -134,9 +120,7 @@ class _ColorsPageState extends State { ), const MacosTooltip( message: 'System Purple', - child: ColorBox( - color: MacosColors.systemPurpleColor, - ), + child: ColorBox(color: MacosColors.systemPurpleColor), ), MacosTooltip( message: 'System Purple Dark', @@ -146,9 +130,7 @@ class _ColorsPageState extends State { ), const MacosTooltip( message: 'System Teal', - child: ColorBox( - color: MacosColors.systemTealColor, - ), + child: ColorBox(color: MacosColors.systemTealColor), ), MacosTooltip( message: 'System Teal Dark', @@ -158,9 +140,7 @@ class _ColorsPageState extends State { ), const MacosTooltip( message: 'System Indigo', - child: ColorBox( - color: MacosColors.systemIndigoColor, - ), + child: ColorBox(color: MacosColors.systemIndigoColor), ), MacosTooltip( message: 'System Indigo Dark', @@ -170,9 +150,7 @@ class _ColorsPageState extends State { ), const MacosTooltip( message: 'System Gray', - child: ColorBox( - color: MacosColors.systemGrayColor, - ), + child: ColorBox(color: MacosColors.systemGrayColor), ), MacosTooltip( message: 'System Gray Dark', @@ -182,15 +160,11 @@ class _ColorsPageState extends State { ), const MacosTooltip( message: 'Link', - child: ColorBox( - color: MacosColors.linkColor, - ), + child: ColorBox(color: MacosColors.linkColor), ), MacosTooltip( message: 'Link Dark', - child: ColorBox( - color: MacosColors.linkColor.darkColor, - ), + child: ColorBox(color: MacosColors.linkColor.darkColor), ), const MacosTooltip( message: 'Unemphasized Background', @@ -221,9 +195,7 @@ class _ColorsPageState extends State { ), const MacosTooltip( message: 'Control', - child: ColorBox( - color: MacosColors.controlColor, - ), + child: ColorBox(color: MacosColors.controlColor), ), MacosTooltip( message: 'Control Dark', @@ -233,9 +205,7 @@ class _ColorsPageState extends State { ), const MacosTooltip( message: 'Control Text', - child: ColorBox( - color: MacosColors.controlTextColor, - ), + child: ColorBox(color: MacosColors.controlTextColor), ), MacosTooltip( message: 'Control Text Dark', @@ -294,9 +264,7 @@ class _ColorsPageState extends State { ), const MacosTooltip( message: 'Label', - child: ColorBox( - color: MacosColors.labelColor, - ), + child: ColorBox(color: MacosColors.labelColor), ), MacosTooltip( message: 'Label Dark', @@ -306,9 +274,7 @@ class _ColorsPageState extends State { ), const MacosTooltip( message: 'Secondary Label', - child: ColorBox( - color: MacosColors.secondaryLabelColor, - ), + child: ColorBox(color: MacosColors.secondaryLabelColor), ), MacosTooltip( message: 'Secondary Label Dark', @@ -318,9 +284,7 @@ class _ColorsPageState extends State { ), const MacosTooltip( message: 'Tertiary Label', - child: ColorBox( - color: MacosColors.tertiaryLabelColor, - ), + child: ColorBox(color: MacosColors.tertiaryLabelColor), ), MacosTooltip( message: 'Tertiary Label Dark', @@ -353,10 +317,7 @@ class _ColorsPageState extends State { } class ColorBox extends StatelessWidget { - const ColorBox({ - super.key, - required this.color, - }); + const ColorBox({super.key, required this.color}); final Color color; @@ -364,10 +325,7 @@ class ColorBox extends StatelessWidget { Widget build(BuildContext context) { return ColoredBox( color: color, - child: const SizedBox( - height: 50, - width: 50, - ), + child: const SizedBox(height: 50, width: 50), ); } } diff --git a/example/lib/pages/dialogs_page.dart b/example/lib/pages/dialogs_page.dart index 33764bda..c5d2eae3 100644 --- a/example/lib/pages/dialogs_page.dart +++ b/example/lib/pages/dialogs_page.dart @@ -215,15 +215,13 @@ class DemoSheet extends StatelessWidget { child: Column( children: [ const SizedBox(height: 50), - const FlutterLogo( - size: 56, - ), + const FlutterLogo(size: 56), const SizedBox(height: 24), Text( 'Welcome to macos_ui', - style: MacosTheme.of(context).typography.largeTitle.copyWith( - fontWeight: FontWeight.bold, - ), + style: MacosTheme.of( + context, + ).typography.largeTitle.copyWith(fontWeight: FontWeight.bold), ), const SizedBox(height: 24), const MacosListTile( diff --git a/example/lib/pages/fields_page.dart b/example/lib/pages/fields_page.dart index fd9183bb..7af455e8 100644 --- a/example/lib/pages/fields_page.dart +++ b/example/lib/pages/fields_page.dart @@ -105,8 +105,9 @@ class _FieldsPageState extends State { SizedBox( width: 300.0, child: MacosSearchField( - results: - countries.map((e) => SearchResultItem(e)).toList(), + results: countries + .map((e) => SearchResultItem(e)) + .toList(), placeholder: 'Search for a country...', onResultSelected: (resultItem) { // Retrieve the user-selected search suggestion via its @@ -125,10 +126,11 @@ class _FieldsPageState extends State { results: actionResults, resultHeight: 40.0, emptyWidget: const Center( - child: Padding( - padding: EdgeInsets.all(8.0), - child: Text('No action found!'), - )), + child: Padding( + padding: EdgeInsets.all(8.0), + child: Text('No action found!'), + ), + ), placeholder: 'Search for an action...', onResultSelected: (resultItem) { // Retrieve the user-selected search suggestion via its @@ -353,7 +355,7 @@ const countries = [ 'Virgin Islands (US)', 'Yemen', 'Zambia', - 'Zimbabwe' + 'Zimbabwe', ]; var actionResults = [ diff --git a/example/lib/pages/resizable_pane_page.dart b/example/lib/pages/resizable_pane_page.dart index 78ed3320..312fc68b 100644 --- a/example/lib/pages/resizable_pane_page.dart +++ b/example/lib/pages/resizable_pane_page.dart @@ -42,30 +42,24 @@ class _ResizablePanePageState extends State { startSize: 200, windowBreakpoint: 700, resizableSide: ResizableSide.right, - builder: (_, __) { - return const Center( - child: Text('Left Resizable Pane'), - ); + builder: (_, _) { + return const Center(child: Text('Left Resizable Pane')); }, ), ContentArea( - builder: (_, __) { + builder: (_, _) { return Column( children: [ const Flexible( fit: FlexFit.loose, - child: Center( - child: Text('Content Area'), - ), + child: Center(child: Text('Content Area')), ), ResizablePane( minSize: 50, startSize: 200, //windowBreakpoint: 600, - builder: (_, __) { - return const Center( - child: Text('Bottom Resizable Pane'), - ); + builder: (_, _) { + return const Center(child: Text('Bottom Resizable Pane')); }, resizableSide: ResizableSide.top, ), diff --git a/example/lib/pages/sliver_toolbar_page.dart b/example/lib/pages/sliver_toolbar_page.dart index be2e680c..583ef5b3 100644 --- a/example/lib/pages/sliver_toolbar_page.dart +++ b/example/lib/pages/sliver_toolbar_page.dart @@ -1,5 +1,4 @@ import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; import 'package:macos_ui/macos_ui.dart'; class SliverToolbarPage extends StatefulWidget { @@ -128,25 +127,23 @@ class _SliverToolbarPageState extends State { ), ), SliverList( - delegate: SliverChildListDelegate( - [ - Row( - children: [ - ...List.generate( - 3, - (index) => const FlutterLogo(size: 150), - ) - ], - ), - ...List.generate( - 100, - (index) => Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Text('Item ${index + 1}'), + delegate: SliverChildListDelegate([ + Row( + children: [ + ...List.generate( + 3, + (index) => const FlutterLogo(size: 150), ), + ], + ), + ...List.generate( + 100, + (index) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Text('Item ${index + 1}'), ), - ], - ), + ), + ]), ), ], ); diff --git a/example/lib/pages/tabview_page.dart b/example/lib/pages/tabview_page.dart index 5e224429..03c20fb6 100644 --- a/example/lib/pages/tabview_page.dart +++ b/example/lib/pages/tabview_page.dart @@ -9,10 +9,7 @@ class TabViewPage extends StatefulWidget { } class _TabViewPageState extends State { - final _controller = MacosTabController( - initialIndex: 0, - length: 3, - ); + final _controller = MacosTabController(initialIndex: 0, length: 3); @override Widget build(BuildContext context) { @@ -49,26 +46,14 @@ class _TabViewPageState extends State { child: MacosTabView( controller: _controller, tabs: const [ - MacosTab( - label: 'Tab 1', - ), - MacosTab( - label: 'Tab 2', - ), - MacosTab( - label: 'Tab 3', - ), + MacosTab(label: 'Tab 1'), + MacosTab(label: 'Tab 2'), + MacosTab(label: 'Tab 3'), ], children: const [ - Center( - child: Text('Tab 1'), - ), - Center( - child: Text('Tab 2'), - ), - Center( - child: Text('Tab 3'), - ), + Center(child: Text('Tab 1')), + Center(child: Text('Tab 2')), + Center(child: Text('Tab 3')), ], ), ); diff --git a/example/lib/pages/toolbar_page.dart b/example/lib/pages/toolbar_page.dart index 104bd7c1..659bc873 100644 --- a/example/lib/pages/toolbar_page.dart +++ b/example/lib/pages/toolbar_page.dart @@ -17,18 +17,14 @@ class _ToolbarPageState extends State { titleWidth: 100.0, actions: [ ToolBarIconButton( - icon: const MacosIcon( - CupertinoIcons.folder_badge_plus, - ), + icon: const MacosIcon(CupertinoIcons.folder_badge_plus), onPressed: () => debugPrint('New Folder...'), label: 'New Folder', showLabel: true, tooltipMessage: 'This is a beautiful tooltip', ), ToolBarIconButton( - icon: const MacosIcon( - CupertinoIcons.add_circled, - ), + icon: const MacosIcon(CupertinoIcons.add_circled), onPressed: () => debugPrint('Add...'), label: 'Add', showLabel: true, @@ -37,17 +33,13 @@ class _ToolbarPageState extends State { const ToolBarSpacer(), ToolBarIconButton( label: 'Delete', - icon: const MacosIcon( - CupertinoIcons.trash, - ), + icon: const MacosIcon(CupertinoIcons.trash), onPressed: () => debugPrint('pressed'), showLabel: false, ), const ToolBarIconButton( label: 'Change View', - icon: MacosIcon( - CupertinoIcons.list_bullet, - ), + icon: MacosIcon(CupertinoIcons.list_bullet), showLabel: false, ), ToolBarPullDownButton( @@ -98,17 +90,13 @@ class _ToolbarPageState extends State { const ToolBarDivider(), ToolBarIconButton( label: 'Table', - icon: const MacosIcon( - CupertinoIcons.square_grid_3x2, - ), + icon: const MacosIcon(CupertinoIcons.square_grid_3x2), onPressed: () => debugPrint('Table...'), showLabel: false, ), ToolBarIconButton( label: 'Toggle Sidebar', - icon: const MacosIcon( - CupertinoIcons.sidebar_left, - ), + icon: const MacosIcon(CupertinoIcons.sidebar_left), onPressed: () => MacosWindowScope.of(context).toggleSidebar(), showLabel: false, ), @@ -146,9 +134,7 @@ class _ToolbarPageState extends State { ), ToolBarIconButton( label: 'Share', - icon: const MacosIcon( - CupertinoIcons.share, - ), + icon: const MacosIcon(CupertinoIcons.share), onPressed: () => debugPrint('pressed'), showLabel: false, ), diff --git a/example/lib/pages/typography_page.dart b/example/lib/pages/typography_page.dart index 3779cb57..3dbf8d6d 100644 --- a/example/lib/pages/typography_page.dart +++ b/example/lib/pages/typography_page.dart @@ -19,9 +19,7 @@ class TypographyPage extends StatelessWidget { ); return MacosScaffold( - toolBar: const ToolBar( - title: Text('Typography'), - ), + toolBar: const ToolBar(title: Text('Typography')), children: [ ContentArea( builder: (context, scrollController) { @@ -42,88 +40,99 @@ class TypographyPage extends StatelessWidget { const SizedBox(height: 8.0), Text( 'LargeTitle', - style: typography.largeTitle - .copyWith(fontWeight: FontWeight.w700), + style: typography.largeTitle.copyWith( + fontWeight: FontWeight.w700, + ), ), const SizedBox(height: 24.0), Text('Title1', style: typography.title1), const SizedBox(height: 8.0), Text( 'Title1', - style: typography.title1 - .copyWith(fontWeight: FontWeight.w700), + style: typography.title1.copyWith( + fontWeight: FontWeight.w700, + ), ), const SizedBox(height: 24.0), Text('Title2', style: typography.title2), const SizedBox(height: 8.0), Text( 'Title2', - style: typography.title2 - .copyWith(fontWeight: FontWeight.w700), + style: typography.title2.copyWith( + fontWeight: FontWeight.w700, + ), ), const SizedBox(height: 24.0), Text('Title3', style: typography.title3), const SizedBox(height: 8.0), Text( 'Title3', - style: typography.title3 - .copyWith(fontWeight: FontWeight.w600), + style: typography.title3.copyWith( + fontWeight: FontWeight.w600, + ), ), const SizedBox(height: 24.0), Text('Headline', style: typography.headline), const SizedBox(height: 8.0), Text( 'Headline', - style: typography.headline - .copyWith(fontWeight: MacosFontWeight.w860), + style: typography.headline.copyWith( + fontWeight: MacosFontWeight.w860, + ), ), const SizedBox(height: 24.0), Text('Body', style: typography.body), const SizedBox(height: 8.0), Text( 'Body', - style: typography.body - .copyWith(fontWeight: MacosFontWeight.w590), + style: typography.body.copyWith( + fontWeight: MacosFontWeight.w590, + ), ), const SizedBox(height: 24.0), Text('Callout', style: typography.callout), const SizedBox(height: 8.0), Text( 'Callout', - style: typography.callout - .copyWith(fontWeight: MacosFontWeight.w590), + style: typography.callout.copyWith( + fontWeight: MacosFontWeight.w590, + ), ), const SizedBox(height: 24.0), Text('Subheadline', style: typography.subheadline), const SizedBox(height: 8.0), Text( 'Subheadline', - style: typography.subheadline - .copyWith(fontWeight: MacosFontWeight.w590), + style: typography.subheadline.copyWith( + fontWeight: MacosFontWeight.w590, + ), ), const SizedBox(height: 24.0), Text('Footnote', style: typography.subheadline), const SizedBox(height: 8.0), Text( 'Footnote', - style: typography.subheadline - .copyWith(fontWeight: MacosFontWeight.w590), + style: typography.subheadline.copyWith( + fontWeight: MacosFontWeight.w590, + ), ), const SizedBox(height: 24.0), Text('Caption1', style: typography.caption1), const SizedBox(height: 8.0), Text( 'Caption1', - style: typography.caption1 - .copyWith(fontWeight: MacosFontWeight.w510), + style: typography.caption1.copyWith( + fontWeight: MacosFontWeight.w510, + ), ), const SizedBox(height: 24.0), Text('Caption2', style: typography.caption2), const SizedBox(height: 8.0), Text( 'Caption2', - style: typography.caption2 - .copyWith(fontWeight: MacosFontWeight.w590), + style: typography.caption2.copyWith( + fontWeight: MacosFontWeight.w590, + ), ), ], ), @@ -139,74 +148,63 @@ class TypographyPage extends StatelessWidget { const SizedBox(height: 8.0), Text( 'LargeTitle', - style: secondaryTypography.largeTitle - .copyWith(fontWeight: FontWeight.w700), + style: secondaryTypography.largeTitle.copyWith( + fontWeight: FontWeight.w700, + ), ), const SizedBox(height: 24.0), - Text( - 'Title1', - style: secondaryTypography.title1, - ), + Text('Title1', style: secondaryTypography.title1), const SizedBox(height: 8.0), Text( 'Title1', - style: secondaryTypography.title1 - .copyWith(fontWeight: FontWeight.w700), + style: secondaryTypography.title1.copyWith( + fontWeight: FontWeight.w700, + ), ), const SizedBox(height: 24.0), - Text( - 'Title2', - style: secondaryTypography.title2, - ), + Text('Title2', style: secondaryTypography.title2), const SizedBox(height: 8.0), Text( 'Title2', - style: secondaryTypography.title2 - .copyWith(fontWeight: FontWeight.w700), + style: secondaryTypography.title2.copyWith( + fontWeight: FontWeight.w700, + ), ), const SizedBox(height: 24.0), - Text( - 'Title3', - style: secondaryTypography.title3, - ), + Text('Title3', style: secondaryTypography.title3), const SizedBox(height: 8.0), Text( 'Title3', - style: secondaryTypography.title3 - .copyWith(fontWeight: FontWeight.w600), + style: secondaryTypography.title3.copyWith( + fontWeight: FontWeight.w600, + ), ), const SizedBox(height: 24.0), - Text( - 'Headline', - style: secondaryTypography.headline, - ), + Text('Headline', style: secondaryTypography.headline), const SizedBox(height: 8.0), Text( 'Headline', - style: secondaryTypography.headline - .copyWith(fontWeight: MacosFontWeight.w860), + style: secondaryTypography.headline.copyWith( + fontWeight: MacosFontWeight.w860, + ), ), const SizedBox(height: 24.0), - Text( - 'Body', - style: secondaryTypography.body, - ), + Text('Body', style: secondaryTypography.body), const SizedBox(height: 8.0), Text( 'Body', - style: secondaryTypography.body - .copyWith(fontWeight: MacosFontWeight.w590), + style: secondaryTypography.body.copyWith( + fontWeight: MacosFontWeight.w590, + ), ), const SizedBox(height: 24.0), - Text( - 'Callout', - style: secondaryTypography.callout, - ), + Text('Callout', style: secondaryTypography.callout), const SizedBox(height: 8.0), Text( 'Callout', - style: secondaryTypography.callout - .copyWith(fontWeight: MacosFontWeight.w590), + style: secondaryTypography.callout.copyWith( + fontWeight: MacosFontWeight.w590, + ), ), const SizedBox(height: 24.0), Text( @@ -216,41 +214,36 @@ class TypographyPage extends StatelessWidget { const SizedBox(height: 8.0), Text( 'Subheadline', - style: secondaryTypography.subheadline - .copyWith(fontWeight: FontWeight.w600), + style: secondaryTypography.subheadline.copyWith( + fontWeight: FontWeight.w600, + ), ), const SizedBox(height: 24.0), - Text( - 'Footnote', - style: secondaryTypography.footnote, - ), + Text('Footnote', style: secondaryTypography.footnote), const SizedBox(height: 8.0), Text( 'Footnote', - style: secondaryTypography.footnote - .copyWith(fontWeight: MacosFontWeight.w590), + style: secondaryTypography.footnote.copyWith( + fontWeight: MacosFontWeight.w590, + ), ), const SizedBox(height: 24.0), - Text( - 'Caption1', - style: secondaryTypography.caption1, - ), + Text('Caption1', style: secondaryTypography.caption1), const SizedBox(height: 8.0), Text( 'Caption1', - style: secondaryTypography.caption1 - .copyWith(fontWeight: MacosFontWeight.w510), + style: secondaryTypography.caption1.copyWith( + fontWeight: MacosFontWeight.w510, + ), ), const SizedBox(height: 24.0), - Text( - 'Caption2', - style: secondaryTypography.caption2, - ), + Text('Caption2', style: secondaryTypography.caption2), const SizedBox(height: 8.0), Text( 'Caption2', - style: secondaryTypography.caption2 - .copyWith(fontWeight: MacosFontWeight.w590), + style: secondaryTypography.caption2.copyWith( + fontWeight: MacosFontWeight.w590, + ), ), ], ), @@ -266,74 +259,63 @@ class TypographyPage extends StatelessWidget { const SizedBox(height: 8.0), Text( 'LargeTitle', - style: tertiaryTypography.largeTitle - .copyWith(fontWeight: FontWeight.w700), + style: tertiaryTypography.largeTitle.copyWith( + fontWeight: FontWeight.w700, + ), ), const SizedBox(height: 24.0), - Text( - 'Title1', - style: tertiaryTypography.title1, - ), + Text('Title1', style: tertiaryTypography.title1), const SizedBox(height: 8.0), Text( 'Title1', - style: tertiaryTypography.title1 - .copyWith(fontWeight: FontWeight.w700), + style: tertiaryTypography.title1.copyWith( + fontWeight: FontWeight.w700, + ), ), const SizedBox(height: 24.0), - Text( - 'Title2', - style: tertiaryTypography.title2, - ), + Text('Title2', style: tertiaryTypography.title2), const SizedBox(height: 8.0), Text( 'Title2', - style: tertiaryTypography.title2 - .copyWith(fontWeight: FontWeight.w700), + style: tertiaryTypography.title2.copyWith( + fontWeight: FontWeight.w700, + ), ), const SizedBox(height: 24.0), - Text( - 'Title3', - style: tertiaryTypography.title3, - ), + Text('Title3', style: tertiaryTypography.title3), const SizedBox(height: 8.0), Text( 'Title3', - style: tertiaryTypography.title3 - .copyWith(fontWeight: FontWeight.w600), + style: tertiaryTypography.title3.copyWith( + fontWeight: FontWeight.w600, + ), ), const SizedBox(height: 24.0), - Text( - 'Headline', - style: tertiaryTypography.headline, - ), + Text('Headline', style: tertiaryTypography.headline), const SizedBox(height: 8.0), Text( 'Headline', - style: tertiaryTypography.headline - .copyWith(fontWeight: MacosFontWeight.w860), + style: tertiaryTypography.headline.copyWith( + fontWeight: MacosFontWeight.w860, + ), ), const SizedBox(height: 24.0), - Text( - 'Body', - style: tertiaryTypography.body, - ), + Text('Body', style: tertiaryTypography.body), const SizedBox(height: 8.0), Text( 'Body', - style: tertiaryTypography.body - .copyWith(fontWeight: MacosFontWeight.w590), + style: tertiaryTypography.body.copyWith( + fontWeight: MacosFontWeight.w590, + ), ), const SizedBox(height: 24.0), - Text( - 'Callout', - style: tertiaryTypography.callout, - ), + Text('Callout', style: tertiaryTypography.callout), const SizedBox(height: 8.0), Text( 'Callout', - style: tertiaryTypography.callout - .copyWith(fontWeight: MacosFontWeight.w590), + style: tertiaryTypography.callout.copyWith( + fontWeight: MacosFontWeight.w590, + ), ), const SizedBox(height: 24.0), Text( @@ -343,41 +325,36 @@ class TypographyPage extends StatelessWidget { const SizedBox(height: 8.0), Text( 'Subheadline', - style: tertiaryTypography.subheadline - .copyWith(fontWeight: MacosFontWeight.w590), + style: tertiaryTypography.subheadline.copyWith( + fontWeight: MacosFontWeight.w590, + ), ), const SizedBox(height: 24.0), - Text( - 'Footnote', - style: tertiaryTypography.footnote, - ), + Text('Footnote', style: tertiaryTypography.footnote), const SizedBox(height: 8.0), Text( 'Footnote', - style: tertiaryTypography.footnote - .copyWith(fontWeight: MacosFontWeight.w590), + style: tertiaryTypography.footnote.copyWith( + fontWeight: MacosFontWeight.w590, + ), ), const SizedBox(height: 24.0), - Text( - 'Caption1', - style: tertiaryTypography.caption1, - ), + Text('Caption1', style: tertiaryTypography.caption1), const SizedBox(height: 8.0), Text( 'Caption1', - style: tertiaryTypography.caption1 - .copyWith(fontWeight: MacosFontWeight.w510), + style: tertiaryTypography.caption1.copyWith( + fontWeight: MacosFontWeight.w510, + ), ), const SizedBox(height: 24.0), - Text( - 'Caption2', - style: tertiaryTypography.caption2, - ), + Text('Caption2', style: tertiaryTypography.caption2), const SizedBox(height: 8.0), Text( 'Caption2', - style: tertiaryTypography.caption2 - .copyWith(fontWeight: MacosFontWeight.w590), + style: tertiaryTypography.caption2.copyWith( + fontWeight: MacosFontWeight.w590, + ), ), ], ), diff --git a/example/lib/platform_menus.dart b/example/lib/platform_menus.dart index 91ba6a7c..3e920e32 100644 --- a/example/lib/platform_menus.dart +++ b/example/lib/platform_menus.dart @@ -17,12 +17,8 @@ List menuBarItems() { PlatformMenu( label: 'macos_ui Widget Gallery', menus: [ - PlatformProvidedMenuItem( - type: PlatformProvidedMenuItemType.about, - ), - PlatformProvidedMenuItem( - type: PlatformProvidedMenuItemType.quit, - ), + PlatformProvidedMenuItem(type: PlatformProvidedMenuItemType.about), + PlatformProvidedMenuItem(type: PlatformProvidedMenuItemType.quit), ], ), PlatformMenu( diff --git a/example/lib/widgets/widget_text_title1.dart b/example/lib/widgets/widget_text_title1.dart index 77ab7314..121e0131 100644 --- a/example/lib/widgets/widget_text_title1.dart +++ b/example/lib/widgets/widget_text_title1.dart @@ -11,18 +11,16 @@ class WidgetTextTitle1 extends StatelessWidget { Widget build(BuildContext context) { return DecoratedBox( decoration: BoxDecoration( - color: MacosColors.systemGrayColor.withOpacity(0.5), + color: MacosColors.systemGrayColor.withValues(alpha: 0.5), borderRadius: BorderRadius.circular(4.0), ), child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 6.0, - ), + padding: const EdgeInsets.symmetric(horizontal: 6.0), child: Text( widgetName, - style: MacosTypography.of(context) - .title1 - .copyWith(fontFamily: GoogleFonts.jetBrainsMono().fontFamily), + style: MacosTypography.of( + context, + ).title1.copyWith(fontFamily: GoogleFonts.jetBrainsMono().fontFamily), ), ), ); diff --git a/example/lib/widgets/widget_text_title2.dart b/example/lib/widgets/widget_text_title2.dart index 8da1135d..943e5025 100644 --- a/example/lib/widgets/widget_text_title2.dart +++ b/example/lib/widgets/widget_text_title2.dart @@ -11,18 +11,16 @@ class WidgetTextTitle2 extends StatelessWidget { Widget build(BuildContext context) { return DecoratedBox( decoration: BoxDecoration( - color: MacosColors.systemGrayColor.withOpacity(0.5), + color: MacosColors.systemGrayColor.withValues(alpha: 0.5), borderRadius: BorderRadius.circular(4.0), ), child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 6.0, - ), + padding: const EdgeInsets.symmetric(horizontal: 6.0), child: Text( widgetName, - style: MacosTypography.of(context) - .title2 - .copyWith(fontFamily: GoogleFonts.jetBrainsMono().fontFamily), + style: MacosTypography.of( + context, + ).title2.copyWith(fontFamily: GoogleFonts.jetBrainsMono().fontFamily), ), ), ); diff --git a/example/macos/Podfile.lock b/example/macos/Podfile.lock index 475f42a3..b40e00de 100644 --- a/example/macos/Podfile.lock +++ b/example/macos/Podfile.lock @@ -35,13 +35,13 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos SPEC CHECKSUMS: - appkit_ui_element_colors: 39bb2d80be3f19b152ccf4c70d5bbe6cba43d74a - FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 - macos_ui: 6229a8922cd97bafb7d9636c8eb8dfb0744183ca - macos_window_utils: 933f91f64805e2eb91a5bd057cf97cd097276663 + appkit_ui_element_colors: bb247a2d02b8313cc47e1b83be48d996034c4001 + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 + macos_ui: 50a2048b7ef82bde42570e2775f50907537a0eeb + macos_window_utils: 721df4da91cb4bde7b2b7b6ae93cdead4851118f path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 - url_launcher_macos: 5f437abeda8c85500ceb03f5c1938a8c5a705399 + url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404 PODFILE CHECKSUM: ff0a9a3ce75ee73f200ca7e2f47745698c917ef9 -COCOAPODS: 1.14.3 +COCOAPODS: 1.15.2 diff --git a/example/macos/Runner.xcodeproj/project.pbxproj b/example/macos/Runner.xcodeproj/project.pbxproj index 717c51d9..d130c440 100644 --- a/example/macos/Runner.xcodeproj/project.pbxproj +++ b/example/macos/Runner.xcodeproj/project.pbxproj @@ -27,6 +27,7 @@ 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; 841463C0F24F8E3B273A97BD /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22FC83C884F4624B8C19DB88 /* Pods_Runner.framework */; }; + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -80,6 +81,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, 841463C0F24F8E3B273A97BD /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -174,6 +176,9 @@ /* Begin PBXNativeTarget section */ 33CC10EC2044A3C60003C045 /* Runner */ = { + packageProductDependencies = ( + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, + ); isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( @@ -199,6 +204,9 @@ /* Begin PBXProject section */ 33CC10E52044A3C60003C045 /* Project object */ = { + packageReferences = ( + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, + ); isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; @@ -627,6 +635,18 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ +/* Begin XCLocalSwiftPackageReference section */ + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; + }; +/* End XCLocalSwiftPackageReference section */ +/* Begin XCSwiftPackageProductDependency section */ + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { + isa = XCSwiftPackageProductDependency; + productName = FlutterGeneratedPluginSwiftPackage; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 33CC10E52044A3C60003C045 /* Project object */; } diff --git a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 5b055a3a..8b5a3a28 100644 --- a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -5,6 +5,24 @@ + + + + + + + + + + diff --git a/example/macos/Runner/AppDelegate.swift b/example/macos/Runner/AppDelegate.swift index 8e02df28..b3c17614 100644 --- a/example/macos/Runner/AppDelegate.swift +++ b/example/macos/Runner/AppDelegate.swift @@ -6,4 +6,8 @@ class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } } diff --git a/example/pubspec.lock b/example/pubspec.lock index 640f7187..fe0fd510 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,58 +5,58 @@ packages: dependency: transitive description: name: appkit_ui_element_colors - sha256: c3e50f900aae314d339de489535736238627071457c4a4a2dbbb1545b4f04f22 + sha256: b88a7c35d440fa3ac75222d0e2b7e3259200e531e33b5d2468e358119f3481dc url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.0.1" async: dependency: transitive description: name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" url: "https://pub.dev" source: hosted - version: "2.11.0" + version: "2.13.0" boolean_selector: dependency: transitive description: name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" characters: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" clock: dependency: transitive description: name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" collection: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.1" crypto: dependency: transitive description: name: crypto - sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27 + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.6" cupertino_icons: dependency: "direct main" description: @@ -69,26 +69,26 @@ packages: dependency: transitive description: name: equatable - sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7" url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.0.7" fake_async: dependency: transitive description: name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.3" ffi: dependency: transitive description: name: ffi - sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" flutter: dependency: "direct main" description: flutter @@ -98,10 +98,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" + sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "6.0.0" flutter_test: dependency: "direct dev" description: flutter @@ -116,89 +116,89 @@ packages: dependency: "direct main" description: name: google_fonts - sha256: b1ac0fe2832c9cc95e5e88b57d627c5e68c223b9657f4b96e1487aa9098c7b82 + sha256: "517b20870220c48752eafa0ba1a797a092fb22df0d89535fd9991e86ee2cdd9c" url: "https://pub.dev" source: hosted - version: "6.2.1" + version: "6.3.2" gradient_borders: dependency: transitive description: name: gradient_borders - sha256: b1cd969552c83f458ff755aa68e13a0327d09f06c3f42f471b423b01427f21f8 + sha256: "492bc88ab8d88a4117a7f00e525a669b65f19973bea7ee677f9d9de7603bf037" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.0.2" http: dependency: transitive description: name: http - sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 + sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b" url: "https://pub.dev" source: hosted - version: "1.2.2" + version: "1.4.0" http_parser: dependency: transitive description: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.2" leak_tracker: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "11.0.2" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" lints: dependency: transitive description: name: lints - sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" + sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0 url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "6.0.0" macos_ui: dependency: "direct main" description: path: ".." relative: true source: path - version: "2.1.0" + version: "2.2.1" macos_window_utils: dependency: transitive description: name: macos_window_utils - sha256: "230be594d26f6dee92c5a1544f4242d25138a5bfb9f185b27f14de3949ef0be8" + sha256: d4df3501fd32ac0d2d7590cb6a8e4758337d061c8fa0db816fdd636be63a8438 url: "https://pub.dev" source: hosted - version: "1.5.0" + version: "1.9.0" matcher: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.17" material_color_utilities: dependency: transitive description: @@ -211,10 +211,10 @@ packages: dependency: transitive description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.16.0" nested: dependency: transitive description: @@ -227,34 +227,34 @@ packages: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" path_provider: dependency: transitive description: name: path_provider - sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.5" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7" + sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9 url: "https://pub.dev" source: hosted - version: "2.2.10" + version: "2.2.17" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 + sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" path_provider_linux: dependency: transitive description: @@ -283,10 +283,10 @@ packages: dependency: transitive description: name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.5" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: @@ -299,111 +299,111 @@ packages: dependency: "direct main" description: name: provider - sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84" url: "https://pub.dev" source: hosted - version: "6.1.2" + version: "6.1.5" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.10.1" stack_trace: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" string_scanner: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.4.1" term_glyph: dependency: transitive description: name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" test_api: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.6" typed_data: dependency: transitive description: name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.0" url_launcher: dependency: "direct main" description: name: url_launcher - sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3" + sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "6.3.2" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: e35a698ac302dd68e41f73250bd9517fe3ab5fa4f18fe4647a0872db61bacbab + sha256: "8582d7f6fe14d2652b4c45c9b6c14c0b678c2af2d083a11b604caeba51930d79" url: "https://pub.dev" source: hosted - version: "6.3.10" + version: "6.3.16" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e + sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb" url: "https://pub.dev" source: hosted - version: "6.3.1" + version: "6.3.3" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.2.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de" + sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.2.2" url_launcher_platform_interface: dependency: transitive description: @@ -416,50 +416,50 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" + sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.4.1" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185" + sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.4" vector_math: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 url: "https://pub.dev" source: hosted - version: "14.2.5" + version: "15.0.0" web: dependency: transitive description: name: web - sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062 + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.1.1" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.1.0" sdks: - dart: ">=3.5.3 <4.0.0" - flutter: ">=3.24.0" + dart: ">=3.9.2 <4.0.0" + flutter: ">=3.35.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 22e45eb8..d57e3877 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -4,7 +4,7 @@ publish_to: 'none' version: 1.0.0+1 environment: - sdk: '>=3.5.3 <4.0.0' + sdk: '>=3.9.2 <4.0.0' dependencies: flutter: @@ -13,14 +13,14 @@ dependencies: cupertino_icons: ^1.0.8 macos_ui: path: .. - provider: ^6.1.2 - google_fonts: ^6.2.1 - url_launcher: ^6.3.0 + provider: ^6.1.5 + google_fonts: ^6.3.2 + url_launcher: ^6.3.2 dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^4.0.0 + flutter_lints: ^6.0.0 flutter: assets: diff --git a/lib/macos_ui.dart b/lib/macos_ui.dart index d47a163a..e0a5adcc 100644 --- a/lib/macos_ui.dart +++ b/lib/macos_ui.dart @@ -12,7 +12,7 @@ /// * [yaru_icons](https://pub.dev/packages/yaru_icons) /// * [yaru_colors](https://pub.dev/packages/yaru_colors) -library macos_ui; +library; export 'package:macos_window_utils/macos/ns_window_delegate.dart'; export 'package:macos_window_utils/macos_window_utils.dart'; @@ -89,3 +89,5 @@ export 'src/theme/time_picker_theme.dart'; export 'src/theme/tooltip_theme.dart'; export 'src/theme/typography.dart'; export 'src/enums/accent_color.dart'; +export 'src/utils/window_main_state_listener.dart'; +export 'src/utils/accent_color_listener.dart'; diff --git a/lib/src/buttons/back_button.dart b/lib/src/buttons/back_button.dart index 605356a4..7882b168 100644 --- a/lib/src/buttons/back_button.dart +++ b/lib/src/buttons/back_button.dart @@ -41,11 +41,9 @@ class MacosBackButton extends StatefulWidget { properties.add(ColorProperty('fillColor', fillColor)); properties.add(ColorProperty('hoverColor', fillColor)); properties.add(StringProperty('semanticLabel', semanticLabel)); - properties.add(FlagProperty( - 'enabled', - value: enabled, - ifFalse: 'disabled', - )); + properties.add( + FlagProperty('enabled', value: enabled, ifFalse: 'disabled'), + ); } @override @@ -191,11 +189,11 @@ class MacosBackButtonState extends State decoration: BoxDecoration( color: buttonHeldDown ? brightness == Brightness.dark - ? const Color(0xff3C383C) - : const Color(0xffE5E5E5) + ? const Color(0xff3C383C) + : const Color(0xffE5E5E5) : _isHovered - ? hoverColor - : fillColor, + ? hoverColor + : fillColor, borderRadius: const BorderRadius.all(Radius.circular(7)), ), child: Icon( diff --git a/lib/src/buttons/checkbox.dart b/lib/src/buttons/checkbox.dart index 2d21e7c7..9695a500 100644 --- a/lib/src/buttons/checkbox.dart +++ b/lib/src/buttons/checkbox.dart @@ -58,19 +58,19 @@ class MacosCheckbox extends StatelessWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(StringProperty( - 'state', - isMixed - ? 'mixed' - : value! - ? 'checked' - : 'unchecked', - )); - properties.add(FlagProperty( - 'disabled', - value: isDisabled, - ifFalse: 'enabled', - )); + properties.add( + StringProperty( + 'state', + isMixed + ? 'mixed' + : value! + ? 'checked' + : 'unchecked', + ), + ); + properties.add( + FlagProperty('disabled', value: isDisabled, ifFalse: 'enabled'), + ); properties.add(DoubleProperty('size', size)); properties.add(ColorProperty('activeColor', activeColor)); properties.add(ColorProperty('disabledColor', disabledColor)); @@ -84,49 +84,50 @@ class MacosCheckbox extends StatelessWidget { final MacosThemeData theme = MacosTheme.of(context); bool isLight = !theme.brightness.isDark; 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, - ), - ), + 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, ), ), - ); - }); - }); + ), + ), + ); + }, + ); + }, + ); } } @@ -192,20 +193,35 @@ class _CheckboxStack extends StatelessWidget { final bool isMainWindow; final double size; + Color _getCheckmarkColor() { + if (isDisabled) { + return const MacosColor.fromRGBO(172, 172, 172, 1.0); + } + + if (theme.brightness.isDark) { + return theme.accentColor == AccentColor.graphite && isMainWindow + ? MacosColors.black + : MacosColors.white; + } + + if (theme.isMainWindow == false) { + return MacosColors.black; + } + + return MacosColors.white; + } + @override Widget build(BuildContext context) { final icon = value == false ? null : isMixed - ? CupertinoIcons.minus - : CupertinoIcons.checkmark; + ? CupertinoIcons.minus + : CupertinoIcons.checkmark; return Stack( children: [ - _InnerDropShadow( - value: value, - isEnabled: !isDisabled, - ), + _InnerDropShadow(value: value, isEnabled: !isDisabled), Center( child: Icon( icon, @@ -216,24 +232,6 @@ class _CheckboxStack extends StatelessWidget { ], ); } - - _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. @@ -245,10 +243,7 @@ class _InnerDropShadow extends StatelessWidget { final bool isEnabled; /// Creates a widget that paints an inner drop shadow for a checkbox. - const _InnerDropShadow({ - required this.value, - required this.isEnabled, - }); + const _InnerDropShadow({required this.value, required this.isEnabled}); @override Widget build(BuildContext context) { @@ -310,10 +305,7 @@ class _BoxDecorationBuilder { MacosColor.fromRGBO(74, 74, 74, 1.0 * isEnabledFactor), MacosColor.fromRGBO(101, 101, 101, 1.0 * isEnabledFactor), ] - : const [ - MacosColors.transparent, - MacosColors.transparent, - ]; + : const [MacosColors.transparent, MacosColors.transparent]; } if (isDarkModeEnabled) { @@ -365,9 +357,6 @@ class _BoxDecorationBuilder { MacosColor.fromRGBO(148, 148, 148, 1.0 * isEnabledFactor), MacosColor.fromRGBO(148, 148, 148, 1.0 * isEnabledFactor), ]; - - default: - throw UnimplementedError(); } } else { switch (accentColor) { @@ -418,9 +407,6 @@ class _BoxDecorationBuilder { MacosColor.fromRGBO(86, 86, 86, 1.0 * isEnabledFactor), MacosColor.fromRGBO(55, 55, 55, 1.0 * isEnabledFactor), ]; - - default: - throw UnimplementedError(); } } } @@ -443,7 +429,7 @@ class _BoxDecorationBuilder { spreadRadius: -0.5, offset: Offset(0.0, 0.5), blurStyle: BlurStyle.outer, - ) + ), ] : const []; diff --git a/lib/src/buttons/disclosure_button.dart b/lib/src/buttons/disclosure_button.dart index 5cef6e0e..6f8a9bee 100644 --- a/lib/src/buttons/disclosure_button.dart +++ b/lib/src/buttons/disclosure_button.dart @@ -44,11 +44,9 @@ class MacosDisclosureButton extends StatefulWidget { properties.add(ColorProperty('fillColor', fillColor)); properties.add(ColorProperty('hoverColor', fillColor)); properties.add(StringProperty('semanticLabel', semanticLabel)); - properties.add(FlagProperty( - 'enabled', - value: enabled, - ifFalse: 'disabled', - )); + properties.add( + FlagProperty('enabled', value: enabled, ifFalse: 'disabled'), + ); } @override @@ -161,10 +159,7 @@ class MacosDisclosureButtonState extends State child: Semantics( button: true, child: ConstrainedBox( - constraints: const BoxConstraints( - minWidth: 20, - minHeight: 20, - ), + constraints: const BoxConstraints(minWidth: 20, minHeight: 20), child: FadeTransition( opacity: _opacityAnimation, child: AnimatedBuilder( @@ -174,8 +169,8 @@ class MacosDisclosureButtonState extends State decoration: BoxDecoration( color: buttonHeldDown ? brightness == Brightness.dark - ? const MacosColor(0xff3C383C) - : const MacosColor(0xffE5E5E5) + ? const MacosColor(0xff3C383C) + : const MacosColor(0xffE5E5E5) : fillColor, borderRadius: const BorderRadius.all(Radius.circular(7)), ), diff --git a/lib/src/buttons/help_button.dart b/lib/src/buttons/help_button.dart index f825baf5..4a269a6a 100644 --- a/lib/src/buttons/help_button.dart +++ b/lib/src/buttons/help_button.dart @@ -20,8 +20,10 @@ class HelpButton extends StatefulWidget { this.alignment = Alignment.center, this.semanticLabel, this.mouseCursor = SystemMouseCursors.basic, - }) : assert(pressedOpacity == null || - (pressedOpacity >= 0.0 && pressedOpacity <= 1.0)); + }) : assert( + pressedOpacity == null || + (pressedOpacity >= 0.0 && pressedOpacity <= 1.0), + ); /// The color of the button's background. final Color? color; @@ -172,8 +174,8 @@ class HelpButtonState extends State final Color foregroundColor = widget.enabled ? helpIconLuminance(backgroundColor, theme.brightness.isDark) : theme.brightness.isDark - ? const Color.fromRGBO(255, 255, 255, 0.25) - : const Color.fromRGBO(0, 0, 0, 0.25); + ? const Color.fromRGBO(255, 255, 255, 0.25) + : const Color.fromRGBO(0, 0, 0, 0.25); return MouseRegion( cursor: widget.mouseCursor!, diff --git a/lib/src/buttons/icon_button.dart b/lib/src/buttons/icon_button.dart index 88e8ef20..7a7379b1 100644 --- a/lib/src/buttons/icon_button.dart +++ b/lib/src/buttons/icon_button.dart @@ -25,8 +25,10 @@ class MacosIconButton extends StatefulWidget { ), this.padding, this.mouseCursor = SystemMouseCursors.basic, - }) : assert(pressedOpacity == null || - (pressedOpacity >= 0.0 && pressedOpacity <= 1.0)); + }) : assert( + pressedOpacity == null || + (pressedOpacity >= 0.0 && pressedOpacity <= 1.0), + ); /// The widget to use as the icon. /// @@ -215,10 +217,7 @@ class MacosIconButtonState extends State final Color? disabledColor; if (widget.disabledColor != null) { - disabledColor = MacosDynamicColor.resolve( - widget.disabledColor!, - context, - ); + disabledColor = MacosDynamicColor.resolve(widget.disabledColor!, context); } else { disabledColor = theme.disabledColor; } @@ -253,13 +252,13 @@ class MacosIconButtonState extends State borderRadius: widget.borderRadius != null ? widget.borderRadius : widget.shape == BoxShape.rectangle - ? const BorderRadius.all(Radius.circular(7)) - : null, + ? const BorderRadius.all(Radius.circular(7)) + : null, color: !enabled ? disabledColor : _isHovered - ? hoverColor - : backgroundColor, + ? hoverColor + : backgroundColor, ), child: Padding( padding: padding, @@ -267,10 +266,7 @@ class MacosIconButtonState extends State alignment: widget.alignment, widthFactor: 1.0, heightFactor: 1.0, - child: FittedBox( - fit: BoxFit.scaleDown, - child: widget.icon, - ), + child: FittedBox(fit: BoxFit.scaleDown, child: widget.icon), ), ), ), diff --git a/lib/src/buttons/popup_button.dart b/lib/src/buttons/popup_button.dart index 8082f78c..e862d9c5 100644 --- a/lib/src/buttons/popup_button.dart +++ b/lib/src/buttons/popup_button.dart @@ -45,23 +45,36 @@ class _MacosPopupMenuItemButton extends StatefulWidget { class _MacosPopupMenuItemButtonState extends State<_MacosPopupMenuItemButton> { - bool _isHovered = false; + final _focusNode = FocusNode(); + + bool _isFocused = false; + + bool get _isHighlighted => _isFocused; + + /// The last time the mouse entered this item. + static DateTime _lastMouseEnterTime = DateTime.now(); + + /// The last time the focus changed that wasnโ€™t caused by the mouse. + static DateTime _lastNonMouseFocusChange = DateTime.now(); void _handleFocusChange(bool focused) { if (focused) { - final _MenuLimits menuLimits = widget.route.getMenuLimits( - widget.buttonRect, - widget.constraints.maxHeight, - widget.itemIndex, - ); - widget.route.scrollController!.animateTo( - menuLimits.scrollOffset, - curve: Curves.easeInOut, - duration: const Duration(milliseconds: 100), + final timeSinceMouseEnter = DateTime.now().difference( + _lastMouseEnterTime, ); - setState(() => _isHovered = true); + if (timeSinceMouseEnter > const Duration(milliseconds: 50)) { + _lastNonMouseFocusChange = DateTime.now(); + + final _MenuLimits menuLimits = widget.route.getMenuLimits( + widget.buttonRect, + widget.constraints.maxHeight, + widget.itemIndex, + ); + widget.route.scrollController!.jumpTo(menuLimits.scrollOffset); + } + setState(() => _isFocused = true); } else { - setState(() => _isHovered = false); + setState(() => _isFocused = false); } } @@ -71,10 +84,7 @@ class _MacosPopupMenuItemButtonState popupMenuItem.onTap?.call(); - Navigator.pop( - context, - _MacosPopupRouteResult(popupMenuItem.value), - ); + Navigator.pop(context, _MacosPopupRouteResult(popupMenuItem.value)); } @override @@ -91,14 +101,21 @@ class _MacosPopupMenuItemButtonState child = MouseRegion( cursor: SystemMouseCursors.basic, onEnter: (_) { - setState(() => _isHovered = true); - }, - onExit: (_) { - setState(() => _isHovered = false); + final timeSinceLastNonMouseFocusChange = DateTime.now().difference( + _lastNonMouseFocusChange, + ); + if (timeSinceLastNonMouseFocusChange < + const Duration(milliseconds: 200)) { + return; + } + + _lastMouseEnterTime = DateTime.now(); + FocusScope.of(context).requestFocus(_focusNode); }, child: GestureDetector( onTap: _handleOnTap, child: Focus( + focusNode: _focusNode, onKeyEvent: (FocusNode node, KeyEvent event) { if (event.logicalKey == LogicalKeyboardKey.enter) { _handleOnTap(); @@ -110,7 +127,7 @@ class _MacosPopupMenuItemButtonState autofocus: widget.itemIndex == widget.route.selectedIndex, child: Container( decoration: BoxDecoration( - color: _isHovered + color: _isHighlighted ? MacosPopupButtonTheme.of(context).highlightColor : Colors.transparent, borderRadius: _kBorderRadius, @@ -123,7 +140,7 @@ class _MacosPopupMenuItemButtonState child: MacosIcon( CupertinoIcons.checkmark_alt, size: 16.0, - color: _isHovered + color: _isHighlighted ? MacosColors.white : brightness.resolve( MacosColors.black, @@ -135,7 +152,7 @@ class _MacosPopupMenuItemButtonState DefaultTextStyle( style: TextStyle( fontSize: 13.0, - color: _isHovered + color: _isHighlighted ? MacosColors.white : brightness.resolve( MacosColors.black, @@ -218,8 +235,10 @@ class _MacosPopupMenuState extends State<_MacosPopupMenu> { widget.popupColor ?? MacosPopupButtonTheme.of(context).popupColor, context, ); - final caretColor = - brightness.resolve(CupertinoColors.black, CupertinoColors.white); + final caretColor = brightness.resolve( + CupertinoColors.black, + CupertinoColors.white, + ); final itemsList = ListView.builder( controller: widget.route.scrollController, @@ -252,16 +271,16 @@ class _MacosPopupMenuState extends State<_MacosPopupMenu> { setState(() { _showTopCaret = widget.route.scrollController!.position.extentBefore > - widget.buttonRect.height; + widget.buttonRect.height; _showBottomCaret = widget.route.scrollController!.position.extentAfter > - widget.buttonRect.height; + widget.buttonRect.height; }); } return true; }, child: MacosOverlayFilter( - color: popupColor?.withOpacity(0.25), + color: popupColor?.withValues(alpha: 0.25), borderRadius: _kBorderRadius, child: Column( mainAxisSize: MainAxisSize.min, @@ -286,9 +305,7 @@ class _MacosPopupMenuState extends State<_MacosPopupMenu> { // Wrap the items list with an Expanded widget for to // avoid height overflow when having a lot of items. _showTopCaret || _showBottomCaret - ? Expanded( - child: itemsList, - ) + ? Expanded(child: itemsList) : itemsList, _showBottomCaret ? Container( @@ -334,8 +351,10 @@ class _MacosPopupMenuRouteLayout extends SingleChildLayoutDelegate { // The maximum height of a simple menu should be one or more rows less than // the view height. This ensures a tappable area outside of the simple menu // with which to dismiss the menu. - double maxHeight = - math.max(0.0, constraints.maxHeight - 2 * _kMenuItemHeight); + double maxHeight = math.max( + 0.0, + constraints.maxHeight - 2 * _kMenuItemHeight, + ); if (route.menuMaxHeight != null && route.menuMaxHeight! <= maxHeight) { maxHeight = route.menuMaxHeight!; } @@ -351,8 +370,11 @@ class _MacosPopupMenuRouteLayout extends SingleChildLayoutDelegate { @override Offset getPositionForChild(Size size, Size childSize) { - final _MenuLimits menuLimits = - route.getMenuLimits(buttonRect, size.height, route.selectedIndex); + final _MenuLimits menuLimits = route.getMenuLimits( + buttonRect, + size.height, + route.selectedIndex, + ); assert(() { final Rect container = Offset.zero & size; @@ -434,9 +456,9 @@ class _MacosPopupRoute extends PopupRoute<_MacosPopupRouteResult> { this.popupColor, this.menuMaxHeight, }) : itemHeights = List.filled( - items.length, - itemHeight ?? _kMinInteractiveDimension, - ); + items.length, + itemHeight ?? _kMinInteractiveDimension, + ); final List<_MenuItem> items; final EdgeInsetsGeometry padding; @@ -525,15 +547,19 @@ class _MacosPopupRoute extends PopupRoute<_MacosPopupRouteResult> { // In this case, we want to change the menu limits to align with the top // or bottom edge of the button. final double topLimit = math.min(_kMenuItemHeight, buttonTop); - final double bottomLimit = - math.max(availableHeight - _kMenuItemHeight, buttonBottom); + final double bottomLimit = math.max( + availableHeight - _kMenuItemHeight, + buttonBottom, + ); - double menuTop = (buttonTop - selectedItemOffset) - + double menuTop = + (buttonTop - selectedItemOffset) - (itemHeights[selectedIndex] - buttonRect.height) / 2.0; double preferredMenuHeight = 8.0; if (items.isNotEmpty) { - preferredMenuHeight += - itemHeights.reduce((double total, double height) => total + height); + preferredMenuHeight += itemHeights.reduce( + (double total, double height) => total + height, + ); } // If there are too many elements in the menu, we need to shrink it down @@ -558,7 +584,8 @@ class _MacosPopupRoute extends PopupRoute<_MacosPopupRouteResult> { if (menuBottom - itemHeights[selectedIndex] / 2.0 < buttonBottom - buttonRect.height / 2.0) { - menuBottom = buttonBottom - + menuBottom = + buttonBottom - buttonRect.height / 2.0 + itemHeights[selectedIndex] / 2.0; menuTop = menuBottom - menuHeight; @@ -579,9 +606,11 @@ class _MacosPopupRoute extends PopupRoute<_MacosPopupRouteResult> { // set it instead to the maximum allowed scroll offset. scrollOffset = math.min(scrollOffset, preferredMenuHeight - menuHeight); } - bool hasTopItemsNotShown = preferredMenuHeight > computedMaxHeight && + bool hasTopItemsNotShown = + preferredMenuHeight > computedMaxHeight && scrollOffset > buttonRect.height / 2.0; - bool hasBottomItemsNotShown = preferredMenuHeight > computedMaxHeight && + bool hasBottomItemsNotShown = + preferredMenuHeight > computedMaxHeight && scrollOffset < buttonRect.height / 2.0; assert((menuBottom - menuTop - menuHeight).abs() < precisionErrorTolerance); @@ -630,10 +659,14 @@ class _MacosPopupRoutePage extends StatelessWidget { // and all of the items' intrinsic heights are less than _kMinInteractiveDimension. // Otherwise the initialScrollOffset is just a rough approximation based on // treating the items as if their heights were all equal to _kMinInteractiveDimension. - final _MenuLimits menuLimits = - route.getMenuLimits(buttonRect, constraints.maxHeight, selectedIndex); - route.scrollController ??= - ScrollController(initialScrollOffset: menuLimits.scrollOffset); + final _MenuLimits menuLimits = route.getMenuLimits( + buttonRect, + constraints.maxHeight, + selectedIndex, + ); + route.scrollController ??= ScrollController( + initialScrollOffset: menuLimits.scrollOffset, + ); final TextDirection? textDirection = Directionality.maybeOf(context); final Widget menu = _MacosPopupMenu( @@ -674,11 +707,8 @@ class _MacosPopupRoutePage extends StatelessWidget { // selected item lines up with the vertical center of the popup button, // as closely as possible. class _MenuItem extends SingleChildRenderObjectWidget { - const _MenuItem({ - super.key, - required this.onLayout, - required this.item, - }) : super(child: item); + const _MenuItem({super.key, required this.onLayout, required this.item}) + : super(child: item); final ValueChanged onLayout; final MacosPopupMenuItem? item; @@ -844,20 +874,20 @@ class MacosPopupButton extends StatefulWidget { this.popupColor, this.menuMaxHeight, this.alignment = AlignmentDirectional.centerStart, - }) : assert( - items == null || - items.isEmpty || - value == null || - items.where((MacosPopupMenuItem item) { - return item.value == value; - }).length == - 1, - "There should be exactly one item with [MacosPopupButton]'s value: " - '$value. \n' - 'Either zero or 2 or more [MacosPopupMenuItem]s were detected ' - 'with the same value', - ), - assert(itemHeight == null || itemHeight >= _kMinInteractiveDimension); + }) : assert( + items == null || + items.isEmpty || + value == null || + items.where((MacosPopupMenuItem item) { + return item.value == value; + }).length == + 1, + "There should be exactly one item with [MacosPopupButton]'s value: " + '$value. \n' + 'Either zero or 2 or more [MacosPopupMenuItem]s were detected ' + 'with the same value', + ), + assert(itemHeight == null || itemHeight >= _kMinInteractiveDimension); /// The list of items the user can select. /// @@ -980,11 +1010,13 @@ class MacosPopupButton extends StatefulWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DoubleProperty( - 'itemHeight', - itemHeight, - defaultValue: kMinInteractiveDimension, - )); + properties.add( + DoubleProperty( + 'itemHeight', + itemHeight, + defaultValue: kMinInteractiveDimension, + ), + ); properties.add( FlagProperty('hasAutofocus', value: autofocus, ifFalse: 'noAutofocus'), ); @@ -1070,17 +1102,21 @@ class _MacosPopupButtonState extends State> widget.items!.isEmpty || (widget.value == null && widget.items! - .where((MacosPopupMenuItem item) => - item.enabled && item.value == widget.value) + .where( + (MacosPopupMenuItem item) => + item.enabled && item.value == widget.value, + ) .isEmpty)) { _selectedIndex = null; return; } - assert(widget.items! - .where((MacosPopupMenuItem item) => item.value == widget.value) - .length == - 1); + assert( + widget.items! + .where((MacosPopupMenuItem item) => item.value == widget.value) + .length == + 1, + ); for (int itemIndex = 0; itemIndex < widget.items!.length; itemIndex++) { if (widget.items![itemIndex].value == widget.value) { _selectedIndex = itemIndex; @@ -1116,7 +1152,8 @@ class _MacosPopupButtonState extends State> final NavigatorState navigator = Navigator.of(context); assert(_popupRoute == null); final RenderBox itemBox = context.findRenderObject()! as RenderBox; - final Rect itemRect = itemBox.localToGlobal( + final Rect itemRect = + itemBox.localToGlobal( _kPopupRouteOffset, ancestor: navigator.context.findRenderObject(), ) & @@ -1126,8 +1163,10 @@ class _MacosPopupButtonState extends State> buttonRect: menuMargin.resolve(textDirection).inflateRect(itemRect), padding: _kMenuItemPadding.resolve(textDirection), selectedIndex: _selectedIndex ?? 0, - capturedThemes: - InheritedTheme.capture(from: context, to: navigator.context), + capturedThemes: InheritedTheme.capture( + from: context, + to: navigator.context, + ), style: _textStyle!, barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, itemHeight: widget.itemHeight, @@ -1135,9 +1174,9 @@ class _MacosPopupButtonState extends State> menuMaxHeight: widget.menuMaxHeight, ); - navigator - .push(_popupRoute!) - .then((_MacosPopupRouteResult? newValue) { + navigator.push(_popupRoute!).then(( + _MacosPopupRouteResult? newValue, + ) { _removeMacosPopupRoute(); if (!mounted || newValue == null) return; widget.onChanged?.call(newValue.result); @@ -1150,8 +1189,9 @@ class _MacosPopupButtonState extends State> void dispose() { WidgetsBinding.instance.removeObserver(this); _removeMacosPopupRoute(); - WidgetsBinding.instance.focusManager - .removeHighlightModeListener(_handleFocusHighlightModeChange); + WidgetsBinding.instance.focusManager.removeHighlightModeListener( + _handleFocusHighlightModeChange, + ); focusNode!.removeListener(_handleFocusChanged); _internalNode?.dispose(); super.dispose(); @@ -1187,20 +1227,15 @@ class _MacosPopupButtonState extends State> int? hintIndex; if (widget.hint != null || (!_enabled && widget.disabledHint != null)) { - Widget displayedHint = - _enabled ? widget.hint! : widget.disabledHint ?? widget.hint!; + Widget displayedHint = _enabled + ? widget.hint! + : widget.disabledHint ?? widget.hint!; if (widget.selectedItemBuilder == null) { displayedHint = _MacosPopupMenuItemContainer(child: displayedHint); } hintIndex = items.length; - items.add( - ExcludeSemantics( - child: IgnorePointer( - child: displayedHint, - ), - ), - ); + items.add(ExcludeSemantics(child: IgnorePointer(child: displayedHint))); } // If value is null (then _selectedIndex is null) then we @@ -1228,9 +1263,7 @@ class _MacosPopupButtonState extends State> ); Widget result = DefaultTextStyle( - style: _textStyle!.copyWith( - color: buttonStyles.textColor, - ), + style: _textStyle!.copyWith(color: buttonStyles.textColor), child: Container( decoration: _showHighlight ? const BoxDecoration( @@ -1247,10 +1280,7 @@ class _MacosPopupButtonState extends State> ), ], color: buttonStyles.bgColor, - border: Border.all( - width: 0.5, - color: buttonStyles.borderColor, - ), + border: Border.all(width: 0.5, color: buttonStyles.borderColor), borderRadius: _kBorderRadius, ), padding: const EdgeInsets.only(left: 8.0, right: 2.0), @@ -1302,10 +1332,7 @@ class _MacosPopupButtonState extends State> // We use this utility function to get the appropriate styling, according to the // macOS Design Guidelines and the current MacosPopupButtonTheme. -_ButtonStyles _getButtonStyles( - bool enabled, - BuildContext context, -) { +_ButtonStyles _getButtonStyles(bool enabled, BuildContext context) { final theme = MacosTheme.of(context); final brightness = theme.brightness; final popupTheme = MacosPopupButtonTheme.of(context); @@ -1380,7 +1407,9 @@ class _UpDownCaretsPainter extends CustomPainter { /// Draw background canvas.drawRRect( - BorderRadius.circular(radius).toRRect(Offset.zero & size), + const BorderRadius.all( + Radius.circular(radius), + ).toRRect(Offset.zero & size), Paint()..color = backgroundColor, ); diff --git a/lib/src/buttons/pulldown_button.dart b/lib/src/buttons/pulldown_button.dart index 37c0e7d1..e0055c25 100644 --- a/lib/src/buttons/pulldown_button.dart +++ b/lib/src/buttons/pulldown_button.dart @@ -6,11 +6,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:macos_ui/macos_ui.dart'; -enum PulldownButtonState { - enabled, - hovered, - pressed, -} +enum PulldownButtonState { enabled, hovered, pressed } const Duration _kMenuDuration = Duration(milliseconds: 300); const double _kMenuItemHeight = 20.0; @@ -19,10 +15,7 @@ const EdgeInsets _kMenuItemPadding = EdgeInsets.symmetric(horizontal: 6.0); const BorderRadius _kBorderRadius = BorderRadius.all(Radius.circular(5.0)); const double _kMenuLeftOffset = 8.0; -enum PulldownMenuAlignment { - left, - right, -} +enum PulldownMenuAlignment { left, right } // The widget that is the button wrapping the menu items. class _MacosPulldownMenuItemButton extends StatefulWidget { @@ -65,8 +58,8 @@ class _MacosPulldownMenuItemButtonState final MacosPulldownMenuEntry menuEntity = widget.route.items[widget.itemIndex].item!; if (menuEntity is MacosPulldownMenuItem) { + Navigator.of(context).pop(); menuEntity.onTap?.call(); - Navigator.pop(context); } } @@ -200,9 +193,9 @@ class _MacosPulldownMenuState extends State<_MacosPulldownMenu> { explicitChildNodes: true, child: IntrinsicWidth( child: MacosOverlayFilter( - color: MacosPulldownButtonTheme.of(context) - .pulldownColor - ?.withOpacity(0.25), + color: MacosPulldownButtonTheme.of( + context, + ).pulldownColor?.withValues(alpha: 0.25), borderRadius: _kBorderRadius, child: Padding( padding: const EdgeInsets.all(6.0), @@ -294,11 +287,7 @@ class _MacosPulldownMenuRouteLayout extends SingleChildLayoutDelegate { } class _MenuLimits { - const _MenuLimits( - this.top, - this.bottom, - this.height, - ); + const _MenuLimits(this.top, this.bottom, this.height); final double top; final double bottom; final double height; @@ -315,9 +304,9 @@ class _MacosPulldownRoute extends PopupRoute { this.itemHeight, required this.menuAlignment, }) : itemHeights = List.filled( - items.length, - itemHeight ?? _kMenuItemHeight, - ); + items.length, + itemHeight ?? _kMenuItemHeight, + ); final List<_MenuItem> items; final EdgeInsetsGeometry padding; @@ -368,10 +357,7 @@ class _MacosPulldownRoute extends PopupRoute { } } - _MenuLimits getMenuLimits( - Rect buttonRect, - double availableHeight, - ) { + _MenuLimits getMenuLimits(Rect buttonRect, double availableHeight) { double computedMaxHeight = availableHeight - 2.0 * _kMenuItemHeight; final double buttonTop = buttonRect.top; @@ -381,14 +367,17 @@ class _MacosPulldownRoute extends PopupRoute { // bottom may be less than [_kMenuItemHeight] from the edge of the screen. // In this case, we want to change the menu limits to align with the top // or bottom edge of the button. - final double bottomLimit = - math.max(availableHeight - _kMenuItemHeight, buttonBottom); + final double bottomLimit = math.max( + availableHeight - _kMenuItemHeight, + buttonBottom, + ); double menuTop = buttonTop + buttonRect.height; double preferredMenuHeight = 8.0; if (items.isNotEmpty) { - preferredMenuHeight += - itemHeights.reduce((double total, double height) => total + height); + preferredMenuHeight += itemHeights.reduce( + (double total, double height) => total + height, + ); } // If there are too many elements in the menu, we need to shrink it down @@ -406,11 +395,7 @@ class _MacosPulldownRoute extends PopupRoute { } assert((menuBottom - menuTop - menuHeight).abs() < precisionErrorTolerance); - return _MenuLimits( - menuTop, - menuBottom, - menuHeight, - ); + return _MenuLimits(menuTop, menuBottom, menuHeight); } } @@ -476,11 +461,8 @@ class _MacosPulldownRoutePage extends StatelessWidget { // each menu item. class _MenuItem extends SingleChildRenderObjectWidget { // ignore: use_super_parameters - const _MenuItem({ - Key? key, - required this.onLayout, - this.item, - }) : super(key: key, child: item); + const _MenuItem({Key? key, required this.onLayout, this.item}) + : super(key: key, child: item); final ValueChanged onLayout; @@ -538,9 +520,9 @@ class MacosPulldownMenuDivider extends StatelessWidget alignment: Alignment.centerLeft, child: Container( color: MacosTheme.of(context).brightness.resolve( - MacosColors.disabledControlTextColor, - MacosColors.disabledControlTextColor.darkColor, - ), + MacosColors.disabledControlTextColor, + MacosColors.disabledControlTextColor.darkColor, + ), height: 0.5, ), ), @@ -642,10 +624,11 @@ class MacosPulldownButton extends StatefulWidget { this.autofocus = false, this.alignment = AlignmentDirectional.centerStart, this.menuAlignment = PulldownMenuAlignment.left, - }) : assert(itemHeight == null || itemHeight >= _kMenuItemHeight), - assert( - (title != null || icon != null) && !(title != null && icon != null), - "There should be either a title or an icon argument provided, and not both at at the same time."); + }) : assert(itemHeight == null || itemHeight >= _kMenuItemHeight), + assert( + (title != null || icon != null) && !(title != null && icon != null), + "There should be either a title or an icon argument provided, and not both at at the same time.", + ); /// The list of menu entries for the pull-down menu. /// @@ -721,10 +704,7 @@ class MacosPulldownButton extends StatefulWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DoubleProperty( - 'itemHeight', - itemHeight, - )); + properties.add(DoubleProperty('itemHeight', itemHeight)); properties.add( FlagProperty('hasAutofocus', value: autofocus, ifFalse: 'noAutofocus'), ); @@ -834,7 +814,8 @@ class _MacosPulldownButtonState extends State final NavigatorState navigator = Navigator.of(context); assert(_pulldownRoute == null); final RenderBox itemBox = context.findRenderObject()! as RenderBox; - final Rect itemRect = itemBox.localToGlobal( + final Rect itemRect = + itemBox.localToGlobal( Offset.zero, ancestor: navigator.context.findRenderObject(), ) & @@ -843,8 +824,10 @@ class _MacosPulldownButtonState extends State items: menuItems, buttonRect: menuMargin.resolve(textDirection).inflateRect(itemRect), padding: _kMenuItemPadding.resolve(textDirection), - capturedThemes: - InheritedTheme.capture(from: context, to: navigator.context), + capturedThemes: InheritedTheme.capture( + from: context, + to: navigator.context, + ), style: _textStyle!, barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, itemHeight: widget.itemHeight, @@ -852,9 +835,9 @@ class _MacosPulldownButtonState extends State ); navigator.push(_pulldownRoute!).then((_) { + if (!mounted) return; setState(() => _pullDownButtonState = PulldownButtonState.enabled); _removeMacosPulldownRoute(); - if (!mounted) return; }); widget.onTap?.call(); @@ -877,8 +860,9 @@ class _MacosPulldownButtonState extends State void dispose() { WidgetsBinding.instance.removeObserver(this); _removeMacosPulldownRoute(); - WidgetsBinding.instance.focusManager - .removeHighlightModeListener(_handleFocusHighlightModeChange); + WidgetsBinding.instance.focusManager.removeHighlightModeListener( + _handleFocusHighlightModeChange, + ); focusNode!.removeListener(_handleFocusChanged); _internalNode?.dispose(); super.dispose(); @@ -890,8 +874,12 @@ class _MacosPulldownButtonState extends State final borderRadius = _hasIcon ? const BorderRadius.all(Radius.circular(7.0)) : _kBorderRadius; - final buttonStyles = - _getButtonStyles(_pullDownButtonState, _enabled, _hasIcon, context); + final buttonStyles = _getButtonStyles( + _pullDownButtonState, + _enabled, + _hasIcon, + context, + ); Widget result = Container( decoration: _showHighlight @@ -921,14 +909,14 @@ class _MacosPulldownButtonState extends State _hasIcon ? MacosIcon(widget.icon!, color: buttonStyles.textColor) : _enabled - ? Text( - widget.title!, - style: TextStyle(color: buttonStyles.textColor), - ) - : Text( - widget.disabledTitle ?? widget.title!, - style: TextStyle(color: buttonStyles.textColor), - ), + ? Text( + widget.title!, + style: TextStyle(color: buttonStyles.textColor), + ) + : Text( + widget.disabledTitle ?? widget.title!, + style: TextStyle(color: buttonStyles.textColor), + ), Padding( padding: EdgeInsets.only(left: _hasIcon ? 2.0 : 8.0), child: SizedBox( @@ -1042,7 +1030,7 @@ _ButtonStyles _getButtonStyles( ); break; case PulldownButtonState.pressed: - textColor = caretColor = iconColor.withOpacity(0.85); + textColor = caretColor = iconColor.withValues(alpha: 0.85); bgColor = brightness.resolve( const Color.fromRGBO(0, 0, 0, 0.1), const Color.fromRGBO(255, 255, 255, 0.1), @@ -1061,8 +1049,8 @@ _ButtonStyles _getButtonStyles( case PulldownButtonState.hovered: break; case PulldownButtonState.pressed: - bgColor = pulldownTheme.backgroundColor!.withOpacity(0.4); - caretBgColor = pulldownTheme.highlightColor!.withOpacity(0.9); + bgColor = pulldownTheme.backgroundColor!.withValues(alpha: 0.4); + caretBgColor = pulldownTheme.highlightColor!.withValues(alpha: 0.9); break; } } @@ -1093,10 +1081,7 @@ class _ButtonStyles { } class _DownCaretPainter extends CustomPainter { - const _DownCaretPainter({ - required this.color, - required this.backgroundColor, - }); + const _DownCaretPainter({required this.color, required this.backgroundColor}); final Color color; final Color backgroundColor; @@ -1108,7 +1093,9 @@ class _DownCaretPainter extends CustomPainter { /// Draw background canvas.drawRRect( - BorderRadius.circular(radius).toRRect(Offset.zero & size), + const BorderRadius.all( + Radius.circular(radius), + ).toRRect(Offset.zero & size), Paint()..color = backgroundColor, ); diff --git a/lib/src/buttons/push_button.dart b/lib/src/buttons/push_button.dart index e95a9857..e66d29e2 100644 --- a/lib/src/buttons/push_button.dart +++ b/lib/src/buttons/push_button.dart @@ -130,8 +130,10 @@ class PushButton extends StatefulWidget { this.semanticLabel, this.mouseCursor = SystemMouseCursors.basic, this.secondary, - }) : assert(pressedOpacity == null || - (pressedOpacity >= 0.0 && pressedOpacity <= 1.0)); + }) : assert( + pressedOpacity == null || + (pressedOpacity >= 0.0 && pressedOpacity <= 1.0), + ); /// The widget below this widget in the tree. /// @@ -170,9 +172,11 @@ class PushButton extends StatefulWidget { /// /// This defaults to 0.4. If null, opacity will not change on pressed if using /// your own custom effects is desired. - @Deprecated("'PushButton' animations now match their native macOSโ€™ " - "counterparts. Therefore, its opacity no longer changes when it is " - "pressed.") + @Deprecated( + "'PushButton' animations now match their native macOSโ€™ " + "counterparts. Therefore, its opacity no longer changes when it is " + "pressed.", + ) final double? pressedOpacity; /// The radius of the button's corners when it has a background color. @@ -215,11 +219,9 @@ class PushButton extends StatefulWidget { properties.add(DiagnosticsProperty('alignment', alignment)); properties.add(StringProperty('semanticLabel', semanticLabel)); properties.add(DiagnosticsProperty('borderRadius', borderRadius)); - properties.add(FlagProperty( - 'enabled', - value: enabled, - ifFalse: 'disabled', - )); + properties.add( + FlagProperty('enabled', value: enabled, ifFalse: 'disabled'), + ); properties.add(DiagnosticsProperty('secondary', secondary)); } @@ -298,12 +300,12 @@ class PushButtonState extends State final blendedBackgroundColor = Color.lerp( theme.canvasColor, backgroundColor, - backgroundColor.opacity, + backgroundColor.a, )!; return widget.enabled ? textLuminance(blendedBackgroundColor) - : textLuminance(blendedBackgroundColor).withOpacity(0.25); + : textLuminance(blendedBackgroundColor).withValues(alpha: 0.25); } BoxDecoration _getClickEffectBoxDecoration() { @@ -347,11 +349,13 @@ class PushButtonState extends State builder: (context, _) { final Color backgroundColor = _getBackgroundColor(); - final Color foregroundColor = - _getForegroundColor(backgroundColor); + final Color foregroundColor = _getForegroundColor( + backgroundColor, + ); - final baseStyle = - theme.typography.body.copyWith(color: foregroundColor); + final baseStyle = theme.typography.body.copyWith( + color: foregroundColor, + ); return DecoratedBox( decoration: _getBoxDecoration().copyWith( @@ -458,9 +462,6 @@ class _BoxDecorationBuilder { MacosColor.fromRGBO(64, 64, 64, 1.0 * isEnabledFactor), MacosColor.fromRGBO(57, 57, 57, 1.0 * isEnabledFactor), ]; - - default: - throw UnimplementedError(); } } else { switch (accentColor) { @@ -511,9 +512,6 @@ class _BoxDecorationBuilder { MacosColor.fromRGBO(86, 86, 86, 1.0 * isEnabledFactor), MacosColor.fromRGBO(55, 55, 55, 1.0 * isEnabledFactor), ]; - - default: - throw UnimplementedError(); } } } @@ -649,9 +647,6 @@ class _BoxDecorationBuilder { blurStyle: isEnabled ? BlurStyle.normal : BlurStyle.outer, ), ]; - - default: - throw UnimplementedError(); } } } diff --git a/lib/src/buttons/radio_button.dart b/lib/src/buttons/radio_button.dart index eda3de26..b65c2ef7 100644 --- a/lib/src/buttons/radio_button.dart +++ b/lib/src/buttons/radio_button.dart @@ -28,7 +28,7 @@ class MacosRadioButton extends StatelessWidget { /// Whether the button is checked or not final T value; -// The currently selected value for a group of radio buttons. + // The currently selected value for a group of radio buttons. /// /// This radio button is considered selected if its [value] matches the /// [groupValue]. @@ -73,11 +73,9 @@ class MacosRadioButton extends StatelessWidget { // 'state', // value ? 'checked' : 'unchecked', // )); - properties.add(FlagProperty( - 'disabled', - value: isDisabled, - ifFalse: 'enabled', - )); + properties.add( + FlagProperty('disabled', value: isDisabled, ifFalse: 'enabled'), + ); properties.add(DoubleProperty('size', size)); properties.add(ColorProperty('onColor', onColor)); properties.add(ColorProperty('offColor', offColor)); @@ -119,8 +117,8 @@ class MacosRadioButton extends StatelessWidget { (isDisabled ? CupertinoColors.quaternarySystemFill : selected || isLight - ? CupertinoColors.white - : CupertinoColors.tertiarySystemFill), + ? CupertinoColors.white + : CupertinoColors.tertiarySystemFill), context, ), boxShadow: const [ diff --git a/lib/src/buttons/segmented_control.dart b/lib/src/buttons/segmented_control.dart index 45f36539..71aec8d0 100644 --- a/lib/src/buttons/segmented_control.dart +++ b/lib/src/buttons/segmented_control.dart @@ -58,58 +58,61 @@ class _MacosSegmentedControlState extends State { spreadRadius: 0.5, ), ], - borderRadius: const BorderRadius.all( - Radius.circular(5.0), - ), + borderRadius: const BorderRadius.all(Radius.circular(5.0)), ), child: Padding( padding: const EdgeInsets.all(0.5), child: IntrinsicHeight( child: IntrinsicWidth( child: Row( - children: widget.tabs.map((t) { - final row = Row( - children: [ - GestureDetector( - onTap: () { - setState(() { - widget.controller.index = widget.tabs.indexOf(t); - }); - }, - child: t.copyWith( - active: - widget.controller.index == widget.tabs.indexOf(t), - ), - ), - ], - ); - bool showDividerColor = true; - final last = widget.tabs.indexOf(t) == widget.tabs.length - 1; - if ((widget.controller.index - 1 == widget.tabs.indexOf(t)) || - (widget.controller.index + 1 == - widget.tabs.indexOf(t) + 1) || - last) { - showDividerColor = false; - } + children: widget.tabs + .map((t) { + final row = Row( + children: [ + GestureDetector( + onTap: () { + setState(() { + widget.controller.index = widget.tabs.indexOf(t); + }); + }, + child: t.copyWith( + active: + widget.controller.index == + widget.tabs.indexOf(t), + ), + ), + ], + ); + bool showDividerColor = true; + final last = + widget.tabs.indexOf(t) == widget.tabs.length - 1; + if ((widget.controller.index - 1 == + widget.tabs.indexOf(t)) || + (widget.controller.index + 1 == + widget.tabs.indexOf(t) + 1) || + last) { + showDividerColor = false; + } - if (!last) { - row.children.add( - VerticalDivider( - color: showDividerColor - ? brightness.resolve( - const Color(0xFFC9C9C9), - const Color(0xFF26222C), - ) - : MacosColors.transparent, - width: 2.0, - indent: 5.0, - endIndent: 5.0, - ), - ); - } + if (!last) { + row.children.add( + VerticalDivider( + color: showDividerColor + ? brightness.resolve( + const Color(0xFFC9C9C9), + const Color(0xFF26222C), + ) + : MacosColors.transparent, + width: 2.0, + indent: 5.0, + endIndent: 5.0, + ), + ); + } - return row; - }).toList(growable: false), + return row; + }) + .toList(growable: false), ), ), ), diff --git a/lib/src/buttons/switch.dart b/lib/src/buttons/switch.dart index 25d7f637..08214c07 100644 --- a/lib/src/buttons/switch.dart +++ b/lib/src/buttons/switch.dart @@ -107,18 +107,12 @@ class MacosSwitch extends StatefulWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(FlagProperty( - 'checked', - value: value, - ifFalse: 'unchecked', - )); + properties.add(FlagProperty('checked', value: value, ifFalse: 'unchecked')); properties.add(EnumProperty('size', size)); properties.add(EnumProperty('dragStartBehavior', dragStartBehavior)); - properties.add(FlagProperty( - 'enabled', - value: onChanged == null, - ifFalse: 'disabled', - )); + properties.add( + FlagProperty('enabled', value: onChanged == null, ifFalse: 'disabled'), + ); properties.add(ColorProperty('activeColor', activeColor)); properties.add(ColorProperty('trackColor', trackColor)); properties.add(ColorProperty('knobColor', knobColor)); @@ -279,15 +273,25 @@ class _MacosSwitchState extends State Widget build(BuildContext context) { assert(debugCheckHasMacosTheme(context)); final MacosThemeData theme = MacosTheme.of(context); - MacosColor borderColor = - MacosDynamicColor.resolve(_kDefaultBorderColor, context).toMacosColor(); - MacosColor activeColor = MacosColor(MacosDynamicColor.resolve( + MacosColor borderColor = MacosDynamicColor.resolve( + _kDefaultBorderColor, + context, + ).toMacosColor(); + final resolvedActiveColor = MacosDynamicColor.resolve( widget.activeColor ?? theme.primaryColor, context, - ).value); - MacosColor trackColor = widget.trackColor ?? + ); + MacosColor activeColor = MacosColor.fromRGBO( + (resolvedActiveColor.r * 255).toInt(), + (resolvedActiveColor.g * 255).toInt(), + (resolvedActiveColor.b * 255).toInt(), + resolvedActiveColor.a, + ); + MacosColor trackColor = + widget.trackColor ?? MacosDynamicColor.resolve(_kDefaultTrackColor, context).toMacosColor(); - MacosColor knobColor = widget.knobColor ?? + MacosColor knobColor = + widget.knobColor ?? MacosDynamicColor.resolve(_kDefaultKnobColor, context).toMacosColor(); // Shot in the dark to try and get the border color correct for each @@ -430,21 +434,21 @@ class _RenderMacosSwitch extends RenderConstrainedBox { required ValueChanged? onChanged, required TextDirection textDirection, required _MacosSwitchState state, - }) : _value = value, - _size = size, - _activeColor = activeColor, - _trackColor = trackColor, - _knobPainter = MacosSwitchKnobPainter(color: knobColor), - _borderColor = borderColor, - _onChanged = onChanged, - _textDirection = textDirection, - _state = state, - super( - additionalConstraints: BoxConstraints.tightFor( - width: size.trackSize.width, - height: size.trackSize.height, - ), - ) { + }) : _value = value, + _size = size, + _activeColor = activeColor, + _trackColor = trackColor, + _knobPainter = MacosSwitchKnobPainter(color: knobColor), + _borderColor = borderColor, + _onChanged = onChanged, + _textDirection = textDirection, + _state = state, + super( + additionalConstraints: BoxConstraints.tightFor( + width: size.trackSize.width, + height: size.trackSize.height, + ), + ) { state.position.addListener(markNeedsPaint); state._reaction.addListener(markNeedsPaint); } @@ -646,21 +650,25 @@ class _RenderMacosSwitch extends RenderConstrainedBox { @override void debugFillProperties(DiagnosticPropertiesBuilder description) { super.debugFillProperties(description); - description.add(FlagProperty( - 'value', - value: value, - ifTrue: 'checked', - ifFalse: 'unchecked', - showName: true, - )); - description.add(FlagProperty( - 'isInteractive', - value: isInteractive, - ifTrue: 'enabled', - ifFalse: 'disabled', - showName: true, - defaultValue: true, - )); + description.add( + FlagProperty( + 'value', + value: value, + ifTrue: 'checked', + ifFalse: 'unchecked', + showName: true, + ), + ); + description.add( + FlagProperty( + 'isInteractive', + value: isInteractive, + ifTrue: 'enabled', + ifFalse: 'disabled', + showName: true, + defaultValue: true, + ), + ); } } diff --git a/lib/src/buttons/toolbar/toolbar_icon_button.dart b/lib/src/buttons/toolbar/toolbar_icon_button.dart index 4b165a3d..23abb84b 100644 --- a/lib/src/buttons/toolbar/toolbar_icon_button.dart +++ b/lib/src/buttons/toolbar/toolbar_icon_button.dart @@ -1,5 +1,6 @@ import 'package:macos_ui/macos_ui.dart'; import 'package:macos_ui/src/library.dart'; +import 'package:macos_window_utils/widgets/macos_toolbar_passthrough.dart'; /// An icon button suitable for the toolbar. class ToolBarIconButton extends ToolbarItem { @@ -57,12 +58,12 @@ class ToolBarIconButton extends ToolbarItem { disabledColor: Colors.transparent, icon: MacosIconTheme( data: MacosTheme.of(context).iconTheme.copyWith( - color: brightness.resolve( - const Color.fromRGBO(0, 0, 0, 0.5), - const Color.fromRGBO(255, 255, 255, 0.5), - ), - size: showLabel ? 16.0 : 20.0, - ), + color: brightness.resolve( + const Color.fromRGBO(0, 0, 0, 0.5), + const Color.fromRGBO(255, 255, 255, 0.5), + ), + size: showLabel ? 16.0 : 20.0, + ), child: icon, ), onPressed: onPressed, @@ -97,17 +98,11 @@ class ToolBarIconButton extends ToolbarItem { } if (tooltipMessage != null) { - iconButton = MacosTooltip( - message: tooltipMessage!, - child: iconButton, - ); + iconButton = MacosTooltip(message: tooltipMessage!, child: iconButton); } - return iconButton; + return MacosToolbarPassthrough(child: iconButton); } else { - return ToolbarOverflowMenuItem( - label: label, - onPressed: onPressed, - ); + return ToolbarOverflowMenuItem(label: label, onPressed: onPressed); } } } diff --git a/lib/src/buttons/toolbar/toolbar_overflow_button.dart b/lib/src/buttons/toolbar/toolbar_overflow_button.dart index 08584418..aa0a01f2 100644 --- a/lib/src/buttons/toolbar/toolbar_overflow_button.dart +++ b/lib/src/buttons/toolbar/toolbar_overflow_button.dart @@ -2,7 +2,7 @@ import 'package:macos_ui/macos_ui.dart'; import 'package:macos_ui/src/library.dart'; /// A button to show at the far right side of the toolbar. -class ToolbarOverflowButton extends StatelessWidget { +class ToolbarOverflowButton extends StatefulWidget { /// Builds a button to show at the far right side of the toolbar, when the /// toolbar actions are overflowing the available horizontal space. /// @@ -20,25 +20,35 @@ class ToolbarOverflowButton extends StatelessWidget { /// Whether the icon button should be smaller in size (half the toolbar height). final bool isDense; + @override + State createState() => _ToolbarOverflowButtonState(); +} + +class _ToolbarOverflowButtonState extends State { + late final GlobalKey popupKey; + + @override + void initState() { + super.initState(); + popupKey = GlobalKey(); + } + @override Widget build(BuildContext context) { - final popupKey = GlobalKey(); return ToolbarPopup( key: popupKey, - content: overflowContentBuilder, + content: widget.overflowContentBuilder, verticalOffset: 8.0, horizontalOffset: 10.0, position: ToolbarPopupPosition.below, placement: ToolbarPopupPlacement.end, child: ToolBarIconButton( label: "", - icon: const MacosIcon( - CupertinoIcons.chevron_right_2, - ), + icon: const MacosIcon(CupertinoIcons.chevron_right_2), onPressed: () { popupKey.currentState?.openPopup(); }, - showLabel: isDense, + showLabel: widget.isDense, ).build(context, ToolbarItemDisplayMode.inToolbar), ); } diff --git a/lib/src/buttons/toolbar/toolbar_pulldown_button.dart b/lib/src/buttons/toolbar/toolbar_pulldown_button.dart index 893d5a9f..64cc5e6d 100644 --- a/lib/src/buttons/toolbar/toolbar_pulldown_button.dart +++ b/lib/src/buttons/toolbar/toolbar_pulldown_button.dart @@ -1,5 +1,6 @@ import 'package:macos_ui/macos_ui.dart'; import 'package:macos_ui/src/library.dart'; +import 'package:macos_window_utils/widgets/macos_toolbar_passthrough.dart'; /// A pulldown button suitable for the toolbar. class ToolBarPullDownButton extends ToolbarItem { @@ -62,10 +63,7 @@ class ToolBarPullDownButton extends ToolbarItem { const Color.fromRGBO(255, 255, 255, 0.5), ), ), - child: MacosPulldownButton( - icon: icon, - items: items, - ), + child: MacosPulldownButton(icon: icon, items: items), ), ); @@ -75,7 +73,7 @@ class ToolBarPullDownButton extends ToolbarItem { child: pulldownButton, ); } - return pulldownButton; + return MacosToolbarPassthrough(child: pulldownButton); } else { // We should show a submenu for the pulldown button items. final subMenuKey = GlobalKey(); @@ -84,8 +82,10 @@ class ToolBarPullDownButton extends ToolbarItem { // Convert the original pulldown menu items to toolbar overflow menu items. items?.forEach((element) { if (element is MacosPulldownMenuItem) { - assert(element.label != null, - 'When you use a MacosPulldownButton in the Toolbar, you must set the label property for all MacosPulldownMenuItems.'); + assert( + element.label != null, + 'When you use a MacosPulldownButton in the Toolbar, you must set the label property for all MacosPulldownMenuItems.', + ); subMenuItems.add( ToolbarOverflowMenuItem( label: element.label!, @@ -117,9 +117,9 @@ class ToolBarPullDownButton extends ToolbarItem { placement: ToolbarPopupPlacement.start, child: MouseRegion( onHover: (e) { - subMenuKey.currentState - ?.openPopup() - .then((value) => setState(() => isSelected = false)); + subMenuKey.currentState?.openPopup().then( + (value) => setState(() => isSelected = false), + ); setState(() => isSelected = true); }, child: ToolbarOverflowMenuItem( diff --git a/lib/src/dialogs/macos_alert_dialog.dart b/lib/src/dialogs/macos_alert_dialog.dart index 0dab2588..2ff9c239 100644 --- a/lib/src/dialogs/macos_alert_dialog.dart +++ b/lib/src/dialogs/macos_alert_dialog.dart @@ -3,10 +3,7 @@ import 'package:macos_ui/macos_ui.dart'; import 'package:macos_ui/src/library.dart'; const _kDialogBorderRadius = BorderRadius.all(Radius.circular(12.0)); -const _kDefaultDialogConstraints = BoxConstraints( - minWidth: 260, - maxWidth: 260, -); +const _kDefaultDialogConstraints = BoxConstraints(minWidth: 260, maxWidth: 260); /// A macOS-style AlertDialog. /// @@ -126,13 +123,13 @@ class MacosAlertDialog extends StatelessWidget { final brightness = MacosTheme.brightnessOf(context); final outerBorderColor = brightness.resolve( - Colors.black.withOpacity(0.23), - Colors.black.withOpacity(0.76), + Colors.black.withValues(alpha: 0.23), + Colors.black.withValues(alpha: 0.76), ); final innerBorderColor = brightness.resolve( - Colors.white.withOpacity(0.45), - Colors.white.withOpacity(0.15), + Colors.white.withValues(alpha: 0.45), + Colors.white.withValues(alpha: 0.15), ); return Dialog( @@ -140,23 +137,15 @@ class MacosAlertDialog extends StatelessWidget { CupertinoColors.systemGrey6.color, MacosColors.controlBackgroundColor.darkColor, ), - shape: const RoundedRectangleBorder( - borderRadius: _kDialogBorderRadius, - ), + shape: const RoundedRectangleBorder(borderRadius: _kDialogBorderRadius), child: Container( padding: const EdgeInsets.symmetric(horizontal: 16.0), decoration: BoxDecoration( - border: Border.all( - width: 2, - color: innerBorderColor, - ), + border: Border.all(width: 2, color: innerBorderColor), borderRadius: _kDialogBorderRadius, ), foregroundDecoration: BoxDecoration( - border: Border.all( - width: 1, - color: outerBorderColor, - ), + border: Border.all(width: 1, color: outerBorderColor), borderRadius: _kDialogBorderRadius, ), child: ConstrainedBox( @@ -166,10 +155,7 @@ class MacosAlertDialog extends StatelessWidget { children: [ const SizedBox(height: 20), ConstrainedBox( - constraints: const BoxConstraints( - maxHeight: 64, - maxWidth: 64, - ), + constraints: const BoxConstraints(maxHeight: 64, maxWidth: 64), child: appIcon, ), const SizedBox(height: 16), @@ -186,11 +172,7 @@ class MacosAlertDialog extends StatelessWidget { ), const SizedBox(height: 16), if (secondaryButton == null) ...[ - Row( - children: [ - Expanded(child: primaryButton), - ], - ), + Row(children: [Expanded(child: primaryButton)]), ] else ...[ if (horizontalActions!) ...[ Row( @@ -199,29 +181,17 @@ class MacosAlertDialog extends StatelessWidget { Expanded(child: secondaryButton!), const SizedBox(width: 8.0), ], - Expanded( - child: primaryButton, - ), + Expanded(child: primaryButton), ], ), ] else ...[ Column( mainAxisSize: MainAxisSize.min, children: [ - Row( - children: [ - Expanded(child: primaryButton), - ], - ), + Row(children: [Expanded(child: primaryButton)]), const SizedBox(height: 8.0), if (secondaryButton != null) ...[ - Row( - children: [ - Expanded( - child: secondaryButton!, - ), - ], - ), + Row(children: [Expanded(child: secondaryButton!)]), ], ], ), @@ -256,7 +226,14 @@ Future showMacosAlertDialog({ barrierColor ??= MacosDynamicColor.resolve( MacosColors.controlBackgroundColor, context, - ).withOpacity(0.6); + ); + + barrierColor = Color.fromRGBO( + (barrierColor.r * 255).floor(), + (barrierColor.g * 255).floor(), + (barrierColor.b * 255).floor(), + 0.6, + ); return Navigator.of(context, rootNavigator: useRootNavigator).push( _MacosAlertDialogRoute( @@ -266,7 +243,8 @@ Future showMacosAlertDialog({ }, barrierDismissible: barrierDismissible, barrierColor: barrierColor, - barrierLabel: barrierLabel ?? + barrierLabel: + barrierLabel ?? MaterialLocalizations.of(context).modalBarrierDismissLabel, ), ); @@ -279,10 +257,10 @@ class _MacosAlertDialogRoute extends PopupRoute { Color? barrierColor = const Color(0x80000000), String? barrierLabel, super.settings, - }) : _pageBuilder = pageBuilder, - _barrierDismissible = barrierDismissible, - _barrierLabel = barrierLabel, - _barrierColor = barrierColor; + }) : _pageBuilder = pageBuilder, + _barrierDismissible = barrierDismissible, + _barrierLabel = barrierLabel, + _barrierColor = barrierColor; final RoutePageBuilder _pageBuilder; @@ -329,10 +307,7 @@ class _MacosAlertDialogRoute extends PopupRoute { ) { if (animation.status == AnimationStatus.reverse) { return FadeTransition( - opacity: CurvedAnimation( - parent: animation, - curve: Curves.easeOutSine, - ), + opacity: CurvedAnimation(parent: animation, curve: Curves.easeOutSine), child: child, ); } @@ -358,11 +333,7 @@ class _SubtleBounceCurve extends Curve { @override double transform(double t) { final simulation = SpringSimulation( - const SpringDescription( - damping: 14, - mass: 1.4, - stiffness: 180, - ), + const SpringDescription(damping: 14, mass: 1.4, stiffness: 180), 0.0, 1.0, 0.1, diff --git a/lib/src/fields/search_field.dart b/lib/src/fields/search_field.dart index 2064ef9a..972280a9 100644 --- a/lib/src/fields/search_field.dart +++ b/lib/src/fields/search_field.dart @@ -259,24 +259,25 @@ class _MacosSearchFieldState extends State> { return OverlayEntry( builder: (context) => StreamBuilder?>( stream: suggestionStream.stream, - builder: ( - BuildContext context, - AsyncSnapshot?> snapshot, - ) { - late var count = widget.maxResultsToShow; - if (snapshot.data != null) { - count = snapshot.data!.length; - } - return Positioned( - left: offset.dx, - width: size.width, - child: CompositedTransformFollower( - offset: _getYOffset(offset, size, count), - link: _layerLink, - child: _resultsBuilder(), - ), - ); - }, + builder: + ( + BuildContext context, + AsyncSnapshot?> snapshot, + ) { + late var count = widget.maxResultsToShow; + if (snapshot.data != null) { + count = snapshot.data!.length; + } + return Positioned( + left: offset.dx, + width: size.width, + child: CompositedTransformFollower( + offset: _getYOffset(offset, size, count), + link: _layerLink, + child: _resultsBuilder(), + ), + ); + }, ), ); } @@ -289,10 +290,7 @@ class _MacosSearchFieldState extends State> { } else { if (resultCount > widget.maxResultsToShow) { showOverlayAbove = false; - return Offset( - 0, - -(widget.resultHeight * widget.maxResultsToShow), - ); + return Offset(0, -(widget.resultHeight * widget.maxResultsToShow)); } else { showOverlayAbove = true; return Offset(0, -(widget.resultHeight * resultCount)); @@ -303,67 +301,72 @@ class _MacosSearchFieldState extends State> { Widget _resultsBuilder() { return StreamBuilder?>( stream: suggestionStream.stream, - builder: ( - BuildContext context, - AsyncSnapshot?> snapshot, - ) { - if (widget.results == null || - snapshot.data == null || - !isResultExpanded) { - return const SizedBox.shrink(); - } else if (snapshot.data!.isEmpty) { - return MacosOverlayFilter( - borderRadius: _kBorderRadius, - child: widget.emptyWidget, - ); - } else { - if (snapshot.data!.length > widget.maxResultsToShow) { - height = widget.resultHeight * widget.maxResultsToShow; - } else if (snapshot.data!.length == 1) { - height = widget.resultHeight; - } else { - height = snapshot.data!.length * widget.resultHeight; - } - height += _kResultsOverlayMargin; - - return TextFieldTapRegion( - child: MacosOverlayFilter( - borderRadius: _kBorderRadius, - color: MacosSearchFieldTheme.of(context).resultsBackgroundColor, - child: SizedBox( - height: height, - child: ListView.builder( - reverse: showOverlayAbove, - padding: const EdgeInsets.all(6.0), - itemCount: snapshot.data!.length, - itemBuilder: (context, index) { - var selectedItem = snapshot.data![index]!; - return _SearchResultItemButton( - resultHeight: widget.resultHeight, - onPressed: () { - searchController!.text = selectedItem.searchKey; - searchController!.selection = - TextSelection.fromPosition( - TextPosition( - offset: searchController!.text.length, - ), + builder: + ( + BuildContext context, + AsyncSnapshot?> snapshot, + ) { + if (widget.results == null || + snapshot.data == null || + !isResultExpanded) { + return const SizedBox.shrink(); + } else if (snapshot.data!.isEmpty) { + return MacosOverlayFilter( + borderRadius: _kBorderRadius, + child: widget.emptyWidget, + ); + } else { + if (snapshot.data!.length > widget.maxResultsToShow) { + height = widget.resultHeight * widget.maxResultsToShow; + } else if (snapshot.data!.length == 1) { + height = widget.resultHeight; + } else { + height = snapshot.data!.length * widget.resultHeight; + } + height += _kResultsOverlayMargin; + + return TextFieldTapRegion( + child: MacosOverlayFilter( + borderRadius: _kBorderRadius, + color: MacosSearchFieldTheme.of( + context, + ).resultsBackgroundColor, + child: SizedBox( + height: height, + child: ListView.builder( + reverse: showOverlayAbove, + padding: const EdgeInsets.all(6.0), + itemCount: snapshot.data!.length, + itemBuilder: (context, index) { + var selectedItem = snapshot.data![index]!; + return _SearchResultItemButton( + resultHeight: widget.resultHeight, + onPressed: () { + searchController!.text = selectedItem.searchKey; + searchController!.selection = + TextSelection.fromPosition( + TextPosition( + offset: searchController!.text.length, + ), + ); + selectedItem.onSelected?.call(); + // Hide the results + suggestionStream.sink.add(null); + if (widget.onResultSelected != null) { + widget.onResultSelected!(selectedItem); + } + }, + child: + selectedItem.child ?? + Text(selectedItem.searchKey), ); - selectedItem.onSelected?.call(); - // Hide the results - suggestionStream.sink.add(null); - if (widget.onResultSelected != null) { - widget.onResultSelected!(selectedItem); - } }, - child: selectedItem.child ?? Text(selectedItem.searchKey), - ); - }, + ), + ), ), - ), - ), - ); - } - }, + ); + } + }, ); } @@ -413,9 +416,9 @@ class _MacosSearchFieldState extends State> { } if (widget.results != null) { for (final suggestion in widget.results!) { - if (suggestion.searchKey - .toLowerCase() - .contains(query.toLowerCase())) { + if (suggestion.searchKey.toLowerCase().contains( + query.toLowerCase(), + )) { searchResult.add(suggestion); } } @@ -450,11 +453,7 @@ class SearchResultItem { /// field. /// /// Can be further customized via its [child] property. - const SearchResultItem( - this.searchKey, { - this.child, - this.onSelected, - }); + const SearchResultItem(this.searchKey, {this.child, this.onSelected}); /// The string to search for. final String searchKey; @@ -527,10 +526,7 @@ class _SearchResultItemButtonState extends State<_SearchResultItemButton> { fontSize: 13.0, color: _isHovered ? MacosColors.white - : brightness.resolve( - MacosColors.black, - MacosColors.white, - ), + : brightness.resolve(MacosColors.black, MacosColors.white), ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), diff --git a/lib/src/fields/text_field.dart b/lib/src/fields/text_field.dart index 8564301d..c62f2039 100644 --- a/lib/src/fields/text_field.dart +++ b/lib/src/fields/text_field.dart @@ -99,8 +99,8 @@ class _TextFieldSelectionGestureDetectorBuilder extends TextSelectionGestureDetectorBuilder { _TextFieldSelectionGestureDetectorBuilder({ required _MacosTextFieldState state, - }) : _state = state, - super(delegate: state); + }) : _state = state, + super(delegate: state); final _MacosTextFieldState _state; @@ -111,10 +111,12 @@ class _TextFieldSelectionGestureDetectorBuilder // this handler. If the clear button widget recognizes the up event, // then do not handle it. if (_state._clearGlobalKey.currentContext != null) { - final RenderBox renderBox = _state._clearGlobalKey.currentContext! - .findRenderObject()! as RenderBox; - final Offset localOffset = - renderBox.globalToLocal(details.globalPosition); + final RenderBox renderBox = + _state._clearGlobalKey.currentContext!.findRenderObject()! + as RenderBox; + final Offset localOffset = renderBox.globalToLocal( + details.globalPosition, + ); if (renderBox.hitTest(BoxHitTestResult(), position: localOffset)) { return; } @@ -293,31 +295,37 @@ class MacosTextField extends StatefulWidget { this.scrollPhysics, this.autofillHints, this.restorationId, - }) : smartDashesType = smartDashesType ?? - (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled), - smartQuotesType = smartQuotesType ?? - (obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled), - assert(maxLines == null || maxLines > 0), - assert(minLines == null || minLines > 0), - assert( - (maxLines == null) || (minLines == null) || (maxLines >= minLines), - "minLines can't be greater than maxLines", - ), - assert( - !expands || (maxLines == null && minLines == null), - 'minLines and maxLines must be null when expands is true.', - ), - assert(!obscureText || maxLines == 1, - 'Obscured fields cannot be multiline.'), - assert(maxLength == null || maxLength > 0), - // Assert the following instead of setting it directly to avoid surprising the user by silently changing the value they set. - assert( - !identical(textInputAction, TextInputAction.newline) || - maxLines == 1 || - !identical(keyboardType, TextInputType.text), - 'Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.'), - keyboardType = keyboardType ?? - (maxLines == 1 ? TextInputType.text : TextInputType.multiline); + }) : smartDashesType = + smartDashesType ?? + (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled), + smartQuotesType = + smartQuotesType ?? + (obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled), + assert(maxLines == null || maxLines > 0), + assert(minLines == null || minLines > 0), + assert( + (maxLines == null) || (minLines == null) || (maxLines >= minLines), + "minLines can't be greater than maxLines", + ), + assert( + !expands || (maxLines == null && minLines == null), + 'minLines and maxLines must be null when expands is true.', + ), + assert( + !obscureText || maxLines == 1, + 'Obscured fields cannot be multiline.', + ), + assert(maxLength == null || maxLength > 0), + // Assert the following instead of setting it directly to avoid surprising the user by silently changing the value they set. + assert( + !identical(textInputAction, TextInputAction.newline) || + maxLines == 1 || + !identical(keyboardType, TextInputType.text), + 'Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.', + ), + keyboardType = + keyboardType ?? + (maxLines == 1 ? TextInputType.text : TextInputType.multiline); /// Creates a borderless macOS-style text field. /// @@ -412,31 +420,37 @@ class MacosTextField extends StatefulWidget { this.autofillHints, this.restorationId, this.contextMenuBuilder = _defaultContextMenuBuilder, - }) : smartDashesType = smartDashesType ?? - (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled), - smartQuotesType = smartQuotesType ?? - (obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled), - assert(maxLines == null || maxLines > 0), - assert(minLines == null || minLines > 0), - assert( - (maxLines == null) || (minLines == null) || (maxLines >= minLines), - "minLines can't be greater than maxLines", - ), - assert( - !expands || (maxLines == null && minLines == null), - 'minLines and maxLines must be null when expands is true.', - ), - assert(!obscureText || maxLines == 1, - 'Obscured fields cannot be multiline.'), - assert(maxLength == null || maxLength > 0), - // Assert the following instead of setting it directly to avoid surprising the user by silently changing the value they set. - assert( - !identical(textInputAction, TextInputAction.newline) || - maxLines == 1 || - !identical(keyboardType, TextInputType.text), - 'Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.'), - keyboardType = keyboardType ?? - (maxLines == 1 ? TextInputType.text : TextInputType.multiline); + }) : smartDashesType = + smartDashesType ?? + (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled), + smartQuotesType = + smartQuotesType ?? + (obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled), + assert(maxLines == null || maxLines > 0), + assert(minLines == null || minLines > 0), + assert( + (maxLines == null) || (minLines == null) || (maxLines >= minLines), + "minLines can't be greater than maxLines", + ), + assert( + !expands || (maxLines == null && minLines == null), + 'minLines and maxLines must be null when expands is true.', + ), + assert( + !obscureText || maxLines == 1, + 'Obscured fields cannot be multiline.', + ), + assert(maxLength == null || maxLength > 0), + // Assert the following instead of setting it directly to avoid surprising the user by silently changing the value they set. + assert( + !identical(textInputAction, TextInputAction.newline) || + maxLines == 1 || + !identical(keyboardType, TextInputType.text), + 'Use keyboardType TextInputType.multiline when using TextInputAction.newline on a multiline TextField.', + ), + keyboardType = + keyboardType ?? + (maxLines == 1 ? TextInputType.text : TextInputType.multiline); static Widget _defaultContextMenuBuilder( BuildContext context, @@ -724,156 +738,184 @@ class MacosTextField extends StatefulWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty( - 'controller', - controller, - defaultValue: null, - )); - properties.add(DiagnosticsProperty( - 'focusNode', - focusNode, - defaultValue: null, - )); - properties.add(DiagnosticsProperty( - 'decoration', - decoration, - defaultValue: kDefaultRoundedBorderDecoration, - )); + properties.add( + DiagnosticsProperty( + 'controller', + controller, + defaultValue: null, + ), + ); + properties.add( + DiagnosticsProperty( + 'focusNode', + focusNode, + defaultValue: null, + ), + ); + properties.add( + DiagnosticsProperty( + 'decoration', + decoration, + defaultValue: kDefaultRoundedBorderDecoration, + ), + ); properties.add(DiagnosticsProperty('padding', padding)); properties.add(StringProperty('placeholder', placeholder)); properties.add( - DiagnosticsProperty( - 'placeholderStyle', - placeholderStyle, + DiagnosticsProperty('placeholderStyle', placeholderStyle), + ); + properties.add( + EnumProperty( + 'prefix', + prefix == null ? null : prefixMode, + ), + ); + properties.add( + EnumProperty( + 'suffix', + suffix == null ? null : suffixMode, + ), + ); + properties.add( + EnumProperty('clearButtonMode', clearButtonMode), + ); + properties.add( + DiagnosticsProperty( + 'keyboardType', + keyboardType, + defaultValue: TextInputType.text, + ), + ); + properties.add( + DiagnosticsProperty('style', style, defaultValue: null), + ); + properties.add( + DiagnosticsProperty('autofocus', autofocus, defaultValue: false), + ); + properties.add( + DiagnosticsProperty( + 'obscuringCharacter', + obscuringCharacter, + defaultValue: 'โ€ข', + ), + ); + properties.add( + DiagnosticsProperty( + 'obscureText', + obscureText, + defaultValue: false, + ), + ); + properties.add( + DiagnosticsProperty('autocorrect', autocorrect, defaultValue: true), + ); + properties.add( + EnumProperty( + 'smartDashesType', + smartDashesType, + defaultValue: obscureText + ? SmartDashesType.disabled + : SmartDashesType.enabled, + ), + ); + properties.add( + EnumProperty( + 'smartQuotesType', + smartQuotesType, + defaultValue: obscureText + ? SmartQuotesType.disabled + : SmartQuotesType.enabled, + ), + ); + properties.add( + DiagnosticsProperty( + 'enableSuggestions', + enableSuggestions, + defaultValue: true, ), ); - properties.add(EnumProperty( - 'prefix', - prefix == null ? null : prefixMode, - )); - properties.add(EnumProperty( - 'suffix', - suffix == null ? null : suffixMode, - )); - properties.add(EnumProperty( - 'clearButtonMode', - clearButtonMode, - )); - properties.add(DiagnosticsProperty( - 'keyboardType', - keyboardType, - defaultValue: TextInputType.text, - )); - properties.add(DiagnosticsProperty( - 'style', - style, - defaultValue: null, - )); - properties.add(DiagnosticsProperty( - 'autofocus', - autofocus, - defaultValue: false, - )); - properties.add(DiagnosticsProperty( - 'obscuringCharacter', - obscuringCharacter, - defaultValue: 'โ€ข', - )); - properties.add(DiagnosticsProperty( - 'obscureText', - obscureText, - defaultValue: false, - )); - properties.add(DiagnosticsProperty( - 'autocorrect', - autocorrect, - defaultValue: true, - )); - properties.add(EnumProperty( - 'smartDashesType', - smartDashesType, - defaultValue: - obscureText ? SmartDashesType.disabled : SmartDashesType.enabled, - )); - properties.add(EnumProperty( - 'smartQuotesType', - smartQuotesType, - defaultValue: - obscureText ? SmartQuotesType.disabled : SmartQuotesType.enabled, - )); - properties.add(DiagnosticsProperty( - 'enableSuggestions', - enableSuggestions, - defaultValue: true, - )); properties.add(IntProperty('maxLines', maxLines, defaultValue: 1)); properties.add(IntProperty('minLines', minLines, defaultValue: null)); - properties.add(DiagnosticsProperty( - 'expands', - expands, - defaultValue: false, - )); + properties.add( + DiagnosticsProperty('expands', expands, defaultValue: false), + ); properties.add(IntProperty('maxLength', maxLength, defaultValue: null)); - properties.add(EnumProperty( - 'maxLengthEnforcement', - maxLengthEnforcement, - defaultValue: null, - )); - properties.add(DoubleProperty( - 'cursorWidth', - cursorWidth, - defaultValue: 2.0, - )); - properties.add(DoubleProperty( - 'cursorHeight', - cursorHeight, - defaultValue: null, - )); - properties.add(DiagnosticsProperty( - 'cursorRadius', - cursorRadius, - defaultValue: null, - )); - properties.add(createCupertinoColorProperty( - 'cursorColor', - cursorColor, - defaultValue: null, - )); - properties.add(FlagProperty( - 'selectionEnabled', - value: selectionEnabled, - defaultValue: true, - ifFalse: 'selection disabled', - )); - properties.add(DiagnosticsProperty( - 'selectionControls', - selectionControls, - defaultValue: null, - )); - properties.add(DiagnosticsProperty( - 'scrollController', - scrollController, - defaultValue: null, - )); - properties.add(DiagnosticsProperty( - 'scrollPhysics', - scrollPhysics, - defaultValue: null, - )); - properties.add(EnumProperty( - 'textAlign', - textAlign, - defaultValue: TextAlign.start, - )); - properties.add(DiagnosticsProperty( - 'textAlignVertical', - textAlignVertical, - defaultValue: null, - )); - properties.add(DiagnosticsProperty( - 'contextMenuBuilder', - contextMenuBuilder, - )); + properties.add( + EnumProperty( + 'maxLengthEnforcement', + maxLengthEnforcement, + defaultValue: null, + ), + ); + properties.add( + DoubleProperty('cursorWidth', cursorWidth, defaultValue: 2.0), + ); + properties.add( + DoubleProperty('cursorHeight', cursorHeight, defaultValue: null), + ); + properties.add( + DiagnosticsProperty( + 'cursorRadius', + cursorRadius, + defaultValue: null, + ), + ); + properties.add( + createCupertinoColorProperty( + 'cursorColor', + cursorColor, + defaultValue: null, + ), + ); + properties.add( + FlagProperty( + 'selectionEnabled', + value: selectionEnabled, + defaultValue: true, + ifFalse: 'selection disabled', + ), + ); + properties.add( + DiagnosticsProperty( + 'selectionControls', + selectionControls, + defaultValue: null, + ), + ); + properties.add( + DiagnosticsProperty( + 'scrollController', + scrollController, + defaultValue: null, + ), + ); + properties.add( + DiagnosticsProperty( + 'scrollPhysics', + scrollPhysics, + defaultValue: null, + ), + ); + properties.add( + EnumProperty( + 'textAlign', + textAlign, + defaultValue: TextAlign.start, + ), + ); + properties.add( + DiagnosticsProperty( + 'textAlignVertical', + textAlignVertical, + defaultValue: null, + ), + ); + properties.add( + DiagnosticsProperty( + 'contextMenuBuilder', + contextMenuBuilder, + ), + ); } } @@ -897,7 +939,7 @@ class _MacosTextFieldState extends State bool _showSelectionHandles = false; late _TextFieldSelectionGestureDetectorBuilder - _selectionGestureDetectorBuilder; + _selectionGestureDetectorBuilder; // API for TextSelectionGestureDetectorBuilderDelegate. @override @@ -909,6 +951,7 @@ class _MacosTextFieldState extends State @override bool get selectionEnabled => widget.selectionEnabled; + // End of API for TextSelectionGestureDetectorBuilderDelegate. @override @@ -1046,7 +1089,7 @@ class _MacosTextFieldState extends State ? const Color.fromRGBO(255, 255, 255, 0.55) : const Color.fromRGBO(0, 0, 0, 0.5); if (widget.enabled != null && widget.enabled == false) { - iconsColor = iconsColor.withOpacity(0.2); + iconsColor = iconsColor.withValues(alpha: 0.2); } // Otherwise, listen to the current state of the text entry. @@ -1070,10 +1113,7 @@ class _MacosTextFieldState extends State right: 6.0, ), child: MacosIconTheme( - data: MacosIconThemeData( - color: iconsColor, - size: 16.0, - ), + data: MacosIconThemeData(color: iconsColor, size: 16.0), child: widget.prefix!, ), ), @@ -1146,6 +1186,54 @@ class _MacosTextFieldState extends State ); } + Color? _resolveAccentColor(BuildContext context, AccentColor? accentColor) { + if (accentColor == null) { + return null; + } + + final isDarkModeActive = MacosTheme.of(context).brightness.isDark; + + if (isDarkModeActive) { + switch (accentColor) { + case AccentColor.blue: + return const Color.fromRGBO(0, 122, 255, 1.0); + case AccentColor.purple: + return const Color.fromRGBO(165, 80, 167, 1.0); + case AccentColor.pink: + return const Color.fromRGBO(247, 79, 158, 1.0); + case AccentColor.red: + return const Color.fromRGBO(255, 82, 87, 1.0); + case AccentColor.orange: + return const Color.fromRGBO(247, 130, 27, 1.0); + case AccentColor.yellow: + return const Color.fromRGBO(255, 198, 0, 1.0); + case AccentColor.green: + return const Color.fromRGBO(98, 186, 70, 1.0); + case AccentColor.graphite: + return const Color.fromRGBO(137, 137, 137, 1.0); + } + } + + switch (accentColor) { + case AccentColor.blue: + return const Color.fromRGBO(0, 122, 255, 1.0); + case AccentColor.purple: + return const Color.fromRGBO(150, 51, 150, 1.0); + case AccentColor.pink: + return const Color.fromRGBO(247, 79, 158, 1.0); + case AccentColor.red: + return const Color.fromRGBO(224, 56, 62, 1.0); + case AccentColor.orange: + return const Color.fromRGBO(247, 130, 27, 1.0); + case AccentColor.yellow: + return const Color.fromRGBO(255, 199, 38, 1.0); + case AccentColor.green: + return const Color.fromRGBO(98, 186, 70, 1.0); + case AccentColor.graphite: + return const Color.fromRGBO(152, 152, 152, 1.0); + } + } + @override void restoreState(RestorationBucket? oldBucket, bool initialRestore) { if (_controller != null) { @@ -1195,251 +1283,278 @@ class _MacosTextFieldState extends State super.build(context); // See AutomaticKeepAliveClientMixin. assert(debugCheckHasDirectionality(context)); assert(debugCheckHasMacosTheme(context)); - final TextEditingController controller = _effectiveController; - - TextSelectionControls? textSelectionControls = widget.selectionControls; - switch (defaultTargetPlatform) { - case TargetPlatform.iOS: - case TargetPlatform.android: - case TargetPlatform.fuchsia: - textSelectionControls ??= cupertinoTextSelectionControls; - break; - - case TargetPlatform.linux: - case TargetPlatform.windows: - case TargetPlatform.macOS: - textSelectionControls ??= cupertinoDesktopTextSelectionControls; - break; - } + return StreamBuilder( + stream: AccentColorListener.instance.onChanged, + builder: (context, _) { + final TextEditingController controller = _effectiveController; + + TextSelectionControls? textSelectionControls = widget.selectionControls; + switch (defaultTargetPlatform) { + case TargetPlatform.iOS: + case TargetPlatform.android: + case TargetPlatform.fuchsia: + textSelectionControls ??= cupertinoTextSelectionControls; + break; + + case TargetPlatform.linux: + case TargetPlatform.windows: + case TargetPlatform.macOS: + textSelectionControls ??= cupertinoDesktopTextSelectionControls; + break; + } - final bool enabled = widget.enabled ?? true; - final Offset cursorOffset = Offset( - _iOSHorizontalCursorOffsetPixels / - MediaQuery.of(context).devicePixelRatio, - 0, - ); - final List formatters = [ - ...?widget.inputFormatters, - if (widget.maxLength != null) - LengthLimitingTextInputFormatter( - widget.maxLength, - maxLengthEnforcement: _effectiveMaxLengthEnforcement, - ), - ]; - final MacosThemeData themeData = MacosTheme.of(context); - - final TextStyle? resolvedStyle = widget.style?.copyWith( - color: MacosDynamicColor.maybeResolve(widget.style?.color, context), - backgroundColor: MacosDynamicColor.maybeResolve( - widget.style?.backgroundColor, - context, - ), - ); + final bool enabled = widget.enabled ?? true; + final Offset cursorOffset = Offset( + _iOSHorizontalCursorOffsetPixels / + MediaQuery.of(context).devicePixelRatio, + 0, + ); + final List formatters = [ + ...?widget.inputFormatters, + if (widget.maxLength != null) + LengthLimitingTextInputFormatter( + widget.maxLength, + maxLengthEnforcement: _effectiveMaxLengthEnforcement, + ), + ]; + final MacosThemeData themeData = MacosTheme.of(context); + + final TextStyle? resolvedStyle = widget.style?.copyWith( + color: MacosDynamicColor.maybeResolve(widget.style?.color, context), + backgroundColor: MacosDynamicColor.maybeResolve( + widget.style?.backgroundColor, + context, + ), + ); - final textStyle = themeData.typography.body.merge(resolvedStyle); + final textStyle = themeData.typography.body.merge(resolvedStyle); - final resolvedPlaceholderStyle = widget.placeholderStyle?.copyWith( - color: MacosDynamicColor.maybeResolve( - widget.placeholderStyle?.color, - context, - ), - backgroundColor: MacosDynamicColor.maybeResolve( - widget.placeholderStyle?.backgroundColor, - context, - ), - ); + final resolvedPlaceholderStyle = widget.placeholderStyle?.copyWith( + color: MacosDynamicColor.maybeResolve( + widget.placeholderStyle?.color, + context, + ), + backgroundColor: MacosDynamicColor.maybeResolve( + widget.placeholderStyle?.backgroundColor, + context, + ), + ); - final placeholderStyle = textStyle.merge(enabled - ? resolvedPlaceholderStyle - : resolvedPlaceholderStyle! - .copyWith(color: resolvedPlaceholderStyle.color!.withOpacity(0.2))); - - final Brightness keyboardAppearance = - widget.keyboardAppearance ?? MacosTheme.brightnessOf(context); - Color? cursorColor; - cursorColor = MacosDynamicColor.maybeResolve(widget.cursorColor, context); - cursorColor ??= - themeData.brightness.isDark ? MacosColors.white : MacosColors.black; - final Color disabledColor = - MacosDynamicColor.resolve(_kDisabledBackground, context); - - Color? decorationColor = - MacosDynamicColor.maybeResolve(widget.decoration?.color, context); - if (decorationColor.runtimeType == ResolvedMacosDynamicColor) { - if ((decorationColor as ResolvedMacosDynamicColor).color == - const Color(0xffffffff) || - (decorationColor).darkColor == const Color(0xff000000)) { - decorationColor = themeData.brightness.isDark - ? const Color.fromRGBO(30, 30, 30, 1) - : MacosColors.white; - } - } + final placeholderStyle = textStyle.merge( + enabled + ? resolvedPlaceholderStyle + : resolvedPlaceholderStyle!.copyWith( + color: resolvedPlaceholderStyle.color!.withValues(alpha: 0.2), + ), + ); - final BoxBorder? border = widget.decoration?.border; - Border? resolvedBorder = border as Border?; - if (border is Border) { - BorderSide resolveBorderSide(BorderSide side) { - return side == BorderSide.none - ? side - : side.copyWith( - color: MacosDynamicColor.resolve(side.color, context), - ); - } + final Brightness keyboardAppearance = + widget.keyboardAppearance ?? MacosTheme.brightnessOf(context); + Color? cursorColor; + cursorColor = MacosDynamicColor.maybeResolve( + widget.cursorColor, + context, + ); + cursorColor ??= _resolveAccentColor( + context, + AccentColorListener.instance.currentAccentColor, + ); + cursorColor ??= textStyle.color; // next best is "match text" + cursorColor ??= // last resort - fall back to theme forground color + themeData.brightness.isDark + ? MacosColors.white + : MacosColors.black; + final Color disabledColor = MacosDynamicColor.resolve( + _kDisabledBackground, + context, + ); - resolvedBorder = border.runtimeType != Border - ? border - : Border( - top: resolveBorderSide(border.top), - left: resolveBorderSide(border.left), - bottom: resolveBorderSide(border.bottom), - right: resolveBorderSide(border.right), - ); - } + Color? decorationColor = MacosDynamicColor.maybeResolve( + widget.decoration?.color, + context, + ); + if (decorationColor.runtimeType == ResolvedMacosDynamicColor) { + if ((decorationColor as ResolvedMacosDynamicColor).color == + const Color(0xffffffff) || + (decorationColor).darkColor == const Color(0xff000000)) { + decorationColor = themeData.brightness.isDark + ? const Color.fromRGBO(30, 30, 30, 1) + : MacosColors.white; + } + } - final BoxDecoration? effectiveDecoration = widget.decoration?.copyWith( - border: resolvedBorder, - color: enabled ? decorationColor : disabledColor, - ); + final BoxBorder? border = widget.decoration?.border; + Border? resolvedBorder = border as Border?; + if (border is Border) { + BorderSide resolveBorderSide(BorderSide side) { + return side == BorderSide.none + ? side + : side.copyWith( + color: MacosDynamicColor.resolve(side.color, context), + ); + } - final BoxDecoration? focusedDecoration = widget.focusedDecoration?.copyWith( - border: Border.all( - width: 3.0, - color: themeData.brightness.isDark - ? const Color.fromRGBO(26, 169, 255, 0.3) - : const Color.fromRGBO(0, 103, 244, 0.25), - ), - ); + resolvedBorder = border.runtimeType != Border + ? border + : Border( + top: resolveBorderSide(border.top), + left: resolveBorderSide(border.left), + bottom: resolveBorderSide(border.bottom), + right: resolveBorderSide(border.right), + ); + } - final focusedPlaceholderDecoration = focusedDecoration?.copyWith( - border: () { - if (focusedDecoration.border is Border) { - BorderSide borderSide(BorderSide fromSide) { - return BorderSide( - color: fromSide.color.withOpacity(0.0), - style: fromSide.style, - width: fromSide.width, + final BoxDecoration? effectiveDecoration = widget.decoration?.copyWith( + border: resolvedBorder, + color: enabled ? decorationColor : disabledColor, + ); + + final BoxDecoration? focusedDecoration = widget.focusedDecoration + ?.copyWith( + border: Border.all( + width: 3.0, + color: themeData.brightness.isDark + ? const Color.fromRGBO(26, 169, 255, 0.3) + : const Color.fromRGBO(0, 103, 244, 0.25), + ), ); - } - return Border( - bottom: borderSide((focusedDecoration.border as Border).bottom), - top: borderSide((focusedDecoration.border as Border).top), - left: borderSide((focusedDecoration.border as Border).left), - right: borderSide((focusedDecoration.border as Border).right), - ); - } - return focusedDecoration.border; - }(), - color: focusedDecoration.color ?? const Color(0x00000000), - ); + final focusedPlaceholderDecoration = focusedDecoration?.copyWith( + border: () { + if (focusedDecoration.border is Border) { + BorderSide borderSide(BorderSide fromSide) { + return BorderSide( + color: fromSide.color.withValues(alpha: 0.0), + style: fromSide.style, + width: fromSide.width, + ); + } - final Color selectionColor = - MacosTheme.of(context).primaryColor.withOpacity(0.2); - - final Widget paddedEditable = Padding( - padding: widget.padding, - child: RepaintBoundary( - child: UnmanagedRestorationScope( - bucket: bucket, - child: EditableText( - key: editableTextKey, - controller: controller, - readOnly: widget.readOnly, - showCursor: widget.showCursor, - showSelectionHandles: _showSelectionHandles, - focusNode: _effectiveFocusNode, - keyboardType: widget.keyboardType, - textInputAction: widget.textInputAction, - textCapitalization: widget.textCapitalization, - style: textStyle, - strutStyle: widget.strutStyle, - textAlign: widget.textAlign, - autofocus: widget.autofocus, - obscuringCharacter: widget.obscuringCharacter, - obscureText: widget.obscureText, - autocorrect: widget.autocorrect, - smartDashesType: widget.smartDashesType, - smartQuotesType: widget.smartQuotesType, - enableSuggestions: widget.enableSuggestions, - maxLines: widget.maxLines, - minLines: widget.minLines, - expands: widget.expands, - selectionColor: selectionColor, - selectionControls: - widget.selectionEnabled ? textSelectionControls : null, - onChanged: widget.onChanged, - onSelectionChanged: _handleSelectionChanged, - onEditingComplete: widget.onEditingComplete, - onSubmitted: widget.onSubmitted, - inputFormatters: formatters, - rendererIgnoresPointer: true, - cursorWidth: widget.cursorWidth, - cursorHeight: widget.cursorHeight, - cursorRadius: widget.cursorRadius, - cursorColor: cursorColor, - cursorOpacityAnimates: true, - cursorOffset: cursorOffset, - paintCursorAboveText: true, - autocorrectionTextRectColor: selectionColor, - backgroundCursorColor: MacosDynamicColor.resolve( - CupertinoColors.inactiveGray, - context, + return Border( + bottom: borderSide((focusedDecoration.border as Border).bottom), + top: borderSide((focusedDecoration.border as Border).top), + left: borderSide((focusedDecoration.border as Border).left), + right: borderSide((focusedDecoration.border as Border).right), + ); + } + return focusedDecoration.border; + }(), + color: focusedDecoration.color ?? const Color(0x00000000), + ); + + final Color selectionColor = MacosTheme.of( + context, + ).primaryColor.withValues(alpha: 0.2); + + final Widget paddedEditable = Padding( + padding: widget.padding, + child: RepaintBoundary( + child: UnmanagedRestorationScope( + bucket: bucket, + child: EditableText( + key: editableTextKey, + controller: controller, + readOnly: widget.readOnly, + showCursor: widget.showCursor, + showSelectionHandles: _showSelectionHandles, + focusNode: _effectiveFocusNode, + keyboardType: widget.keyboardType, + textInputAction: widget.textInputAction, + textCapitalization: widget.textCapitalization, + style: textStyle, + strutStyle: widget.strutStyle, + textAlign: widget.textAlign, + autofocus: widget.autofocus, + obscuringCharacter: widget.obscuringCharacter, + obscureText: widget.obscureText, + autocorrect: widget.autocorrect, + smartDashesType: widget.smartDashesType, + smartQuotesType: widget.smartQuotesType, + enableSuggestions: widget.enableSuggestions, + maxLines: widget.maxLines, + minLines: widget.minLines, + expands: widget.expands, + selectionColor: selectionColor, + selectionControls: widget.selectionEnabled + ? textSelectionControls + : null, + onChanged: widget.onChanged, + onSelectionChanged: _handleSelectionChanged, + onEditingComplete: widget.onEditingComplete, + onSubmitted: widget.onSubmitted, + inputFormatters: formatters, + rendererIgnoresPointer: true, + cursorWidth: widget.cursorWidth, + cursorHeight: widget.cursorHeight, + cursorRadius: widget.cursorRadius, + cursorColor: cursorColor, + cursorOpacityAnimates: true, + cursorOffset: cursorOffset, + paintCursorAboveText: true, + autocorrectionTextRectColor: selectionColor, + backgroundCursorColor: MacosDynamicColor.resolve( + CupertinoColors.inactiveGray, + context, + ), + selectionHeightStyle: widget.selectionHeightStyle, + selectionWidthStyle: widget.selectionWidthStyle, + scrollPadding: widget.scrollPadding, + keyboardAppearance: keyboardAppearance, + dragStartBehavior: widget.dragStartBehavior, + scrollController: widget.scrollController, + scrollPhysics: widget.scrollPhysics, + enableInteractiveSelection: widget.enableInteractiveSelection, + autofillHints: widget.autofillHints, + restorationId: 'editable', + mouseCursor: SystemMouseCursors.text, + contextMenuBuilder: widget.contextMenuBuilder, + ), ), - selectionHeightStyle: widget.selectionHeightStyle, - selectionWidthStyle: widget.selectionWidthStyle, - scrollPadding: widget.scrollPadding, - keyboardAppearance: keyboardAppearance, - dragStartBehavior: widget.dragStartBehavior, - scrollController: widget.scrollController, - scrollPhysics: widget.scrollPhysics, - enableInteractiveSelection: widget.enableInteractiveSelection, - autofillHints: widget.autofillHints, - restorationId: 'editable', - mouseCursor: SystemMouseCursors.text, - contextMenuBuilder: widget.contextMenuBuilder, ), - ), - ), - ); + ); - return Semantics( - enabled: enabled, - onTap: !enabled || widget.readOnly - ? null - : () { - if (!controller.selection.isValid) { - controller.selection = - TextSelection.collapsed(offset: controller.text.length); - } - _requestKeyboard(); - }, - child: IgnorePointer( - ignoring: !enabled, - child: AnimatedContainer( - /// Value eyeballed from MacOS Big Sur - duration: const Duration(milliseconds: 125), - decoration: _effectiveFocusNode.hasFocus - ? focusedDecoration - : focusedPlaceholderDecoration, - child: Container( - decoration: - _effectiveFocusNode.hasFocus ? null : effectiveDecoration, - child: _selectionGestureDetectorBuilder.buildGestureDetector( - behavior: HitTestBehavior.translucent, - child: Align( - alignment: Alignment(-1.0, _textAlignVertical.y), - widthFactor: 1.0, - heightFactor: 1.0, - child: _addTextDependentAttachments( - paddedEditable, - textStyle, - placeholderStyle, + return Semantics( + enabled: enabled, + onTap: !enabled || widget.readOnly + ? null + : () { + if (!controller.selection.isValid) { + controller.selection = TextSelection.collapsed( + offset: controller.text.length, + ); + } + _requestKeyboard(); + }, + child: IgnorePointer( + ignoring: !enabled, + child: AnimatedContainer( + /// Value eyeballed from MacOS Big Sur + duration: const Duration(milliseconds: 125), + decoration: _effectiveFocusNode.hasFocus + ? focusedDecoration + : focusedPlaceholderDecoration, + child: Container( + decoration: _effectiveFocusNode.hasFocus + ? null + : effectiveDecoration, + child: _selectionGestureDetectorBuilder.buildGestureDetector( + behavior: HitTestBehavior.translucent, + child: Align( + alignment: Alignment(-1.0, _textAlignVertical.y), + widthFactor: 1.0, + heightFactor: 1.0, + child: _addTextDependentAttachments( + paddedEditable, + textStyle, + placeholderStyle, + ), + ), ), ), ), ), - ), - ), + ); + }, ); } } diff --git a/lib/src/icon/image_icon.dart b/lib/src/icon/image_icon.dart index 55986dd1..2e7e8a87 100644 --- a/lib/src/icon/image_icon.dart +++ b/lib/src/icon/image_icon.dart @@ -71,7 +71,7 @@ class MacosImageIcon extends StatelessWidget { Color iconColor = color ?? iconTheme.color!; if (iconOpacity != null && iconOpacity != 1.0) { - iconColor = iconColor.withOpacity(iconColor.opacity * iconOpacity); + iconColor = iconColor.withValues(alpha: iconColor.a * iconOpacity); } return Semantics( @@ -90,12 +90,14 @@ class MacosImageIcon extends StatelessWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty( - 'image', - image, - ifNull: '', - showName: false, - )); + properties.add( + DiagnosticsProperty( + 'image', + image, + ifNull: '', + showName: false, + ), + ); properties.add(DoubleProperty('size', size, defaultValue: null)); properties.add(ColorProperty('color', color, defaultValue: null)); } diff --git a/lib/src/icon/macos_icon.dart b/lib/src/icon/macos_icon.dart index 6664ffb4..26beecaa 100644 --- a/lib/src/icon/macos_icon.dart +++ b/lib/src/icon/macos_icon.dart @@ -1,6 +1,7 @@ import 'package:flutter/foundation.dart'; import 'package:macos_ui/macos_ui.dart'; import 'package:macos_ui/src/library.dart'; +import 'package:vector_math/vector_math_64.dart'; /// An Icon widget that respects a macOS icon theme. class MacosIcon extends StatelessWidget { @@ -85,17 +86,14 @@ class MacosIcon extends StatelessWidget { if (icon == null) { return Semantics( label: semanticLabel, - child: SizedBox( - width: iconSize, - height: iconSize, - ), + child: SizedBox(width: iconSize, height: iconSize), ); } final iconOpacity = iconTheme.opacity ?? 1.0; Color iconColor = color ?? iconTheme.color!; if (iconOpacity != 1.0) { - iconColor = iconColor.withOpacity(iconColor.opacity * iconOpacity); + iconColor = iconColor.withValues(alpha: iconColor.a * iconOpacity); } Widget iconWidget = RichText( @@ -117,7 +115,8 @@ class MacosIcon extends StatelessWidget { switch (textDirection) { case TextDirection.rtl: iconWidget = Transform( - transform: Matrix4.identity()..scale(-1.0, 1.0, 1.0), + transform: Matrix4.identity() + ..scaleByVector3(Vector3(-1.0, 1.0, 1.0)), alignment: Alignment.center, transformHitTests: false, child: iconWidget, @@ -134,9 +133,7 @@ class MacosIcon extends StatelessWidget { child: SizedBox( width: iconSize, height: iconSize, - child: Center( - child: iconWidget, - ), + child: Center(child: iconWidget), ), ), ); @@ -145,12 +142,9 @@ class MacosIcon extends StatelessWidget { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(IconDataProperty( - 'icon', - icon, - ifNull: '', - showName: false, - )); + properties.add( + IconDataProperty('icon', icon, ifNull: '', showName: false), + ); properties.add(DoubleProperty('size', size, defaultValue: null)); properties.add(ColorProperty('color', color, defaultValue: null)); } diff --git a/lib/src/indicators/capacity_indicators.dart b/lib/src/indicators/capacity_indicators.dart index ed26f90f..57d6ab59 100644 --- a/lib/src/indicators/capacity_indicators.dart +++ b/lib/src/indicators/capacity_indicators.dart @@ -80,8 +80,9 @@ class CapacityIndicator extends StatelessWidget { super.debugFillProperties(properties); properties.add(DoubleProperty('value', value)); properties.add(ObjectFlagProperty.has('onChanged', onChanged)); - properties - .add(FlagProperty('discrete', value: discrete, ifFalse: 'continuous')); + properties.add( + FlagProperty('discrete', value: discrete, ifFalse: 'continuous'), + ); properties.add(IntProperty('splits', splits)); properties.add(ColorProperty('color', color)); properties.add(ColorProperty('backgroundColor', backgroundColor)); @@ -101,61 +102,64 @@ class CapacityIndicator extends StatelessWidget { label: semanticLabel, value: value.toStringAsFixed(2), child: Container( - constraints: - const BoxConstraints(minWidth: _kCapacityIndicatorMinWidth), - child: LayoutBuilder(builder: (context, consts) { - double width = consts.maxWidth; - if (width.isInfinite) width = 100; - final splitWidth = width / splits; - if (discrete) { - final fillToIndex = (value / 100) * splits - 1; - return SizedBox( - width: width, - child: GestureDetector( - onPanStart: (event) => - _handleUpdate(event.localPosition, splitWidth), - onPanUpdate: (event) => - _handleUpdate(event.localPosition, splitWidth), - onPanDown: (event) => - _handleUpdate(event.localPosition, splitWidth), - child: Row( - children: List.generate(splits, (index) { - return Container( - padding: EdgeInsets.only( - right: index == splits - 1 ? 0 : 2.0, - ), - width: splitWidth, - child: CapacityIndicatorCell( - value: value > 0 && fillToIndex >= index ? 100 : 0, - backgroundColor: backgroundColor, - borderColor: borderColor, - color: color, - ), - ); - }), + constraints: const BoxConstraints( + minWidth: _kCapacityIndicatorMinWidth, + ), + child: LayoutBuilder( + builder: (context, consts) { + double width = consts.maxWidth; + if (width.isInfinite) width = 100; + final splitWidth = width / splits; + if (discrete) { + final fillToIndex = (value / 100) * splits - 1; + return SizedBox( + width: width, + child: GestureDetector( + onPanStart: (event) => + _handleUpdate(event.localPosition, splitWidth), + onPanUpdate: (event) => + _handleUpdate(event.localPosition, splitWidth), + onPanDown: (event) => + _handleUpdate(event.localPosition, splitWidth), + child: Row( + children: List.generate(splits, (index) { + return Container( + padding: EdgeInsets.only( + right: index == splits - 1 ? 0 : 2.0, + ), + width: splitWidth, + child: CapacityIndicatorCell( + value: value > 0 && fillToIndex >= index ? 100 : 0, + backgroundColor: backgroundColor, + borderColor: borderColor, + color: color, + ), + ); + }), + ), ), - ), - ); - } else { - return SizedBox( - width: width, - child: GestureDetector( - onPanStart: (event) => - _handleUpdate(event.localPosition, splitWidth), - onPanUpdate: (event) => - _handleUpdate(event.localPosition, splitWidth), - onPanDown: (event) => - _handleUpdate(event.localPosition, splitWidth), - child: CapacityIndicatorCell( - value: value, - backgroundColor: backgroundColor, - borderColor: borderColor, - color: color, + ); + } else { + return SizedBox( + width: width, + child: GestureDetector( + onPanStart: (event) => + _handleUpdate(event.localPosition, splitWidth), + onPanUpdate: (event) => + _handleUpdate(event.localPosition, splitWidth), + onPanDown: (event) => + _handleUpdate(event.localPosition, splitWidth), + child: CapacityIndicatorCell( + value: value, + backgroundColor: backgroundColor, + borderColor: borderColor, + color: color, + ), ), - ), - ); - } - }), + ); + } + }, + ), ), ); } @@ -221,7 +225,9 @@ class _CapacityCellPainter extends CustomPainter { /// Draw background canvas.drawRRect( - BorderRadius.circular(radius).toRRect(Offset.zero & size), + const BorderRadius.all( + Radius.circular(radius), + ).toRRect(Offset.zero & size), Paint()..color = backgroundColor, ); @@ -238,7 +244,9 @@ class _CapacityCellPainter extends CustomPainter { /// Draw border canvas.drawRRect( - BorderRadius.circular(radius).toRRect(Offset.zero & size), + const BorderRadius.all( + Radius.circular(radius), + ).toRRect(Offset.zero & size), Paint() ..color = borderColor ..style = PaintingStyle.stroke diff --git a/lib/src/indicators/progress_indicators.dart b/lib/src/indicators/progress_indicators.dart index 6fe47cd9..8124d330 100644 --- a/lib/src/indicators/progress_indicators.dart +++ b/lib/src/indicators/progress_indicators.dart @@ -20,8 +20,8 @@ class ProgressCircle extends StatelessWidget { this.innerColor, this.borderColor, this.semanticLabel, - }) : assert(value == null || value >= 0 && value <= 100), - assert(radius >= 0); + }) : assert(value == null || value >= 0 && value <= 100), + assert(radius >= 0); /// The value of the progress circle. If non-null, this has to /// be non-negative and less the 100. If null, the progress circle @@ -53,11 +53,13 @@ class ProgressCircle extends StatelessWidget { properties.add(ColorProperty('innerColor', innerColor)); properties.add(ColorProperty('borderColor', borderColor)); properties.add(StringProperty('semanticLabel', semanticLabel)); - properties.add(FlagProperty( - 'determinate', - value: isDeterminate, - ifFalse: 'indeterminate', - )); + properties.add( + FlagProperty( + 'determinate', + value: isDeterminate, + ifFalse: 'indeterminate', + ), + ); } @override @@ -87,9 +89,7 @@ class ProgressCircle extends StatelessWidget { } else { return Semantics( label: semanticLabel, - child: c.CupertinoActivityIndicator( - radius: radius, - ), + child: c.CupertinoActivityIndicator(radius: radius), ); } } @@ -114,11 +114,7 @@ class _DeterminateCirclePainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { /// Draw an arc - void drawArc( - double value, { - Paint? paint, - bool useCenter = true, - }) { + void drawArc(double value, {Paint? paint, bool useCenter = true}) { canvas.drawArc( Offset.zero & size, _startAngle, @@ -163,8 +159,8 @@ class ProgressBar extends StatelessWidget { this.trackColor, this.backgroundColor, this.semanticLabel, - }) : assert(value >= 0 && value <= 100), - assert(height >= 0); + }) : assert(value >= 0 && value <= 100), + assert(height >= 0); /// The value of the progress bar. If non-null, this has to /// be non-negative and less the 100. If null, the progress bar @@ -240,9 +236,7 @@ class _DeterminateBarPainter extends CustomPainter { void paint(Canvas canvas, Size size) { // Draw the background line canvas.drawRRect( - const BorderRadius.all(Radius.circular(100)).toRRect( - Offset.zero & size, - ), + const BorderRadius.all(Radius.circular(100)).toRRect(Offset.zero & size), Paint() ..color = backgroundColor ?? CupertinoColors.secondarySystemFill ..style = PaintingStyle.fill, @@ -252,10 +246,7 @@ class _DeterminateBarPainter extends CustomPainter { canvas.drawRRect( const BorderRadius.horizontal(left: Radius.circular(100)).toRRect( Offset.zero & - Size( - (value / 100).clamp(0.0, 1.0) * size.width, - size.height, - ), + Size((value / 100).clamp(0.0, 1.0) * size.width, size.height), ), Paint() ..color = activeColor ?? CupertinoColors.activeBlue diff --git a/lib/src/indicators/rating_indicator.dart b/lib/src/indicators/rating_indicator.dart index eb3cdb7c..172174fb 100644 --- a/lib/src/indicators/rating_indicator.dart +++ b/lib/src/indicators/rating_indicator.dart @@ -28,9 +28,9 @@ class RatingIndicator extends StatelessWidget { this.iconSize = 16, this.onChanged, this.semanticLabel, - }) : assert(iconSize >= 0), - assert(amount > 0), - assert(value >= 0 && value <= amount); + }) : assert(iconSize >= 0), + assert(amount > 0), + assert(value >= 0 && value <= amount); /// The icon used when the star is rated. [CupertinoIcons.star_fill] /// is used by default. If you must replace the star with a custom diff --git a/lib/src/indicators/relevance_indicator.dart b/lib/src/indicators/relevance_indicator.dart index 5d8d0dd2..78482622 100644 --- a/lib/src/indicators/relevance_indicator.dart +++ b/lib/src/indicators/relevance_indicator.dart @@ -23,10 +23,10 @@ class RelevanceIndicator extends StatelessWidget { this.selectedColor = CupertinoColors.label, this.unselectedColor = CupertinoColors.secondaryLabel, this.semanticLabel, - }) : assert(value >= 0 && value <= amount), - assert(amount > 0), - assert(barHeight >= 0), - assert(barWidth >= 0); + }) : assert(value >= 0 && value <= amount), + assert(amount > 0), + assert(barHeight >= 0), + assert(barWidth >= 0); /// The current value of the indicator. It must be in the range /// of 0 to [amount] diff --git a/lib/src/indicators/slider.dart b/lib/src/indicators/slider.dart index e32fc360..f8dde671 100644 --- a/lib/src/indicators/slider.dart +++ b/lib/src/indicators/slider.dart @@ -36,9 +36,9 @@ class MacosSlider extends StatelessWidget { this.tickBackgroundColor = MacosColors.tickBackgroundColor, this.thumbColor = MacosColors.sliderThumbColor, this.semanticLabel, - }) : assert(value >= min && value <= max), - assert(min < max), - assert(splits >= 2); + }) : assert(value >= min && value <= max), + assert(min < max), + assert(splits >= 2); /// The value of this slider. /// @@ -99,8 +99,9 @@ class MacosSlider extends StatelessWidget { properties.add(ColorProperty('backgroundColor', backgroundColor)); properties.add(ColorProperty('tickBackgroundColor', tickBackgroundColor)); properties.add(ColorProperty('thumbColor', thumbColor)); - properties - .add(FlagProperty('discrete', value: discrete, ifTrue: 'discrete')); + properties.add( + FlagProperty('discrete', value: discrete, ifTrue: 'discrete'), + ); properties.add(IntProperty('splits', splits)); properties.add(StringProperty('semanticLabel', semanticLabel)); } @@ -168,8 +169,9 @@ class MacosSlider extends StatelessWidget { children: [ Center( child: Container( - margin: - EdgeInsets.symmetric(horizontal: horizontalPadding), + margin: EdgeInsets.symmetric( + horizontal: horizontalPadding, + ), height: _kSliderHeight, width: width, decoration: BoxDecoration( @@ -186,8 +188,9 @@ class MacosSlider extends StatelessWidget { Align( alignment: Alignment.centerLeft, child: Container( - margin: - EdgeInsets.symmetric(horizontal: horizontalPadding), + margin: EdgeInsets.symmetric( + horizontal: horizontalPadding, + ), height: _kSliderHeight, width: width * _percentage, decoration: BoxDecoration( @@ -200,8 +203,9 @@ class MacosSlider extends StatelessWidget { ), if (discrete) Padding( - padding: - EdgeInsets.symmetric(horizontal: horizontalPadding), + padding: EdgeInsets.symmetric( + horizontal: horizontalPadding, + ), child: SizedBox( height: _kOverallHeight, width: width, @@ -229,8 +233,10 @@ class MacosSlider extends StatelessWidget { horizontal: horizontalPadding, ), child: _ContinuousThumb( - color: - MacosDynamicColor.resolve(thumbColor, context), + color: MacosDynamicColor.resolve( + thumbColor, + context, + ), ), ), ), @@ -244,8 +250,10 @@ class MacosSlider extends StatelessWidget { horizontal: horizontalPadding, ), child: _DiscreteThumb( - color: - MacosDynamicColor.resolve(thumbColor, context), + color: MacosDynamicColor.resolve( + thumbColor, + context, + ), ), ), ), @@ -261,9 +269,7 @@ class MacosSlider extends StatelessWidget { } class _ContinuousThumb extends StatelessWidget { - const _ContinuousThumb({ - required this.color, - }); + const _ContinuousThumb({required this.color}); final Color color; @@ -274,8 +280,9 @@ class _ContinuousThumb extends StatelessWidget { width: _kContinuousThumbSize, decoration: BoxDecoration( color: color, - borderRadius: - const BorderRadius.all(Radius.circular(_kContinuousThumbSize)), + borderRadius: const BorderRadius.all( + Radius.circular(_kContinuousThumbSize), + ), boxShadow: const [ BoxShadow( color: Color.fromRGBO(0, 0, 0, 0.1), @@ -290,9 +297,7 @@ class _ContinuousThumb extends StatelessWidget { } class _DiscreteThumb extends StatelessWidget { - const _DiscreteThumb({ - required this.color, - }); + const _DiscreteThumb({required this.color}); final Color color; @override diff --git a/lib/src/labels/tooltip.dart b/lib/src/labels/tooltip.dart index 35022953..90518765 100644 --- a/lib/src/labels/tooltip.dart +++ b/lib/src/labels/tooltip.dart @@ -92,8 +92,9 @@ class _MacosTooltipState extends State vsync: this, )..addStatusListener(_handleStatusChanged); // Listen to see when a mouse is added. - RendererBinding.instance.mouseTracker - .addListener(_handleMouseTrackerChange); + RendererBinding.instance.mouseTracker.addListener( + _handleMouseTrackerChange, + ); // Listen to global pointer events so that we can hide a tooltip immediately // if some other control is clicked on. GestureBinding.instance.pointerRouter.addGlobalRoute(_handlePointerEvent); @@ -244,10 +245,12 @@ class _MacosTooltipState extends State @override void dispose() { - GestureBinding.instance.pointerRouter - .removeGlobalRoute(_handlePointerEvent); - RendererBinding.instance.mouseTracker - .removeListener(_handleMouseTrackerChange); + GestureBinding.instance.pointerRouter.removeGlobalRoute( + _handlePointerEvent, + ); + RendererBinding.instance.mouseTracker.removeListener( + _handleMouseTrackerChange, + ); if (_entry != null) _removeEntry(); _controller.dispose(); super.dispose(); @@ -392,10 +395,7 @@ class _TooltipOverlay extends StatelessWidget { child: Center( widthFactor: 1.0, heightFactor: 1.0, - child: Text( - message, - style: textStyle, - ), + child: Text(message, style: textStyle), ), ), ), diff --git a/lib/src/layout/content_area.dart b/lib/src/layout/content_area.dart index 5026e260..a7f6b915 100644 --- a/lib/src/layout/content_area.dart +++ b/lib/src/layout/content_area.dart @@ -10,10 +10,8 @@ class ContentArea extends StatelessWidget { /// /// The width of this /// widget is automatically calculated in [MacosScaffoldScope]. - const ContentArea({ - required this.builder, - this.minWidth = 300, - }) : super(key: const Key('macos_scaffold_content_area')); + const ContentArea({required this.builder, this.minWidth = 300}) + : super(key: const Key('macos_scaffold_content_area')); /// The builder that creates a child to display in this widget. final ScrollableWidgetBuilder? builder; @@ -24,9 +22,7 @@ class ContentArea extends StatelessWidget { @override Widget build(BuildContext context) { return ConstrainedBox( - constraints: const BoxConstraints.expand().copyWith( - minWidth: minWidth, - ), + constraints: const BoxConstraints.expand().copyWith(minWidth: minWidth), child: SafeArea( left: false, right: false, diff --git a/lib/src/layout/macos_list_tile.dart b/lib/src/layout/macos_list_tile.dart index 1251e755..2bac3daf 100644 --- a/lib/src/layout/macos_list_tile.dart +++ b/lib/src/layout/macos_list_tile.dart @@ -56,16 +56,14 @@ class MacosListTile extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ DefaultTextStyle( - style: MacosTheme.of(context).typography.headline.copyWith( - fontWeight: FontWeight.bold, - ), + style: MacosTheme.of( + context, + ).typography.headline.copyWith(fontWeight: FontWeight.bold), child: title, ), if (subtitle != null) DefaultTextStyle( - style: MacosTheme.of(context) - .typography - .subheadline + style: MacosTheme.of(context).typography.subheadline .copyWith( color: MacosTheme.brightnessOf(context).isDark ? MacosColors.systemGrayColor diff --git a/lib/src/layout/resizable_pane.dart b/lib/src/layout/resizable_pane.dart index 97836bdd..837c83a7 100644 --- a/lib/src/layout/resizable_pane.dart +++ b/lib/src/layout/resizable_pane.dart @@ -46,16 +46,13 @@ class ResizablePane extends StatefulWidget { required this.resizableSide, this.windowBreakpoint, required this.startSize, - }) : child = null, - useScrollBar = true, - assert( - maxSize >= minSize, - 'minSize should not be more than maxSize.', - ), - assert( - (startSize >= minSize) && (startSize <= maxSize), - 'startSize must not be less than minSize or more than maxWidth', - ); + }) : child = null, + useScrollBar = true, + assert(maxSize >= minSize, 'minSize should not be more than maxSize.'), + assert( + (startSize >= minSize) && (startSize <= maxSize), + 'startSize must not be less than minSize or more than maxWidth', + ); /// Creates a [ResizablePane] without an internal [MacosScrollbar]. /// @@ -75,16 +72,13 @@ class ResizablePane extends StatefulWidget { required this.resizableSide, this.windowBreakpoint, required this.startSize, - }) : builder = null, - useScrollBar = false, - assert( - maxSize >= minSize, - 'minSize should not be more than maxSize.', - ), - assert( - (startSize >= minSize) && (startSize <= maxSize), - 'startSize must not be less than minSize or more than maxWidth', - ); + }) : builder = null, + useScrollBar = false, + assert(maxSize >= minSize, 'minSize should not be more than maxSize.'), + assert( + (startSize >= minSize) && (startSize <= maxSize), + 'startSize must not be less than minSize or more than maxWidth', + ); /// The builder that creates a child to display in this widget, which will /// use the provided [_scrollController] to enable the scrollbar to work. @@ -206,14 +200,12 @@ class _ResizablePaneState extends State { }, onVerticalDragUpdate: (details) { setState(() { - final newHeight = _dragStartSize + + final newHeight = + _dragStartSize + (_dragStartPosition - details.globalPosition.dy); _size = math.max( widget.minSize, - math.min( - widget.maxSize, - newHeight, - ), + math.min(widget.maxSize, newHeight), ); if (_size == widget.minSize) { _cursor = SystemMouseCursors.resizeUp; @@ -239,15 +231,12 @@ class _ResizablePaneState extends State { setState(() { final newWidth = _resizeOnRight ? _dragStartSize - - (_dragStartPosition - details.globalPosition.dx) + (_dragStartPosition - details.globalPosition.dx) : _dragStartSize + - (_dragStartPosition - details.globalPosition.dx); + (_dragStartPosition - details.globalPosition.dx); _size = math.max( widget.minSize, - math.min( - widget.maxSize, - newWidth, - ), + math.min(widget.maxSize, newWidth), ); if (_size == widget.minSize) { _cursor = _resizeOnRight @@ -343,12 +332,7 @@ class _ResizablePaneState extends State { child: _resizeArea, ), if (widget.isResizable && _resizeOnTop) - Positioned( - top: 0, - width: maxWidth, - height: 5, - child: _resizeArea, - ), + Positioned(top: 0, width: maxWidth, height: 5, child: _resizeArea), ], ), ); diff --git a/lib/src/layout/scaffold.dart b/lib/src/layout/scaffold.dart index 59678372..96fe8273 100644 --- a/lib/src/layout/scaffold.dart +++ b/lib/src/layout/scaffold.dart @@ -96,9 +96,7 @@ class _MacosScaffoldState extends State { ), ] else ...[ // Background color - Positioned.fill( - child: ColoredBox(color: backgroundColor), - ), + Positioned.fill(child: ColoredBox(color: backgroundColor)), // Content Area Positioned( @@ -129,14 +127,13 @@ class _MacosScaffoldState extends State { } class _ScaffoldBody extends MultiChildRenderObjectWidget { - const _ScaffoldBody({ - super.children, - }); + const _ScaffoldBody({super.children}); @override RenderObject createRenderObject(BuildContext context) { - final index = children - .indexWhere((e) => e.key == const Key('macos_scaffold_content_area')); + final index = children.indexWhere( + (e) => e.key == const Key('macos_scaffold_content_area'), + ); return _RenderScaffoldBody(contentAreaIndex: index > -1 ? index : null); } @@ -145,8 +142,9 @@ class _ScaffoldBody extends MultiChildRenderObjectWidget { BuildContext context, _RenderScaffoldBody renderObject, ) { - final index = children - .indexWhere((e) => e.key == const Key('macos_scaffold_content_area')); + final index = children.indexWhere( + (e) => e.key == const Key('macos_scaffold_content_area'), + ); renderObject.contentAreaIndex = index > -1 ? index : null; } } diff --git a/lib/src/layout/scrollbar.dart b/lib/src/layout/scrollbar.dart index 1cfc819b..37c3f40c 100644 --- a/lib/src/layout/scrollbar.dart +++ b/lib/src/layout/scrollbar.dart @@ -113,15 +113,15 @@ class _RawMacosScrollBar extends RawScrollbar { super.scrollbarOrientation, required this.effectiveThumbColor, super.radius, - }) : assert(thickness != null && thickness < double.infinity), - assert(thicknessWhileHovering < double.infinity), - super( - thumbVisibility: thumbVisibility ?? false, - fadeDuration: _kScrollbarFadeDuration, - timeToFade: _kScrollbarTimeToFade, - notificationPredicate: - notificationPredicate ?? defaultScrollNotificationPredicate, - ); + }) : assert(thickness != null && thickness < double.infinity), + assert(thicknessWhileHovering < double.infinity), + super( + thumbVisibility: thumbVisibility ?? false, + fadeDuration: _kScrollbarFadeDuration, + timeToFade: _kScrollbarTimeToFade, + notificationPredicate: + notificationPredicate ?? defaultScrollNotificationPredicate, + ); final double thicknessWhileHovering; final Color effectiveThumbColor; @@ -156,7 +156,7 @@ class _RawMacosScrollBarState extends RawScrollbarState<_RawMacosScrollBar> { ); _trackColorTween = ColorTween( begin: MacosColors.transparent, - end: widget.effectiveThumbColor.withOpacity(0.15), + end: widget.effectiveThumbColor.withValues(alpha: 0.15), ).animate(_trackColorAnimationController); _thumbThicknessAnimationController.addListener(() { updateScrollbarPainter(); diff --git a/lib/src/layout/sidebar/sidebar_item.dart b/lib/src/layout/sidebar/sidebar_item.dart index e2666f20..e03989c0 100644 --- a/lib/src/layout/sidebar/sidebar_item.dart +++ b/lib/src/layout/sidebar/sidebar_item.dart @@ -21,6 +21,7 @@ class SidebarItem with Diagnosticable { this.disclosureItems, this.expandDisclosureItems = false, this.trailing, + this.section = false, }); /// The widget before [label]. @@ -71,6 +72,9 @@ class SidebarItem with Diagnosticable { /// final Widget? trailing; + /// If true, this item is a section header. + final bool? section; + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); @@ -79,12 +83,12 @@ class SidebarItem with Diagnosticable { properties.add(StringProperty('semanticLabel', semanticLabel)); properties.add(DiagnosticsProperty('shape', shape)); properties.add(DiagnosticsProperty('focusNode', focusNode)); - properties.add(IterableProperty( - 'disclosure items', - disclosureItems, - )); properties.add( - FlagProperty('expandDisclosureItems', value: expandDisclosureItems)); + IterableProperty('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 6000789c..43e8b82e 100644 --- a/lib/src/layout/sidebar/sidebar_items.dart +++ b/lib/src/layout/sidebar/sidebar_items.dart @@ -24,10 +24,7 @@ enum SidebarItemSize { large(36.0, 18.0); /// {@macro sidebarItemSize} - const SidebarItemSize( - this.height, - this.iconSize, - ); + const SidebarItemSize(this.height, this.iconSize); /// The height of the [SidebarItem]. final double height; @@ -118,7 +115,7 @@ class SidebarItems extends StatelessWidget { for (var element in items) { if (element.disclosureItems != null) { result.addAll(element.disclosureItems!); - } else { + } else if (element.section == false) { result.add(element); } } @@ -147,10 +144,23 @@ class SidebarItems extends StatelessWidget { child: ListView( controller: scrollController, physics: const ClampingScrollPhysics(), - padding: - EdgeInsets.all(10.0 - theme.visualDensity.horizontal), + padding: EdgeInsets.all( + 10.0 - theme.visualDensity.horizontal, + ), children: List.generate(items.length, (index) { final item = items[index]; + if (item.section == true && item.disclosureItems != null) { + return _DisclosureSidebarHeaderItem( + item: item, + selectedItem: _allItems[currentIndex], + onChanged: (item) { + onChanged(_allItems.indexOf(item)); + }, + ); + } + if (item.section == true) { + return _SidebarHeaderItem(item: item); + } if (item.disclosureItems != null) { return MouseRegion( cursor: cursor!, @@ -209,6 +219,98 @@ class _SidebarItemsConfiguration extends InheritedWidget { } } +class _SidebarHeaderItem extends StatelessWidget { + // ignore: use_super_parameters + const _SidebarHeaderItem({Key? key, required this.item}) : super(key: key); + + final SidebarItem item; + + bool get hasLeading => item.leading != null; + bool get hasTrailing => item.trailing != null; + + DefaultTextStyle _buildLabelWithDefaultTextStyle( + TextStyle labelStyle, + BuildContext context, + ) { + final isDarkModeEnabled = MacosTheme.of(context).brightness.isDark; + + return DefaultTextStyle( + style: labelStyle.copyWith( + fontWeight: FontWeight.bold, + fontSize: (labelStyle.fontSize ?? 14.0) * 0.85, + color: isDarkModeEnabled + ? MacosColors.white.withValues(alpha: 0.3) + : MacosColors.black.withValues(alpha: 0.3), + overflow: TextOverflow.ellipsis, + ), + child: item.label, + ); + } + + @override + Widget build(BuildContext context) { + assert(debugCheckHasMacosTheme(context)); + final theme = MacosTheme.of(context); + + final double spacing = 10.0 + theme.visualDensity.horizontal; + final itemSize = _SidebarItemsConfiguration.of(context).itemSize; + + TextStyle? labelStyle; + switch (itemSize) { + case SidebarItemSize.small: + labelStyle = theme.typography.subheadline; + break; + case SidebarItemSize.medium: + labelStyle = theme.typography.body; + break; + case SidebarItemSize.large: + labelStyle = theme.typography.title3; + break; + } + + return Semantics( + label: item.semanticLabel, + child: Container( + width: 134.0 + theme.visualDensity.horizontal, + height: itemSize.height + theme.visualDensity.vertical, + decoration: ShapeDecoration( + color: MacosColors.transparent, + shape: item.shape ?? _SidebarItemsConfiguration.of(context).shape, + ), + padding: EdgeInsets.symmetric( + vertical: 7 + theme.visualDensity.horizontal, + horizontal: spacing, + ), + child: Row( + children: [ + if (hasLeading) + Padding( + padding: EdgeInsets.only(right: spacing), + child: MacosIconTheme.merge( + data: MacosIconThemeData( + color: theme.primaryColor, + size: itemSize.iconSize, + ), + child: item.leading!, + ), + ), + Expanded( + child: _buildLabelWithDefaultTextStyle(labelStyle, context), + ), + if (hasTrailing) ...[ + const Spacer(), + DefaultTextStyle( + style: labelStyle.copyWith(color: null), + child: item.trailing!, + ), + ], + ], + ), + ), + ); + } +} + /// A macOS style navigation-list item intended for use in a [Sidebar] class _SidebarItem extends StatelessWidget { /// Builds a [_SidebarItem]. @@ -235,16 +337,46 @@ class _SidebarItem extends StatelessWidget { void _handleActionTap() => onClick?.call(); - Map> get _actionMap => >{ - ActivateIntent: CallbackAction( - onInvoke: (ActivateIntent intent) => _handleActionTap(), - ), - ButtonActivateIntent: CallbackAction( - onInvoke: (ButtonActivateIntent intent) => _handleActionTap(), + DefaultTextStyle _buildLabelWithDefaultTextStyle( + TextStyle labelStyle, + Color selectedColor, + BuildContext context, + ) { + if (item.section ?? true) { + final isDarkModeEnabled = MacosTheme.of(context).brightness.isDark; + + return DefaultTextStyle( + style: labelStyle.copyWith( + fontWeight: FontWeight.bold, + fontSize: (labelStyle.fontSize ?? 14.0) * 0.85, + color: isDarkModeEnabled + ? MacosColors.white.withValues(alpha: 0.3) + : MacosColors.black.withValues(alpha: 0.3), + overflow: TextOverflow.ellipsis, ), - }; + child: item.label, + ); + } + return DefaultTextStyle( + style: labelStyle.copyWith( + color: selected ? textLuminance(selectedColor) : null, + overflow: TextOverflow.ellipsis, + ), + child: item.label, + ); + } + + Map> get _actionMap => >{ + ActivateIntent: CallbackAction( + onInvoke: (ActivateIntent intent) => _handleActionTap(), + ), + ButtonActivateIntent: CallbackAction( + onInvoke: (ButtonActivateIntent intent) => _handleActionTap(), + ), + }; bool get hasLeading => item.leading != null; + bool get hasTrailing => item.trailing != null; @override @@ -265,6 +397,7 @@ class _SidebarItem extends StatelessWidget { final double spacing = 10.0 + theme.visualDensity.horizontal; final itemSize = _SidebarItemsConfiguration.of(context).itemSize; + TextStyle? labelStyle; switch (itemSize) { case SidebarItemSize.small: @@ -311,24 +444,22 @@ class _SidebarItem extends StatelessWidget { padding: EdgeInsets.only(right: spacing), child: MacosIconTheme.merge( data: MacosIconThemeData( - color: - selected ? MacosColors.white : theme.primaryColor, + color: selected + ? MacosColors.white + : theme.primaryColor, size: itemSize.iconSize, ), child: item.leading!, ), ), Expanded( - child: DefaultTextStyle( - style: labelStyle.copyWith( - color: selected ? textLuminance(selectedColor) : null, - overflow: TextOverflow.ellipsis, - ), - child: item.label, + child: _buildLabelWithDefaultTextStyle( + labelStyle, + selectedColor, + context, ), ), if (hasTrailing) ...[ - const Spacer(), DefaultTextStyle( style: labelStyle.copyWith( color: selected ? textLuminance(selectedColor) : null, @@ -345,6 +476,212 @@ class _SidebarItem extends StatelessWidget { } } +class _DisclosureSidebarHeaderItem extends StatefulWidget { + // ignore: use_super_parameters + const _DisclosureSidebarHeaderItem({ + Key? key, + required this.item, + this.selectedItem, + this.onChanged, + }) : super(key: key); + + final SidebarItem item; + + final SidebarItem? selectedItem; + + /// A function to perform when the widget is clicked or tapped. + /// + /// Typically a [Navigator] call + final ValueChanged? onChanged; + + @override + __DisclosureSidebarHeaderState createState() => + __DisclosureSidebarHeaderState(); +} + +class __DisclosureSidebarHeaderState extends State<_DisclosureSidebarHeaderItem> + with SingleTickerProviderStateMixin { + static final Animatable _easeInTween = CurveTween( + curve: Curves.easeIn, + ); + static final Animatable _halfTween = Tween( + begin: 0, + end: 0.25, + ); + + late AnimationController _controller; + late Animation _iconTurns; + late Animation _heightFactor; + late bool _isExpanded; + bool _isHovering = false; + + bool get hasLeading => widget.item.leading != null; + + @override + void initState() { + super.initState(); + _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() { + setState(() { + _isExpanded = !_isExpanded; + if (_isExpanded) { + _controller.forward(); + } else { + _controller.reverse().then((void value) { + if (!mounted) return; + setState(() { + // Rebuild without widget.children. + }); + }); + } + PageStorage.of(context).writeState(context, _isExpanded); + }); + // widget.onExpansionChanged?.call(_isExpanded); + } + + Widget _buildChildren(BuildContext context, Widget? child) { + final theme = MacosTheme.of(context); + + final itemSize = _SidebarItemsConfiguration.of(context).itemSize; + TextStyle? labelStyle; + switch (itemSize) { + case SidebarItemSize.small: + labelStyle = theme.typography.subheadline; + break; + case SidebarItemSize.medium: + labelStyle = theme.typography.body; + break; + case SidebarItemSize.large: + labelStyle = theme.typography.title3; + break; + } + + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: double.infinity, + child: MouseRegion( + onEnter: (e) => { + setState(() { + _isHovering = true; + }), + }, + onExit: (e) => { + setState(() { + _isHovering = false; + }), + }, + child: _SidebarItem( + item: SidebarItem( + section: true, + label: widget.item.label, + leading: (hasLeading) + ? Padding( + padding: const EdgeInsets.all(0), + child: MacosIconTheme.merge( + data: MacosIconThemeData(size: itemSize.iconSize), + child: widget.item.leading!, + ), + ) + : null, + unselectedColor: MacosColors.transparent, + focusNode: widget.item.focusNode, + semanticLabel: widget.item.semanticLabel, + shape: widget.item.shape, + trailing: Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + if (widget.item.trailing != null) widget.item.trailing!, + if (_isHovering) + RotationTransition( + turns: _iconTurns, + child: Icon( + CupertinoIcons.chevron_right, + size: 14.0, + color: theme.brightness == Brightness.light + ? MacosColors.black.withValues(alpha: 0.3) + : MacosColors.white.withValues(alpha: 0.3), + ), + ), + ], + ), + ), + onClick: _handleTap, + selected: false, + ), + ), + ), + ClipRect( + child: DefaultTextStyle( + style: labelStyle, + child: Align( + alignment: Alignment.centerLeft, + heightFactor: _heightFactor.value, + child: child, + ), + ), + ), + ], + ); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + assert(debugCheckHasMacosTheme(context)); + final theme = MacosTheme.of(context); + + final bool closed = !_isExpanded && _controller.isDismissed; + + final Widget result = Offstage( + offstage: closed, + child: TickerMode( + enabled: !closed, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: widget.item.disclosureItems!.map((item) { + return Padding( + padding: EdgeInsets.only( + left: 24.0 + theme.visualDensity.horizontal, + ), + child: SizedBox( + width: double.infinity, + child: _SidebarItem( + item: item, + onClick: () => widget.onChanged?.call(item), + selected: widget.selectedItem == item, + ), + ), + ); + }).toList(), + ), + ), + ); + + return AnimatedBuilder( + animation: _controller.view, + builder: _buildChildren, + child: closed ? null : result, + ); + } +} + class _DisclosureSidebarItem extends StatefulWidget { // ignore: use_super_parameters _DisclosureSidebarItem({ @@ -352,8 +689,8 @@ class _DisclosureSidebarItem extends StatefulWidget { required this.item, this.selectedItem, this.onChanged, - }) : assert(item.disclosureItems != null), - super(key: key); + }) : assert(item.disclosureItems != null), + super(key: key); final SidebarItem item; @@ -370,10 +707,13 @@ class _DisclosureSidebarItem extends StatefulWidget { class __DisclosureSidebarItemState extends State<_DisclosureSidebarItem> with SingleTickerProviderStateMixin { - static final Animatable _easeInTween = - CurveTween(curve: Curves.easeIn); - static final Animatable _halfTween = - Tween(begin: 0.0, end: 0.25); + static final Animatable _easeInTween = CurveTween( + curve: Curves.easeIn, + ); + static final Animatable _halfTween = Tween( + begin: 0.0, + end: 0.25, + ); late AnimationController _controller; late Animation _iconTurns; diff --git a/lib/src/layout/tab_view/tab.dart b/lib/src/layout/tab_view/tab.dart index d8edcdd8..1588db06 100644 --- a/lib/src/layout/tab_view/tab.dart +++ b/lib/src/layout/tab_view/tab.dart @@ -2,9 +2,7 @@ import 'package:macos_ui/src/library.dart'; import 'package:macos_ui/src/theme/macos_colors.dart'; import 'package:macos_ui/src/theme/macos_theme.dart'; -const _kTabBorderRadius = BorderRadius.all( - Radius.circular(4.0), -); +const _kTabBorderRadius = BorderRadius.all(Radius.circular(4.0)); /// {@template macosTab} /// A macOS-style navigational button used to move between the views of a @@ -12,11 +10,7 @@ const _kTabBorderRadius = BorderRadius.all( /// {@endtemplate} class MacosTab extends StatelessWidget { /// {@macro macosTab} - const MacosTab({ - super.key, - required this.label, - this.active = false, - }); + const MacosTab({super.key, required this.label, this.active = false}); /// The display label for this tab. final String label; @@ -35,10 +29,7 @@ class MacosTab extends StatelessWidget { decoration: BoxDecoration( borderRadius: _kTabBorderRadius, color: active - ? brightness.resolve( - MacosColors.white, - const Color(0xFF646669), - ) + ? brightness.resolve(MacosColors.white, const Color(0xFF646669)) : MacosColors.transparent, ), child: Padding( @@ -50,13 +41,7 @@ class MacosTab extends StatelessWidget { } /// Copies this [MacosTab] into another. - MacosTab copyWith({ - String? label, - bool? active, - }) { - return MacosTab( - label: label ?? this.label, - active: active ?? this.active, - ); + MacosTab copyWith({String? label, bool? active}) { + return MacosTab(label: label ?? this.label, active: active ?? this.active); } } diff --git a/lib/src/layout/tab_view/tab_controller.dart b/lib/src/layout/tab_view/tab_controller.dart index 2eab2521..74517f97 100644 --- a/lib/src/layout/tab_view/tab_controller.dart +++ b/lib/src/layout/tab_view/tab_controller.dart @@ -10,13 +10,11 @@ import 'package:flutter/widgets.dart'; /// {@endtemplate} class MacosTabController extends ChangeNotifier { /// {@macro macosTabController} - MacosTabController({ - int initialIndex = 0, - required this.length, - }) : assert(length >= 0), - assert(initialIndex >= 0 && (length == 0 || initialIndex < length)), - _index = initialIndex, - _previousIndex = initialIndex; + MacosTabController({int initialIndex = 0, required this.length}) + : assert(length >= 0), + assert(initialIndex >= 0 && (length == 0 || initialIndex < length)), + _index = initialIndex, + _previousIndex = initialIndex; /// The total number of tabs. /// diff --git a/lib/src/layout/tab_view/tab_view.dart b/lib/src/layout/tab_view/tab_view.dart index cca58d2a..d6966b07 100644 --- a/lib/src/layout/tab_view/tab_view.dart +++ b/lib/src/layout/tab_view/tab_view.dart @@ -4,9 +4,7 @@ import 'package:macos_ui/src/layout/tab_view/tab_controller.dart'; import 'package:macos_ui/src/library.dart'; import 'package:macos_ui/src/theme/macos_theme.dart'; -const _kTabViewRadius = BorderRadius.all( - Radius.circular(5.0), -); +const _kTabViewRadius = BorderRadius.all(Radius.circular(5.0)); /// Specifies layout position for [MacosTab] options inside [MacosTabView]. enum MacosTabPosition { @@ -26,6 +24,7 @@ enum MacosTabPosition { /// {@template macosTabView} /// A multipage interface that displays one page at a time. /// +// ignore: unintended_html_in_doc_comment /// /// /// A tab view contains a row of navigational items, [tabs], that move the @@ -44,8 +43,10 @@ class MacosTabView extends StatefulWidget { required this.children, this.position = MacosTabPosition.top, this.padding = const EdgeInsets.all(12.0), - }) : assert(controller.length == children.length && - controller.length == tabs.length); + }) : assert( + controller.length == children.length && + controller.length == tabs.length, + ); /// This widget's selection state. final MacosTabController controller; @@ -166,10 +167,7 @@ class _MacosTabViewState extends State { const Color(0xFFE6E9EA), const Color(0xFF2B2E33), ), - border: Border.all( - color: outerBorderColor, - width: 1.0, - ), + border: Border.all(color: outerBorderColor, width: 1.0), borderRadius: _kTabViewRadius, ), child: IndexedStack( diff --git a/lib/src/layout/title_bar.dart b/lib/src/layout/title_bar.dart index 249c6ebb..617e1ee9 100644 --- a/lib/src/layout/title_bar.dart +++ b/lib/src/layout/title_bar.dart @@ -93,32 +93,33 @@ class TitleBar extends StatelessWidget { final isMacOS = defaultTargetPlatform == TargetPlatform.macOS; return MediaQuery( - data: MediaQuery.of(context).copyWith( - padding: EdgeInsets.only( - left: !kIsWeb && isMacOS ? 70 : 0, - ), - ), + data: MediaQuery.of( + context, + ).copyWith(padding: EdgeInsets.only(left: !kIsWeb && isMacOS ? 70 : 0)), child: ClipRect( child: BackdropFilter( - filter: decoration?.color?.opacity == 1 + filter: decoration?.color?.a == 1 ? ImageFilter.blur() : ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0), child: Container( alignment: alignment, padding: padding, - decoration: BoxDecoration( - color: theme.canvasColor, - border: Border( - bottom: BorderSide(color: dividerColor ?? theme.dividerColor), - ), - ).copyWith( - color: decoration?.color, - image: decoration?.image, - border: decoration?.border, - borderRadius: decoration?.borderRadius, - boxShadow: decoration?.boxShadow, - gradient: decoration?.gradient, - ), + decoration: + BoxDecoration( + color: theme.canvasColor, + border: Border( + bottom: BorderSide( + color: dividerColor ?? theme.dividerColor, + ), + ), + ).copyWith( + color: decoration?.color, + image: decoration?.image, + border: decoration?.border, + borderRadius: decoration?.borderRadius, + boxShadow: decoration?.boxShadow, + gradient: decoration?.gradient, + ), child: NavigationToolbar( middle: _title, centerMiddle: centerTitle, diff --git a/lib/src/layout/toolbar/custom_toolbar_item.dart b/lib/src/layout/toolbar/custom_toolbar_item.dart index bae382fe..ab90ef27 100644 --- a/lib/src/layout/toolbar/custom_toolbar_item.dart +++ b/lib/src/layout/toolbar/custom_toolbar_item.dart @@ -1,5 +1,6 @@ import 'package:macos_ui/macos_ui.dart'; import 'package:macos_ui/src/library.dart'; +import 'package:macos_window_utils/widgets/macos_toolbar_passthrough.dart'; /// A custom widget for the toolbar. class CustomToolbarItem extends ToolbarItem { @@ -64,12 +65,9 @@ class CustomToolbarItem extends ToolbarItem { if (displayMode == ToolbarItemDisplayMode.inToolbar) { Widget widget = inToolbarBuilder(context); if (tooltipMessage != null) { - widget = MacosTooltip( - message: tooltipMessage!, - child: widget, - ); + widget = MacosTooltip(message: tooltipMessage!, child: widget); } - return widget; + return MacosToolbarPassthrough(child: widget); } else { return (inOverflowedBuilder != null) ? inOverflowedBuilder!(context) diff --git a/lib/src/layout/toolbar/overflow_handler.dart b/lib/src/layout/toolbar/overflow_handler.dart index dd1a1d5a..dfc1d0f7 100644 --- a/lib/src/layout/toolbar/overflow_handler.dart +++ b/lib/src/layout/toolbar/overflow_handler.dart @@ -7,9 +7,8 @@ import 'package:macos_ui/src/library.dart'; /// Signature of a function that is called to notify that the children /// that have been hidden due to overflow has changed. -typedef OverflowHandlerChangedCallback = void Function( - List hiddenChildren, -); +typedef OverflowHandlerChangedCallback = + void Function(List hiddenChildren); /// {@template overflowHandler} /// Lays out children widgets in a single run, and if there is not @@ -105,27 +104,35 @@ class OverflowHandler extends MultiChildRenderObjectWidget { void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(EnumProperty('alignment', alignment)); - properties.add(EnumProperty( - 'crossAxisAlignment', - crossAxisAlignment, - )); - properties.add(EnumProperty( - 'textDirection', - textDirection, - defaultValue: null, - )); + properties.add( + EnumProperty( + 'crossAxisAlignment', + crossAxisAlignment, + ), + ); + properties.add( + EnumProperty( + 'textDirection', + textDirection, + defaultValue: null, + ), + ); properties.add(DoubleProperty("overflowBreakpoint", overflowBreakpoint)); properties.add(EnumProperty('clipBehavior', clipBehavior)); - properties.add(EnumProperty( - 'overflowWidgetAlignment', - overflowWidgetAlignment, - )); - properties.add(FlagProperty( - 'alwaysDisplayOverflowWidget', - value: alwaysDisplayOverflowWidget, - ifTrue: 'always display overflow widget', - ifFalse: 'do not always display overflow widget', - )); + properties.add( + EnumProperty( + 'overflowWidgetAlignment', + overflowWidgetAlignment, + ), + ); + properties.add( + FlagProperty( + 'alwaysDisplayOverflowWidget', + value: alwaysDisplayOverflowWidget, + ifTrue: 'always display overflow widget', + ifFalse: 'do not always display overflow widget', + ), + ); } } @@ -152,13 +159,13 @@ class RenderOverflowHandler extends RenderBox required MainAxisAlignment overflowWidgetAlignment, required bool alwaysDisplayOverflowWidget, required this.overflowChangedCallback, - }) : _alignment = alignment, - _crossAxisAlignment = crossAxisAlignment, - _textDirection = textDirection, - _clipBehavior = clipBehavior, - _overflowBreakpoint = overflowBreakpoint, - _overflowWidgetAlignment = overflowWidgetAlignment, - _alwaysDisplayOverflowWidget = alwaysDisplayOverflowWidget; + }) : _alignment = alignment, + _crossAxisAlignment = crossAxisAlignment, + _textDirection = textDirection, + _clipBehavior = clipBehavior, + _overflowBreakpoint = overflowBreakpoint, + _overflowWidgetAlignment = overflowWidgetAlignment, + _alwaysDisplayOverflowWidget = alwaysDisplayOverflowWidget; double _overflowBreakpoint; @@ -244,18 +251,24 @@ class RenderOverflowHandler extends RenderBox bool get _debugHasNecessaryDirections { if (firstChild != null && lastChild != firstChild) { // i.e. there's more than one child - assert(textDirection != null, - 'Horizontal $runtimeType with multiple children has a null textDirection, so the layout order is undefined.'); + assert( + textDirection != null, + 'Horizontal $runtimeType with multiple children has a null textDirection, so the layout order is undefined.', + ); } if (alignment == MainAxisAlignment.start || alignment == MainAxisAlignment.end) { - assert(textDirection != null, - 'Horizontal $runtimeType with alignment $alignment has a null textDirection, so the alignment cannot be resolved.'); + assert( + textDirection != null, + 'Horizontal $runtimeType with alignment $alignment has a null textDirection, so the alignment cannot be resolved.', + ); } if (crossAxisAlignment == CrossAxisAlignment.start || crossAxisAlignment == CrossAxisAlignment.end) { - assert(textDirection != null, - 'Vertical $runtimeType with crossAxisAlignment $crossAxisAlignment has a null textDirection, so the alignment cannot be resolved.'); + assert( + textDirection != null, + 'Vertical $runtimeType with crossAxisAlignment $crossAxisAlignment has a null textDirection, so the alignment cannot be resolved.', + ); } return true; } @@ -395,8 +408,10 @@ class RenderOverflowHandler extends RenderBox mainAxisLimit) { // This child is not going to be rendered, but the overflow item is. mainAxisExtent += overflowItemMainAxisExtent; - crossAxisExtent = - math.max(crossAxisExtent, overflowItemCrossAxisExtent); + crossAxisExtent = math.max( + crossAxisExtent, + overflowItemCrossAxisExtent, + ); overflowed = true; break; } @@ -467,8 +482,10 @@ class RenderOverflowHandler extends RenderBox mainAxisLimit) { // This child is not going to be rendered, but the overflow item is. mainAxisExtent += overflowItemMainAxisExtent; - crossAxisExtent = - math.max(crossAxisExtent, overflowItemCrossAxisExtent); + crossAxisExtent = math.max( + crossAxisExtent, + overflowItemCrossAxisExtent, + ); overflowItemVisible = true; overflowed = true; hiddenChildren.add(childIndex); @@ -509,7 +526,8 @@ class RenderOverflowHandler extends RenderBox containerMainAxisExtent = size.width; containerCrossAxisExtent = size.height; - _hasVisualOverflow = containerMainAxisExtent < mainAxisExtent || + _hasVisualOverflow = + containerMainAxisExtent < mainAxisExtent || containerCrossAxisExtent < crossAxisExtent; // Notify callback if the children we've hidden has changed @@ -527,8 +545,10 @@ class RenderOverflowHandler extends RenderBox // Calculate alignment parameters based on the axis extents. double crossAxisOffset = 0; - final double mainAxisFreeSpace = - math.max(0.0, containerMainAxisExtent - mainAxisExtent); + final double mainAxisFreeSpace = math.max( + 0.0, + containerMainAxisExtent - mainAxisExtent, + ); double childLeadingSpace = 0.0; double childBetweenSpace = 0.0; @@ -547,8 +567,9 @@ class RenderOverflowHandler extends RenderBox : 0.0; break; case MainAxisAlignment.spaceAround: - childBetweenSpace = - visibleChildCount > 0 ? mainAxisFreeSpace / visibleChildCount : 0.0; + childBetweenSpace = visibleChildCount > 0 + ? mainAxisFreeSpace / visibleChildCount + : 0.0; childLeadingSpace = childBetweenSpace / 2.0; break; case MainAxisAlignment.spaceEvenly: @@ -592,8 +613,9 @@ class RenderOverflowHandler extends RenderBox // it to be aligned at the "opposite side" as this looks visually // more consistent late double overflowChildMainPosition; - double endAlignedMainAxisPosition = - flipMainAxis ? 0 : containerMainAxisExtent - childMainAxisExtent; + double endAlignedMainAxisPosition = flipMainAxis + ? 0 + : containerMainAxisExtent - childMainAxisExtent; switch (_overflowWidgetAlignment) { case MainAxisAlignment.start: // we're already in the right spot @@ -694,26 +716,34 @@ class RenderOverflowHandler extends RenderBox void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(EnumProperty('alignment', alignment)); - properties.add(EnumProperty( - 'crossAxisAlignment', - crossAxisAlignment, - )); - properties.add(EnumProperty( - 'textDirection', - textDirection, - defaultValue: null, - )); + properties.add( + EnumProperty( + 'crossAxisAlignment', + crossAxisAlignment, + ), + ); + properties.add( + EnumProperty( + 'textDirection', + textDirection, + defaultValue: null, + ), + ); properties.add(EnumProperty('clipBehavior', clipBehavior)); properties.add(DoubleProperty('overflowBreakpoint', overflowBreakpoint)); - properties.add(EnumProperty( - 'overflowWidgetAlignment', - overflowWidgetAlignment, - )); - properties.add(FlagProperty( - 'alwaysDisplayOverflowWidget', - value: alwaysDisplayOverflowWidget, - ifTrue: 'always display overflow widget', - ifFalse: 'do not always display overflow widget', - )); + properties.add( + EnumProperty( + 'overflowWidgetAlignment', + overflowWidgetAlignment, + ), + ); + properties.add( + FlagProperty( + 'alwaysDisplayOverflowWidget', + value: alwaysDisplayOverflowWidget, + ifTrue: 'always display overflow widget', + ifFalse: 'do not always display overflow widget', + ), + ); } } diff --git a/lib/src/layout/toolbar/sliver_toolbar.dart b/lib/src/layout/toolbar/sliver_toolbar.dart index a96d571b..4cbb090f 100644 --- a/lib/src/layout/toolbar/sliver_toolbar.dart +++ b/lib/src/layout/toolbar/sliver_toolbar.dart @@ -170,23 +170,27 @@ class SliverToolBar extends StatefulWidget with Diagnosticable { properties.add(DiagnosticsProperty('alignment', alignment)); properties.add(DiagnosticsProperty('title', title)); properties.add(DoubleProperty('titleWidth', titleWidth)); - properties - .add(DiagnosticsProperty('decoration', decoration)); + properties.add( + DiagnosticsProperty('decoration', decoration), + ); properties.add(DiagnosticsProperty('padding', padding)); properties.add(DiagnosticsProperty('leading', leading)); - properties.add(FlagProperty( - 'automaticallyImplyLeading', - value: automaticallyImplyLeading, - ifTrue: 'automatically imply leading', - )); + properties.add( + FlagProperty( + 'automaticallyImplyLeading', + value: automaticallyImplyLeading, + ifTrue: 'automatically imply leading', + ), + ); properties.add(DiagnosticsProperty>('actions', actions)); properties.add( FlagProperty('centerTitle', value: centerTitle, ifTrue: 'center title'), ); properties.add(DiagnosticsProperty('dividerColor', dividerColor)); properties.add(FlagProperty('pinned', value: pinned, ifTrue: 'pinned')); - properties - .add(FlagProperty('floating', value: floating, ifTrue: 'floating')); + properties.add( + FlagProperty('floating', value: floating, ifTrue: 'floating'), + ); } @override @@ -288,18 +292,23 @@ class _SliverToolBarDelegate extends SliverPersistentHeaderDelegate { double shrinkOffset, bool overlapsContent, ) { - final bool isScrolledUnder = overlapsContent || + final bool isScrolledUnder = + overlapsContent || (pinned || floating && shrinkOffset > maxExtent - minExtent); - final double opacity = - pinned || floating && isScrolledUnder ? toolbarOpacity : 1.0; + final double opacity = pinned || floating && isScrolledUnder + ? toolbarOpacity + : 1.0; BoxDecoration? effectiveDecoration; if (isScrolledUnder) { - effectiveDecoration = decoration?.copyWith( - color: decoration?.color?.withOpacity(opacity), + effectiveDecoration = + decoration?.copyWith( + color: decoration?.color?.withValues(alpha: opacity), ) ?? BoxDecoration( - color: MacosTheme.of(context).canvasColor.withOpacity(opacity), + color: MacosTheme.of( + context, + ).canvasColor.withValues(alpha: opacity), ); } diff --git a/lib/src/layout/toolbar/toolbar.dart b/lib/src/layout/toolbar/toolbar.dart index efd62e3c..4a2df5f3 100644 --- a/lib/src/layout/toolbar/toolbar.dart +++ b/lib/src/layout/toolbar/toolbar.dart @@ -159,21 +159,22 @@ class ToolBar extends StatefulWidget with Diagnosticable { properties.add(DiagnosticsProperty('alignment', alignment)); properties.add(DiagnosticsProperty('title', title)); properties.add(DoubleProperty('titleWidth', titleWidth)); - properties - .add(DiagnosticsProperty('decoration', decoration)); + properties.add( + DiagnosticsProperty('decoration', decoration), + ); properties.add(DiagnosticsProperty('padding', padding)); properties.add(DiagnosticsProperty('leading', leading)); - properties.add(FlagProperty( - 'automaticallyImplyLeading', - value: automaticallyImplyLeading, - ifTrue: 'automatically imply leading', - )); + properties.add( + FlagProperty( + 'automaticallyImplyLeading', + value: automaticallyImplyLeading, + ifTrue: 'automatically imply leading', + ), + ); properties.add(DiagnosticsProperty>('actions', actions)); - properties.add(FlagProperty( - 'centerTitle', - value: centerTitle, - ifTrue: 'center title', - )); + properties.add( + FlagProperty('centerTitle', value: centerTitle, ifTrue: 'center title'), + ); properties.add(DiagnosticsProperty('dividerColor', dividerColor)); } @@ -257,29 +258,28 @@ class _ToolBarState extends State { final isMacOS = defaultTargetPlatform == TargetPlatform.macOS; return MediaQuery( - data: MediaQuery.of(context).copyWith( - padding: EdgeInsets.only( - left: !kIsWeb && isMacOS ? 70 : 0, - ), - ), + data: MediaQuery.of( + context, + ).copyWith(padding: EdgeInsets.only(left: !kIsWeb && isMacOS ? 70 : 0)), child: _WallpaperTintedAreaOrBlurFilter( enableWallpaperTintedArea: kIsWeb ? false : !widget.enableBlur, isWidgetVisible: widget.allowWallpaperTintingOverrides, backgroundColor: theme.canvasColor, - widgetOpacity: widget.decoration?.color?.opacity, + widgetOpacity: widget.decoration?.color?.a, child: Container( alignment: widget.alignment, padding: widget.padding, - decoration: BoxDecoration( - border: Border(bottom: BorderSide(color: dividerColor)), - ).copyWith( - color: widget.decoration?.color, - image: widget.decoration?.image, - border: widget.decoration?.border, - borderRadius: widget.decoration?.borderRadius, - boxShadow: widget.decoration?.boxShadow, - gradient: widget.decoration?.gradient, - ), + decoration: + BoxDecoration( + border: Border(bottom: BorderSide(color: dividerColor)), + ).copyWith( + color: widget.decoration?.color, + image: widget.decoration?.image, + border: widget.decoration?.border, + borderRadius: widget.decoration?.borderRadius, + boxShadow: widget.decoration?.boxShadow, + gradient: widget.decoration?.gradient, + ), child: NavigationToolbar( middle: title, centerMiddle: widget.centerTitle, @@ -289,10 +289,12 @@ class _ToolBarState extends State { isDense: doAllItemsShowLabel, overflowContentBuilder: (context) => ToolbarOverflowMenu( children: overflowedActions - .map((action) => action.build( - context, - ToolbarItemDisplayMode.overflowed, - )) + .map( + (action) => action.build( + context, + ToolbarItemDisplayMode.overflowed, + ), + ) .toList(), ), ), @@ -384,10 +386,7 @@ class _WallpaperTintedAreaOrBlurFilter extends StatelessWidget { child: BackdropFilter( filter: widgetOpacity == 1.0 ? ImageFilter.blur() - : ImageFilter.blur( - sigmaX: 5.0, - sigmaY: 5.0, - ), + : ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0), child: child, ), ), diff --git a/lib/src/layout/toolbar/toolbar_divider.dart b/lib/src/layout/toolbar/toolbar_divider.dart index 346a999c..72a194ed 100644 --- a/lib/src/layout/toolbar/toolbar_divider.dart +++ b/lib/src/layout/toolbar/toolbar_divider.dart @@ -6,10 +6,7 @@ class ToolBarDivider extends ToolbarItem { /// Builds a macOS-styled divider for the toolbar. It generates a vertical /// line (or a horizontal line, if it appears in the overflowed menu) between /// the toolbar actions. - const ToolBarDivider({ - super.key, - this.padding = const EdgeInsets.all(6.0), - }); + const ToolBarDivider({super.key, this.padding = const EdgeInsets.all(6.0)}); /// Optional padding to use for the divider. /// diff --git a/lib/src/layout/toolbar/toolbar_overflow_menu.dart b/lib/src/layout/toolbar/toolbar_overflow_menu.dart index d384df66..6ac846ad 100644 --- a/lib/src/layout/toolbar/toolbar_overflow_menu.dart +++ b/lib/src/layout/toolbar/toolbar_overflow_menu.dart @@ -9,10 +9,7 @@ class ToolbarOverflowMenu extends StatelessWidget { /// as a popup below the [ToolbarOverflowButton]. /// /// Has a similar styling to a pulldown menu. - const ToolbarOverflowMenu({ - super.key, - required this.children, - }); + const ToolbarOverflowMenu({super.key, required this.children}); /// The list of children widgets to lay out vertically inside the menu. final List children; @@ -25,9 +22,9 @@ class ToolbarOverflowMenu extends StatelessWidget { explicitChildNodes: true, child: IntrinsicWidth( child: MacosOverlayFilter( - color: MacosPulldownButtonTheme.of(context) - .pulldownColor - ?.withOpacity(0.25), + color: MacosPulldownButtonTheme.of( + context, + ).pulldownColor?.withValues(alpha: 0.25), borderRadius: _kBorderRadius, child: Padding( padding: const EdgeInsets.all(6.0), diff --git a/lib/src/layout/toolbar/toolbar_overflow_menu_item.dart b/lib/src/layout/toolbar/toolbar_overflow_menu_item.dart index 952420f9..ba705c00 100644 --- a/lib/src/layout/toolbar/toolbar_overflow_menu_item.dart +++ b/lib/src/layout/toolbar/toolbar_overflow_menu_item.dart @@ -62,10 +62,9 @@ class _ToolbarOverflowMenuItemState extends State { Color get _textColor => _isHighlighted ? MacosColors.white - : MacosTheme.brightnessOf(context).resolve( - MacosColors.black, - MacosColors.white, - ); + : MacosTheme.brightnessOf( + context, + ).resolve(MacosColors.black, MacosColors.white); @override Widget build(BuildContext context) { @@ -105,10 +104,7 @@ class _ToolbarOverflowMenuItemState extends State { borderRadius: const BorderRadius.all(Radius.circular(5.0)), ), child: DefaultTextStyle( - style: TextStyle( - fontSize: 13.0, - color: _textColor, - ), + style: TextStyle(fontSize: 13.0, color: _textColor), child: (hasSubMenu) ? Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, diff --git a/lib/src/layout/toolbar/toolbar_popup.dart b/lib/src/layout/toolbar/toolbar_popup.dart index 87f1158b..096c5f60 100644 --- a/lib/src/layout/toolbar/toolbar_popup.dart +++ b/lib/src/layout/toolbar/toolbar_popup.dart @@ -334,22 +334,24 @@ class _ToolbarPopupRoute extends PopupRoute { @override Widget buildPage(context, animation, secondaryAnimation) { - return LayoutBuilder(builder: (context, constraints) { - return _ToolbarPopupRoutePage( - target: target, - placementOffset: placementOffset, - placement: placement, - route: this, - constraints: constraints, - content: content, - buttonRect: buttonRect, - elevation: elevation, - capturedThemes: capturedThemes, - verticalOffset: verticalOffset, - horizontalOffset: horizontalOffset, - position: position, - ); - }); + return LayoutBuilder( + builder: (context, constraints) { + return _ToolbarPopupRoutePage( + target: target, + placementOffset: placementOffset, + placement: placement, + route: this, + constraints: constraints, + content: content, + buttonRect: buttonRect, + elevation: elevation, + capturedThemes: capturedThemes, + verticalOffset: verticalOffset, + horizontalOffset: horizontalOffset, + position: position, + ); + }, + ); } void _dismiss() { @@ -432,10 +434,8 @@ class _ToolbarPopupRoutePage extends StatelessWidget { class _ToolbarPopupContentManager extends StatefulWidget { // ignore: use_super_parameters - const _ToolbarPopupContentManager({ - Key? key, - required this.content, - }) : super(key: key); + const _ToolbarPopupContentManager({Key? key, required this.content}) + : super(key: key); final WidgetBuilder content; @@ -501,8 +501,9 @@ Offset horizontalPositionDependentBox({ final bool fitsLeft = target.dx + verticalOffset + childSize.width <= size.width - margin; final bool fitsRight = target.dx - verticalOffset - childSize.width >= margin; - final bool tooltipLeft = - preferLeft ? fitsLeft || !fitsRight : !(fitsRight || !fitsLeft); + final bool tooltipLeft = preferLeft + ? fitsLeft || !fitsRight + : !(fitsRight || !fitsLeft); double x; if (tooltipLeft) { x = math.min(target.dx + verticalOffset, size.width - margin); @@ -514,8 +515,10 @@ Offset horizontalPositionDependentBox({ if (size.height - margin * 2.0 < childSize.height) { y = (size.height - childSize.height) / 2.0; } else { - final double normalizedTargetY = - target.dy.clamp(margin, size.height - margin); + final double normalizedTargetY = target.dy.clamp( + margin, + size.height - margin, + ); final double edge = margin + childSize.height / 2.0; if (normalizedTargetY < edge) { y = margin; diff --git a/lib/src/layout/toolbar/toolbar_spacer.dart b/lib/src/layout/toolbar/toolbar_spacer.dart index 6b455066..633fb1f4 100644 --- a/lib/src/layout/toolbar/toolbar_spacer.dart +++ b/lib/src/layout/toolbar/toolbar_spacer.dart @@ -7,10 +7,7 @@ const _kToolbarItemWidth = 32.0; class ToolBarSpacer extends ToolbarItem { /// Builds a spacer utility widget for the toolbar. It generates blank space /// between the toolbar actions. - const ToolBarSpacer({ - super.key, - this.spacerUnits = 1.0, - }); + const ToolBarSpacer({super.key, this.spacerUnits = 1.0}); /// How much space to generate, expressed in multiples of [_kToolbarItemWidth] /// @@ -20,9 +17,7 @@ class ToolBarSpacer extends ToolbarItem { @override Widget build(BuildContext context, ToolbarItemDisplayMode displayMode) { if (displayMode == ToolbarItemDisplayMode.inToolbar) { - return SizedBox( - width: spacerUnits * _kToolbarItemWidth, - ); + return SizedBox(width: spacerUnits * _kToolbarItemWidth); } else { return const SizedBox.shrink(); } diff --git a/lib/src/layout/wallpaper_tinted_area.dart b/lib/src/layout/wallpaper_tinted_area.dart index 607ae808..84e6a617 100644 --- a/lib/src/layout/wallpaper_tinted_area.dart +++ b/lib/src/layout/wallpaper_tinted_area.dart @@ -82,11 +82,10 @@ class _WallpaperTintedAreaLayoutBuilder extends StatelessWidget { @override Widget build(BuildContext context) { if (GlobalWallpaperTintingSettings - .data.isWallpaperTintingDisabledByWindow) { + .data + .isWallpaperTintingDisabledByWindow) { return Container( - decoration: BoxDecoration( - color: backgroundColor, - ), + decoration: BoxDecoration(color: backgroundColor), child: child, ); } @@ -142,15 +141,13 @@ class _WallpaperTintedAreaTweenAnimationBuilder extends StatelessWidget { builder: (context, value, child) { return Container( decoration: BoxDecoration( - color: backgroundColor.withOpacity(value), + color: backgroundColor.withValues(alpha: value), backgroundBlendMode: BlendMode.src, ), child: child, ); }, - child: RepaintBoundary( - child: child, - ), + child: RepaintBoundary(child: child), ); } } diff --git a/lib/src/layout/window.dart b/lib/src/layout/window.dart index d28511c0..5e0f447c 100644 --- a/lib/src/layout/window.dart +++ b/lib/src/layout/window.dart @@ -92,7 +92,7 @@ class _MacosWindowState extends State { double _endSidebarWidth = 0.0; double _endSidebarDragStartWidth = 0.0; double _endSidebarDragStartPosition = 0.0; - bool _showSidebar = true; + late bool _showSidebar = widget.sidebar?.shownByDefault ?? true; late bool _showEndSidebar = widget.endSidebar?.shownByDefault ?? false; int _sidebarSlideDuration = 0; SystemMouseCursor _sidebarCursor = SystemMouseCursors.resizeColumn; @@ -101,11 +101,12 @@ class _MacosWindowState extends State { @override void initState() { super.initState(); - _sidebarWidth = (widget.sidebar?.startWidth ?? widget.sidebar?.minWidth) ?? + _sidebarWidth = + (widget.sidebar?.startWidth ?? widget.sidebar?.minWidth) ?? _sidebarWidth; _endSidebarWidth = (widget.endSidebar?.startWidth ?? widget.endSidebar?.minWidth) ?? - _endSidebarWidth; + _endSidebarWidth; widget.disableWallpaperTinting ? GlobalWallpaperTintingSettings.disableWallpaperTinting() @@ -181,12 +182,16 @@ class _MacosWindowState extends State { final sidebar = widget.sidebar; final endSidebar = widget.endSidebar; if (sidebar?.startWidth != null) { - assert((sidebar!.startWidth! >= sidebar.minWidth) && - (sidebar.startWidth! <= sidebar.maxWidth!)); + assert( + (sidebar!.startWidth! >= sidebar.minWidth) && + (sidebar.startWidth! <= sidebar.maxWidth!), + ); } if (endSidebar?.startWidth != null) { - assert((endSidebar!.startWidth! >= endSidebar.minWidth) && - (endSidebar.startWidth! <= endSidebar.maxWidth!)); + assert( + (endSidebar!.startWidth! >= endSidebar.minWidth) && + (endSidebar.startWidth! <= endSidebar.maxWidth!), + ); } final MacosThemeData theme = MacosTheme.of(context); late Color backgroundColor = widget.backgroundColor ?? theme.canvasColor; @@ -231,8 +236,9 @@ class _MacosWindowState extends State { final canShowEndSidebar = _showEndSidebar && !isAtEndBreakpoint && endSidebar != null; final visibleSidebarWidth = canShowSidebar ? _sidebarWidth : 0.0; - final visibleEndSidebarWidth = - canShowEndSidebar ? _endSidebarWidth : 0.0; + final visibleEndSidebarWidth = canShowEndSidebar + ? _endSidebarWidth + : 0.0; final sidebarState = widget.sidebarState; final layout = Stack( @@ -284,9 +290,10 @@ class _MacosWindowState extends State { if (_sidebarScrollController.hasClients && _sidebarScrollController.offset > 0.0) Divider( - thickness: 1, - height: 1, - color: dividerColor), + thickness: 1, + height: 1, + color: dividerColor, + ), if (sidebar.top != null && constraints.maxHeight > 81) Padding( @@ -339,9 +346,10 @@ class _MacosWindowState extends State { if (_sidebarScrollController.hasClients && _sidebarScrollController.offset > 0.0) Divider( - thickness: 1, - height: 1, - color: dividerColor), + thickness: 1, + height: 1, + color: dividerColor, + ), if (sidebar.top != null && constraints.maxHeight > 81) Padding( @@ -418,7 +426,8 @@ class _MacosWindowState extends State { }, onHorizontalDragUpdate: (details) { setState(() { - var newWidth = _sidebarDragStartWidth + + var newWidth = + _sidebarDragStartWidth + details.globalPosition.dx - _sidebarDragStartPosition; @@ -437,10 +446,7 @@ class _MacosWindowState extends State { _sidebarWidth = math.max( sidebar.minWidth, - math.min( - sidebar.maxWidth!, - newWidth, - ), + math.min(sidebar.maxWidth!, newWidth), ); if (_sidebarWidth == sidebar.minWidth) { @@ -494,15 +500,12 @@ class _MacosWindowState extends State { SizedBox(height: endSidebar.topOffset), if (_endSidebarScrollController.hasClients && _endSidebarScrollController.offset > 0.0) - Divider( - thickness: 1, - height: 1, - color: dividerColor, - ), + Divider(thickness: 1, height: 1, color: dividerColor), if (endSidebar.top != null) Padding( - padding: - const EdgeInsets.symmetric(horizontal: 8.0), + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + ), child: endSidebar.top!, ), Expanded( @@ -544,7 +547,8 @@ class _MacosWindowState extends State { }, onHorizontalDragUpdate: (details) { setState(() { - var newWidth = _endSidebarDragStartWidth - + var newWidth = + _endSidebarDragStartWidth - details.globalPosition.dx + _endSidebarDragStartPosition; @@ -563,10 +567,7 @@ class _MacosWindowState extends State { _endSidebarWidth = math.max( endSidebar.minWidth, - math.min( - endSidebar.maxWidth!, - newWidth, - ), + math.min(endSidebar.maxWidth!, newWidth), ); if (_endSidebarWidth == endSidebar.minWidth) { @@ -646,8 +647,8 @@ class MacosWindowScope extends InheritedWidget { required this.isEndSidebarShown, required VoidCallback sidebarToggler, required VoidCallback endSidebarToggler, - }) : _sidebarToggler = sidebarToggler, - _endSidebarToggler = endSidebarToggler; + }) : _sidebarToggler = sidebarToggler, + _endSidebarToggler = endSidebarToggler; /// Provides the constraints from the [MacosWindow] to its descendants. final BoxConstraints constraints; @@ -666,8 +667,8 @@ class MacosWindowScope extends InheritedWidget { /// /// The [context] argument must not be null. static MacosWindowScope of(BuildContext context) { - final MacosWindowScope? result = - context.dependOnInheritedWidgetOfExactType(); + final MacosWindowScope? result = context + .dependOnInheritedWidgetOfExactType(); assert(result != null, 'No MacosWindowScope found in context'); return result!; } diff --git a/lib/src/macos_app.dart b/lib/src/macos_app.dart index 1589821e..4cfb1e0f 100644 --- a/lib/src/macos_app.dart +++ b/lib/src/macos_app.dart @@ -71,11 +71,11 @@ class MacosApp extends StatefulWidget { this.themeMode, this.theme, this.darkTheme, - }) : routeInformationProvider = null, - routeInformationParser = null, - routerDelegate = null, - backButtonDispatcher = null, - routerConfig = null; + }) : routeInformationProvider = null, + routeInformationParser = null, + routerDelegate = null, + backButtonDispatcher = null, + routerConfig = null; /// Creates a [MacosApp] that uses the [Router] instead of a [Navigator]. MacosApp.router({ @@ -106,16 +106,16 @@ class MacosApp extends StatefulWidget { this.themeMode, this.theme, this.darkTheme, - }) : assert(routerDelegate != null || routerConfig != null), - assert(supportedLocales.isNotEmpty), - navigatorObservers = null, - navigatorKey = null, - onGenerateRoute = null, - home = null, - onGenerateInitialRoutes = null, - onUnknownRoute = null, - routes = null, - initialRoute = null; + }) : assert(routerDelegate != null || routerConfig != null), + assert(supportedLocales.isNotEmpty), + navigatorObservers = null, + navigatorKey = null, + onGenerateRoute = null, + home = null, + onGenerateInitialRoutes = null, + onUnknownRoute = null, + routes = null, + initialRoute = null; /// {@macro flutter.widgets.widgetsApp.navigatorKey} final GlobalKey? navigatorKey; @@ -311,64 +311,66 @@ class _MacosAppState extends State { Widget _macosBuilder(BuildContext context, Widget? child) { 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(), - ), - ); - }); - }); + 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) { @@ -478,10 +480,7 @@ class MacosScrollBehavior extends ScrollBehavior { case TargetPlatform.linux: case TargetPlatform.macOS: case TargetPlatform.windows: - return MacosScrollbar( - controller: details.controller, - child: child, - ); + return MacosScrollbar(controller: details.controller, child: child); case TargetPlatform.android: case TargetPlatform.fuchsia: case TargetPlatform.iOS: diff --git a/lib/src/macos_window_utils_config.dart b/lib/src/macos_window_utils_config.dart index 32e52568..bcf2867e 100644 --- a/lib/src/macos_window_utils_config.dart +++ b/lib/src/macos_window_utils_config.dart @@ -83,9 +83,7 @@ class MacosWindowUtilsConfig { } await WindowManipulator.addToolbar(); - await WindowManipulator.setToolbarStyle( - toolbarStyle: toolbarStyle, - ); + await WindowManipulator.setToolbarStyle(toolbarStyle: toolbarStyle); if (removeMenubarInFullScreenMode) { final delegate = _FlutterWindowDelegate(); diff --git a/lib/src/selectors/caret_painters.dart b/lib/src/selectors/caret_painters.dart index b3259e13..db8de8c6 100644 --- a/lib/src/selectors/caret_painters.dart +++ b/lib/src/selectors/caret_painters.dart @@ -7,10 +7,7 @@ const _buttonRadius = 5.0; /// {@endtemplate} class DownCaretPainter extends CustomPainter { /// {@macro downCaretPainter} - const DownCaretPainter({ - required this.color, - required this.backgroundColor, - }); + const DownCaretPainter({required this.color, required this.backgroundColor}); /// The color of the caret. final Color color; @@ -56,10 +53,7 @@ class DownCaretPainter extends CustomPainter { /// {@endtemplate} class UpCaretPainter extends CustomPainter { /// {@macro upCaretPainter} - const UpCaretPainter({ - required this.color, - required this.backgroundColor, - }); + const UpCaretPainter({required this.color, required this.backgroundColor}); /// The color of the caret. final Color color; diff --git a/lib/src/selectors/color_well.dart b/lib/src/selectors/color_well.dart index 9f1c5685..8ad5169f 100644 --- a/lib/src/selectors/color_well.dart +++ b/lib/src/selectors/color_well.dart @@ -80,9 +80,9 @@ class _MacosColorWellState extends State { Stream? _onColorChanged; Stream get onColorChanged { - _onColorChanged ??= _eventChannel - .receiveBroadcastStream() - .map((event) => Color(int.parse(event))); + _onColorChanged ??= _eventChannel.receiveBroadcastStream().map( + (event) => Color(int.parse(event)), + ); return _onColorChanged!; } @@ -106,7 +106,7 @@ class _MacosColorWellState extends State { Widget build(BuildContext context) { final theme = MacosTheme.of(context); final outerColor = theme.brightness.isDark - ? MacosColors.systemGrayColor.withOpacity(0.5) + ? MacosColors.systemGrayColor.withValues(alpha: 0.5) : MacosColors.white; return GestureDetector( onTap: () async { diff --git a/lib/src/selectors/date_picker.dart b/lib/src/selectors/date_picker.dart index 25515a7d..76c4126f 100644 --- a/lib/src/selectors/date_picker.dart +++ b/lib/src/selectors/date_picker.dart @@ -215,12 +215,7 @@ class _MacosDatePickerState extends State { final weekday = widget.weekdayAbbreviations[i]; result.add( ExcludeSemantics( - child: Center( - child: Text( - weekday, - style: headerStyle, - ), - ), + child: Center(child: Text(weekday, style: headerStyle)), ), ); } @@ -295,9 +290,7 @@ class _MacosDatePickerState extends State { ), ); } - dateFields.add( - Text(separator), - ); + dateFields.add(Text(separator)); } dateFields.removeLast(); @@ -410,8 +403,11 @@ class _MacosDatePickerState extends State { child: Column( children: [ Padding( - padding: - const EdgeInsets.only(left: 2.0, top: 2.0, bottom: 4.0), + padding: const EdgeInsets.only( + left: 2.0, + top: 2.0, + bottom: 4.0, + ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -437,9 +433,7 @@ class _MacosDatePickerState extends State { backgroundColor: MacosColors.transparent, borderRadius: BorderRadius.zero, padding: EdgeInsets.zero, - boxConstraints: const BoxConstraints( - maxWidth: 12.0, - ), + boxConstraints: const BoxConstraints(maxWidth: 12.0), onPressed: () { if (_selectedMonth - 1 < 1) { setState(() { @@ -466,9 +460,7 @@ class _MacosDatePickerState extends State { backgroundColor: MacosColors.transparent, borderRadius: BorderRadius.zero, padding: EdgeInsets.zero, - boxConstraints: const BoxConstraints( - maxWidth: 12.0, - ), + boxConstraints: const BoxConstraints(maxWidth: 12.0), onPressed: () { setState(() => _parseInitialDate()); widget.onDateChanged.call(_formatAsDateTime()); @@ -484,9 +476,7 @@ class _MacosDatePickerState extends State { backgroundColor: MacosColors.transparent, borderRadius: BorderRadius.zero, padding: EdgeInsets.zero, - boxConstraints: const BoxConstraints( - maxWidth: 12.0, - ), + boxConstraints: const BoxConstraints(maxWidth: 12.0), onPressed: () { if (_selectedMonth + 1 > 12) { setState(() { @@ -555,14 +545,17 @@ class _MacosDatePickerState extends State { ); final localizations = MaterialLocalizations.of(context); final daysInMonth = DateUtils.getDaysInMonth(_selectedYear, _selectedMonth); - final dayOffset = - DateUtils.firstDayOffset(_selectedYear, _selectedMonth, localizations); + final dayOffset = DateUtils.firstDayOffset( + _selectedYear, + _selectedMonth, + localizations, + ); final dayHeaders = _dayHeaders( MacosTheme.of(context).typography.caption1.copyWith( - color: datePickerTheme.monthViewWeekdayHeaderColor, - fontWeight: FontWeight.w700, - letterSpacing: 0.12, - ), + color: datePickerTheme.monthViewWeekdayHeaderColor, + fontWeight: FontWeight.w700, + letterSpacing: 0.12, + ), localizations, ); @@ -616,10 +609,7 @@ class _MacosDatePickerState extends State { ), ); } else if (isSelectedDay) { - dayText = Text( - localizations.formatDecimal(day), - style: dayStyle, - ); + dayText = Text(localizations.formatDecimal(day), style: dayStyle); decoration = BoxDecoration( color: datePickerTheme.monthViewSelectedDateColor, borderRadius: const BorderRadius.all(Radius.circular(3.0)), @@ -642,20 +632,16 @@ class _MacosDatePickerState extends State { alignment: Alignment.centerRight, child: Padding( padding: const EdgeInsets.only(right: 2.0), - child: dayText ?? - Text( - localizations.formatDecimal(day), - style: dayStyle, - ), + child: + dayText ?? + Text(localizations.formatDecimal(day), style: dayStyle), ), ), ), ); if (isDisabled) { - dayWidget = ExcludeSemantics( - child: dayWidget, - ); + dayWidget = ExcludeSemantics(child: dayWidget); } dayItems.add(dayWidget); diff --git a/lib/src/selectors/graphical_time_picker_painter.dart b/lib/src/selectors/graphical_time_picker_painter.dart index 7a08769c..6fe52e60 100644 --- a/lib/src/selectors/graphical_time_picker_painter.dart +++ b/lib/src/selectors/graphical_time_picker_painter.dart @@ -81,17 +81,14 @@ class GraphicalTimePickerPainter extends CustomPainter { //---Inner shadow---// const blurRadius = 3.0; final shadowPainter = Paint() - ..maskFilter = const MaskFilter.blur( - BlurStyle.normal, - blurRadius, - ) + ..maskFilter = const MaskFilter.blur(BlurStyle.normal, blurRadius) ..color = MacosColors.black; final path = Path() ..fillType = PathFillType.evenOdd ..addRect( - const EdgeInsets.all(blurRadius) - .copyWith(bottom: -rect2.height / 2) - .inflateRect(rect2), + const EdgeInsets.all( + blurRadius, + ).copyWith(bottom: -rect2.height / 2).inflateRect(rect2), ) ..addArc( const EdgeInsets.symmetric(horizontal: blurRadius).inflateRect(rect2), @@ -108,10 +105,7 @@ class GraphicalTimePickerPainter extends CustomPainter { color: theme.dayPeriodTextColor, fontSize: 13.0, ); - TextSpan span = TextSpan( - style: style, - text: dayPeriod, - ); + TextSpan span = TextSpan(style: style, text: dayPeriod); TextPainter periodPainter = TextPainter( text: span, textAlign: TextAlign.center, @@ -126,11 +120,7 @@ class GraphicalTimePickerPainter extends CustomPainter { ); } - void _paintHours( - Canvas canvas, - Size size, - double scaleFactor, - ) { + void _paintHours(Canvas canvas, Size size, double scaleFactor) { TextStyle style = const TextStyle( color: MacosColors.black, fontWeight: FontWeight.w300, @@ -217,11 +207,7 @@ class GraphicalTimePickerPainter extends CustomPainter { ..style = PaintingStyle.fill; // Draw second hand pin hole - canvas.drawCircle( - size.center(Offset.zero), - 2.0, - secondHandPinPaint, - ); + canvas.drawCircle(size.center(Offset.zero), 2.0, secondHandPinPaint); // Draw second hand tail canvas.drawLine( diff --git a/lib/src/selectors/time_picker.dart b/lib/src/selectors/time_picker.dart index 47b4bb15..2316d6ad 100644 --- a/lib/src/selectors/time_picker.dart +++ b/lib/src/selectors/time_picker.dart @@ -214,10 +214,7 @@ class _MacosTimePickerState extends State { TimePickerFieldElement( isSelected: _isHourSelected, element: localizations.formatHour( - TimeOfDay( - hour: _selectedHour, - minute: _selectedMinute, - ), + TimeOfDay(hour: _selectedHour, minute: _selectedMinute), ), onSelected: () { setState(() { @@ -232,10 +229,7 @@ class _MacosTimePickerState extends State { TimePickerFieldElement( isSelected: _isMinuteSelected, element: localizations.formatMinute( - TimeOfDay( - hour: _selectedHour, - minute: _selectedMinute, - ), + TimeOfDay(hour: _selectedHour, minute: _selectedMinute), ), onSelected: () { setState(() { @@ -271,7 +265,8 @@ class _MacosTimePickerState extends State { height: 10.0, width: 12.0, child: IgnorePointer( - ignoring: !_isHourSelected && + ignoring: + !_isHourSelected && !_isMinuteSelected && !_isPeriodSelected, child: GestureDetector( @@ -303,7 +298,8 @@ class _MacosTimePickerState extends State { height: 10.0, width: 12.0, child: IgnorePointer( - ignoring: !_isHourSelected && + ignoring: + !_isHourSelected && !_isMinuteSelected && !_isPeriodSelected, child: GestureDetector( diff --git a/lib/src/sheets/macos_sheet.dart b/lib/src/sheets/macos_sheet.dart index 0c152bf9..51662e59 100644 --- a/lib/src/sheets/macos_sheet.dart +++ b/lib/src/sheets/macos_sheet.dart @@ -3,8 +3,10 @@ import 'package:macos_ui/macos_ui.dart'; import 'package:macos_ui/src/library.dart'; const _kSheetBorderRadius = BorderRadius.all(Radius.circular(12.0)); -const EdgeInsets _defaultInsetPadding = - EdgeInsets.symmetric(horizontal: 140.0, vertical: 48.0); +const EdgeInsets _defaultInsetPadding = EdgeInsets.symmetric( + horizontal: 140.0, + vertical: 48.0, +); /// {@template macosSheet} /// A modal dialog thatโ€™s attached to a particular window and prevents further @@ -54,13 +56,13 @@ class MacosSheet extends StatelessWidget { final brightness = MacosTheme.brightnessOf(context); final outerBorderColor = brightness.resolve( - Colors.black.withOpacity(0.23), - Colors.black.withOpacity(0.76), + Colors.black.withValues(alpha: 0.23), + Colors.black.withValues(alpha: 0.76), ); final innerBorderColor = brightness.resolve( - Colors.white.withOpacity(0.45), - Colors.white.withOpacity(0.15), + Colors.white.withValues(alpha: 0.45), + Colors.white.withValues(alpha: 0.15), ); final EdgeInsets effectivePadding = @@ -72,7 +74,8 @@ class MacosSheet extends StatelessWidget { curve: insetAnimationCurve, child: DecoratedBox( decoration: BoxDecoration( - color: backgroundColor ?? + color: + backgroundColor ?? brightness.resolve( CupertinoColors.systemGrey6.color, MacosColors.controlBackgroundColor.darkColor, @@ -81,17 +84,11 @@ class MacosSheet extends StatelessWidget { ), child: Container( decoration: BoxDecoration( - border: Border.all( - width: 2, - color: innerBorderColor, - ), + border: Border.all(width: 2, color: innerBorderColor), borderRadius: _kSheetBorderRadius, ), foregroundDecoration: BoxDecoration( - border: Border.all( - width: 1, - color: outerBorderColor, - ), + border: Border.all(width: 1, color: outerBorderColor), borderRadius: _kSheetBorderRadius, ), child: child, @@ -114,7 +111,14 @@ Future showMacosSheet({ barrierColor ??= MacosDynamicColor.resolve( MacosColors.controlBackgroundColor, context, - ).withOpacity(0.6); + ); + + barrierColor = Color.fromRGBO( + (barrierColor.r * 255).floor(), + (barrierColor.g * 255).floor(), + (barrierColor.b * 255).floor(), + 0.6, + ); return Navigator.of(context, rootNavigator: useRootNavigator).push( _MacosSheetRoute( @@ -124,7 +128,8 @@ Future showMacosSheet({ }, barrierDismissible: barrierDismissible, barrierColor: barrierColor, - barrierLabel: barrierLabel ?? + barrierLabel: + barrierLabel ?? MaterialLocalizations.of(context).modalBarrierDismissLabel, ), ); @@ -137,10 +142,10 @@ class _MacosSheetRoute extends PopupRoute { Color? barrierColor = const Color(0x80000000), String? barrierLabel, super.settings, - }) : _pageBuilder = pageBuilder, - _barrierDismissible = barrierDismissible, - _barrierLabel = barrierLabel, - _barrierColor = barrierColor; + }) : _pageBuilder = pageBuilder, + _barrierDismissible = barrierDismissible, + _barrierLabel = barrierLabel, + _barrierColor = barrierColor; final RoutePageBuilder _pageBuilder; @@ -187,10 +192,7 @@ class _MacosSheetRoute extends PopupRoute { ) { if (animation.status == AnimationStatus.reverse) { return FadeTransition( - opacity: CurvedAnimation( - parent: animation, - curve: Curves.easeOutSine, - ), + opacity: CurvedAnimation(parent: animation, curve: Curves.easeOutSine), child: child, ); } @@ -216,11 +218,7 @@ class _SubtleBounceCurve extends Curve { @override double transform(double t) { final simulation = SpringSimulation( - const SpringDescription( - damping: 14, - mass: 1.4, - stiffness: 180, - ), + const SpringDescription(damping: 14, mass: 1.4, stiffness: 180), 0.0, 1.0, 0.1, diff --git a/lib/src/theme/date_picker_theme.dart b/lib/src/theme/date_picker_theme.dart index e83f2917..6d41f2b3 100644 --- a/lib/src/theme/date_picker_theme.dart +++ b/lib/src/theme/date_picker_theme.dart @@ -31,8 +31,8 @@ class MacosDatePickerTheme extends InheritedTheme { /// final theme = MacosDatePickerTheme.of(context); /// ``` static MacosDatePickerThemeData of(BuildContext context) { - final MacosDatePickerTheme? datePickerTheme = - context.dependOnInheritedWidgetOfExactType(); + final MacosDatePickerTheme? datePickerTheme = context + .dependOnInheritedWidgetOfExactType(); return datePickerTheme?.data ?? MacosTheme.of(context).datePickerTheme; } @@ -178,10 +178,16 @@ class MacosDatePickerThemeData with Diagnosticable { ) { return MacosDatePickerThemeData( backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t), - selectedElementColor: - Color.lerp(a.selectedElementColor, b.selectedElementColor, t), - selectedElementTextColor: - Color.lerp(a.selectedElementTextColor, b.selectedElementTextColor, t), + selectedElementColor: Color.lerp( + a.selectedElementColor, + b.selectedElementColor, + t, + ), + selectedElementTextColor: Color.lerp( + a.selectedElementTextColor, + b.selectedElementTextColor, + t, + ), caretColor: Color.lerp(a.caretColor, b.caretColor, t), caretControlsBackgroundColor: Color.lerp( a.caretControlsBackgroundColor, @@ -193,10 +199,16 @@ class MacosDatePickerThemeData with Diagnosticable { b.caretControlsSeparatorColor, t, ), - monthViewControlsColor: - Color.lerp(a.monthViewControlsColor, b.monthViewControlsColor, t), - monthViewHeaderColor: - Color.lerp(a.monthViewHeaderColor, b.monthViewHeaderColor, t), + monthViewControlsColor: Color.lerp( + a.monthViewControlsColor, + b.monthViewControlsColor, + t, + ), + monthViewHeaderColor: Color.lerp( + a.monthViewHeaderColor, + b.monthViewHeaderColor, + t, + ), monthViewSelectedDateColor: Color.lerp( a.monthViewSelectedDateColor, b.monthViewSelectedDateColor, @@ -222,8 +234,11 @@ class MacosDatePickerThemeData with Diagnosticable { b.monthViewHeaderDividerColor, t, ), - monthViewDateColor: - Color.lerp(a.monthViewDateColor, b.monthViewDateColor, t), + monthViewDateColor: Color.lerp( + a.monthViewDateColor, + b.monthViewDateColor, + t, + ), shadowColor: Color.lerp(a.shadowColor, b.shadowColor, t), ); } @@ -299,37 +314,37 @@ class MacosDatePickerThemeData with Diagnosticable { ColorProperty('selectedElementTextColor', selectedElementTextColor), ); properties.add(ColorProperty('caretColor', caretColor)); - properties.add(ColorProperty( - 'caretControlsBackgroundColor', - caretControlsBackgroundColor, - )); - properties.add(ColorProperty( - 'caretControlsSeparatorColor', - caretControlsSeparatorColor, - )); - properties - .add(ColorProperty('monthViewControlsColor', monthViewControlsColor)); + properties.add( + ColorProperty( + 'caretControlsBackgroundColor', + caretControlsBackgroundColor, + ), + ); + properties.add( + ColorProperty('caretControlsSeparatorColor', caretControlsSeparatorColor), + ); + properties.add( + ColorProperty('monthViewControlsColor', monthViewControlsColor), + ); properties.add(ColorProperty('monthViewHeaderColor', monthViewHeaderColor)); - properties.add(ColorProperty( - 'monthViewSelectedDateColor', - monthViewSelectedDateColor, - )); - properties.add(ColorProperty( - 'monthViewSelectedDateTextColor', - monthViewSelectedDateTextColor, - )); - properties.add(ColorProperty( - 'monthViewCurrentDateColor', - monthViewCurrentDateColor, - )); - properties.add(ColorProperty( - 'monthViewWeekdayHeaderColor', - monthViewWeekdayHeaderColor, - )); - properties.add(ColorProperty( - 'monthViewHeaderDividerColor', - monthViewHeaderDividerColor, - )); + properties.add( + ColorProperty('monthViewSelectedDateColor', monthViewSelectedDateColor), + ); + properties.add( + ColorProperty( + 'monthViewSelectedDateTextColor', + monthViewSelectedDateTextColor, + ), + ); + properties.add( + ColorProperty('monthViewCurrentDateColor', monthViewCurrentDateColor), + ); + properties.add( + ColorProperty('monthViewWeekdayHeaderColor', monthViewWeekdayHeaderColor), + ); + properties.add( + ColorProperty('monthViewHeaderDividerColor', monthViewHeaderDividerColor), + ); properties.add(ColorProperty('monthViewDateColor', monthViewDateColor)); properties.add(ColorProperty('shadowColor', shadowColor)); } diff --git a/lib/src/theme/help_button_theme.dart b/lib/src/theme/help_button_theme.dart index 6c3cfae6..acf94961 100644 --- a/lib/src/theme/help_button_theme.dart +++ b/lib/src/theme/help_button_theme.dart @@ -11,11 +11,7 @@ class HelpButtonTheme extends InheritedTheme { /// Create a [HelpButtonTheme]. /// /// The [data] parameter must not be null. - const HelpButtonTheme({ - super.key, - required this.data, - required super.child, - }); + const HelpButtonTheme({super.key, required this.data, required super.child}); /// The configuration of this theme. final HelpButtonThemeData data; @@ -31,8 +27,8 @@ class HelpButtonTheme extends InheritedTheme { /// HelpButtonTheme theme = HelpButtonTheme.of(context); /// ``` static HelpButtonThemeData of(BuildContext context) { - final HelpButtonTheme? buttonTheme = - context.dependOnInheritedWidgetOfExactType(); + final HelpButtonTheme? buttonTheme = context + .dependOnInheritedWidgetOfExactType(); return buttonTheme?.data ?? MacosTheme.of(context).helpButtonTheme; } @@ -58,10 +54,7 @@ class HelpButtonThemeData with Diagnosticable { /// Creates a [HelpButtonThemeData]. /// /// The [style] may be null. - const HelpButtonThemeData({ - this.color, - this.disabledColor, - }); + const HelpButtonThemeData({this.color, this.disabledColor}); /// The default background color for [HelpButton] final Color? color; @@ -70,10 +63,7 @@ class HelpButtonThemeData with Diagnosticable { final Color? disabledColor; /// Copies one [HelpButtonThemeData] to another. - HelpButtonThemeData copyWith({ - Color? color, - Color? disabledColor, - }) { + HelpButtonThemeData copyWith({Color? color, Color? disabledColor}) { return HelpButtonThemeData( color: color ?? this.color, disabledColor: disabledColor ?? this.disabledColor, @@ -99,8 +89,8 @@ class HelpButtonThemeData with Diagnosticable { return identical(this, other) || other is HelpButtonThemeData && runtimeType == other.runtimeType && - color?.value == other.color?.value && - disabledColor?.value == other.disabledColor?.value; + color == other.color && + disabledColor == other.disabledColor; } @override @@ -116,9 +106,6 @@ class HelpButtonThemeData with Diagnosticable { /// Merges this [HelpButtonThemeData] with another. HelpButtonThemeData merge(HelpButtonThemeData? other) { if (other == null) return this; - return copyWith( - color: other.color, - disabledColor: other.disabledColor, - ); + return copyWith(color: other.color, disabledColor: other.disabledColor); } } diff --git a/lib/src/theme/icon_button_theme.dart b/lib/src/theme/icon_button_theme.dart index 95e13c6c..bca03d65 100644 --- a/lib/src/theme/icon_button_theme.dart +++ b/lib/src/theme/icon_button_theme.dart @@ -31,8 +31,8 @@ class MacosIconButtonTheme extends InheritedTheme { /// final theme = MacosIconButtonTheme.of(context); /// ``` static MacosIconButtonThemeData of(BuildContext context) { - final MacosIconButtonTheme? buttonTheme = - context.dependOnInheritedWidgetOfExactType(); + final MacosIconButtonTheme? buttonTheme = context + .dependOnInheritedWidgetOfExactType(); return buttonTheme?.data ?? MacosTheme.of(context).iconButtonTheme; } @@ -123,8 +123,11 @@ class MacosIconButtonThemeData with Diagnosticable { hoverColor: Color.lerp(a.hoverColor, b.hoverColor, t), shape: b.shape, borderRadius: BorderRadius.lerp(a.borderRadius, b.borderRadius, t), - boxConstraints: - BoxConstraints.lerp(a.boxConstraints, b.boxConstraints, t), + boxConstraints: BoxConstraints.lerp( + a.boxConstraints, + b.boxConstraints, + t, + ), padding: EdgeInsetsGeometry.lerp(a.padding, b.padding, t), ); } @@ -148,9 +151,9 @@ class MacosIconButtonThemeData with Diagnosticable { identical(this, other) || other is MacosIconButtonThemeData && runtimeType == other.runtimeType && - backgroundColor?.value == other.backgroundColor?.value && - disabledColor?.value == other.disabledColor?.value && - hoverColor?.value == other.hoverColor?.value && + backgroundColor == other.backgroundColor && + disabledColor == other.disabledColor && + hoverColor == other.hoverColor && shape == other.shape && borderRadius == other.borderRadius && boxConstraints == other.boxConstraints && @@ -173,8 +176,9 @@ class MacosIconButtonThemeData with Diagnosticable { properties.add(ColorProperty('disabledColor', disabledColor)); properties.add(ColorProperty('hoverColor', hoverColor)); properties.add(EnumProperty('shape', shape)); - properties - .add(DiagnosticsProperty('borderRadius', borderRadius)); + properties.add( + DiagnosticsProperty('borderRadius', borderRadius), + ); properties.add( DiagnosticsProperty('boxConstraints', boxConstraints), ); diff --git a/lib/src/theme/icon_theme.dart b/lib/src/theme/icon_theme.dart index f3b801f7..b2aae9f9 100644 --- a/lib/src/theme/icon_theme.dart +++ b/lib/src/theme/icon_theme.dart @@ -12,11 +12,7 @@ class MacosIconTheme extends InheritedTheme { /// descendant widgets. /// /// Both [data] and [child] arguments must not be null. - const MacosIconTheme({ - super.key, - required this.data, - required super.child, - }); + const MacosIconTheme({super.key, required this.data, required super.child}); /// Creates an icon theme that controls the color, opacity, and size of /// descendant widgets, and merges in the current icon theme, if any. @@ -61,23 +57,26 @@ class MacosIconTheme extends InheritedTheme { /// MacosIconThemeData theme = MacosIconTheme.of(context); /// ``` static MacosIconThemeData of(BuildContext context) { - final MacosIconThemeData iconThemeData = - _getInheritedIconThemeData(context).resolve(context); + final MacosIconThemeData iconThemeData = _getInheritedIconThemeData( + context, + ).resolve(context); return iconThemeData.isConcrete ? iconThemeData : iconThemeData.copyWith( size: iconThemeData.size ?? const MacosIconThemeData.fallback().size, - color: iconThemeData.color ?? + color: + iconThemeData.color ?? const MacosIconThemeData.fallback().color, - opacity: iconThemeData.opacity ?? + opacity: + iconThemeData.opacity ?? const MacosIconThemeData.fallback().opacity, ); } static MacosIconThemeData _getInheritedIconThemeData(BuildContext context) { - final MacosIconTheme? iconTheme = - context.dependOnInheritedWidgetOfExactType(); + final MacosIconTheme? iconTheme = context + .dependOnInheritedWidgetOfExactType(); return iconTheme?.data ?? MacosTheme.of(context).iconTheme; } @@ -109,27 +108,20 @@ class MacosIconThemeData with Diagnosticable { /// /// The opacity applies to both explicit and default icon colors. The value /// is clamped between 0.0 and 1.0. - const MacosIconThemeData({ - this.color, - double? opacity, - this.size, - }) : _opacity = opacity; + const MacosIconThemeData({this.color, double? opacity, this.size}) + : _opacity = opacity; /// Creates an icon theme with some reasonable default values. /// /// The [color] is blue, the [opacity] is 1.0, and the [size] is 24.0. const MacosIconThemeData.fallback() - : color = const Color.fromARGB(255, 0, 122, 255), - _opacity = 1.0, - size = 24.0; + : color = const Color.fromARGB(255, 0, 122, 255), + _opacity = 1.0, + size = 24.0; /// Creates a copy of this icon theme but with the given fields replaced with /// the new values. - MacosIconThemeData copyWith({ - Color? color, - double? opacity, - double? size, - }) { + MacosIconThemeData copyWith({Color? color, double? opacity, double? size}) { return MacosIconThemeData( color: color ?? this.color, opacity: opacity ?? this.opacity, @@ -199,7 +191,7 @@ class MacosIconThemeData with Diagnosticable { bool operator ==(Object other) { if (other.runtimeType != runtimeType) return false; return other is MacosIconThemeData && - other.color?.value == color?.value && + other.color == color && other.opacity == opacity && other.size == size; } diff --git a/lib/src/theme/macos_colors.dart b/lib/src/theme/macos_colors.dart index 73985d8f..59e539bf 100644 --- a/lib/src/theme/macos_colors.dart +++ b/lib/src/theme/macos_colors.dart @@ -9,36 +9,41 @@ class MacosColor extends Color { /// /// * `a` is the alpha value, with 0 being transparent and 255 being fully /// opaque. - /// * `r` is [red], from 0 to 255. - /// * `g` is [green], from 0 to 255. - /// * `b` is [blue], from 0 to 255. + /// * `r` is red, from 0 to 255. + /// * `g` is green, from 0 to 255. + /// * `b` is blue, from 0 to 255. /// /// Out of range values are brought into range using modulo 255. /// /// See also [fromRGBO], which takes the alpha value as a floating point /// value. const MacosColor.fromARGB(super.a, super.r, super.g, super.b) - : super.fromARGB(); + : super.fromARGB(); /// Create a color from red, green, blue, and opacity, similar to `rgba()` /// in CSS. /// - /// * `r` is [red], from 0 to 255. - /// * `g` is [green], from 0 to 255. - /// * `b` is [blue], from 0 to 255. + /// * `r` is red, from 0 to 255. + /// * `g` is green, from 0 to 255. + /// * `b` is blue, from 0 to 255. /// * `opacity` is alpha channel of this color as a double, with 0.0 being /// transparent and 1.0 being fully opaque. /// /// Out of range values are brought into range using modulo 255. /// /// See also [fromARGB], which takes the opacity as an integer value. - const MacosColor.fromRGBO(super.r, super.g, super.b, super.opcacity) - : super.fromRGBO(); + const MacosColor.fromRGBO(super.r, super.g, super.b, super.opacity) + : super.fromRGBO(); /// Linearly interpolate between two [MacosColor]s. static MacosColor lerp(MacosColor a, MacosColor b, double t) { final Color? color = Color.lerp(a, b, t); - return MacosColor(color!.value); + return MacosColor.fromRGBO( + (color!.r * 255).toInt(), + (color.g * 255).toInt(), + (color.b * 255).toInt(), + color.a, + ); } /// Combine the foreground color as a transparent color over top @@ -50,33 +55,14 @@ class MacosColor extends Color { /// operations for two things that are solid colors with the same shape, but /// overlay each other: instead, just paint one with the combined color. static MacosColor alphaBlend(MacosColor foreground, MacosColor background) { - final int alpha = foreground.alpha; - if (alpha == 0x00) { - // Foreground completely transparent. - return background; - } - final int invAlpha = 0xff - alpha; - int backAlpha = background.alpha; - if (backAlpha == 0xff) { - // Opaque background case - return MacosColor.fromARGB( - 0xff, - (alpha * foreground.red + invAlpha * background.red) ~/ 0xff, - (alpha * foreground.green + invAlpha * background.green) ~/ 0xff, - (alpha * foreground.blue + invAlpha * background.blue) ~/ 0xff, - ); - } else { - // General case - backAlpha = (backAlpha * invAlpha) ~/ 0xff; - final int outAlpha = alpha + backAlpha; - assert(outAlpha != 0x00); - return MacosColor.fromARGB( - outAlpha, - (foreground.red * alpha + background.red * backAlpha) ~/ outAlpha, - (foreground.green * alpha + background.green * backAlpha) ~/ outAlpha, - (foreground.blue * alpha + background.blue * backAlpha) ~/ outAlpha, - ); - } + final newColor = Color.alphaBlend(foreground, background); + + return MacosColor.fromRGBO( + (newColor.r * 255).toInt(), + (newColor.g * 255).toInt(), + (newColor.b * 255).toInt(), + newColor.a, + ); } /// Returns an alpha value representative of the provided [opacity] value. @@ -102,7 +88,12 @@ class MacosColor extends Color { /// Out of range values will have unexpected effects. @override MacosColor withAlpha(int a) { - return MacosColor.fromARGB(a, red, green, blue); + return MacosColor.fromARGB( + a, + (r * 255).toInt(), + (g * 255).toInt(), + (b * 255).toInt(), + ); } /// Darkens a [MacosColor] by a [percent] amount (100 = black) without @@ -110,11 +101,11 @@ class MacosColor extends Color { static MacosColor darken(MacosColor c, [int percent = 10]) { assert(1 <= percent && percent <= 100); var f = 1 - percent / 100; - return MacosColor.fromARGB( - c.alpha, - (c.red * f).round(), - (c.green * f).round(), - (c.blue * f).round(), + return MacosColor.fromRGBO( + (c.r * f * 255).round(), + (c.g * f * 255).round(), + (c.b * f * 255).round(), + c.a, ); } @@ -123,11 +114,11 @@ class MacosColor extends Color { static MacosColor lighten(MacosColor c, [int percent = 10]) { assert(1 <= percent && percent <= 100); var p = percent / 100; - return MacosColor.fromARGB( - c.alpha, - c.red + ((255 - c.red) * p).round(), - c.green + ((255 - c.green) * p).round(), - c.blue + ((255 - c.blue) * p).round(), + return MacosColor.fromRGBO( + (c.r + ((1.0 - c.r) * p) * 255).toInt(), + (c.g + ((1.0 - c.g) * p) * 255).toInt(), + (c.b + ((1.0 - c.b) * p) * 255).toInt(), + c.a, ); } @@ -139,22 +130,26 @@ class MacosColor extends Color { if (other.runtimeType != runtimeType) { return false; } - return other is MacosColor && other.value == value; + return other is MacosColor && other.hashCode == hashCode; } @override - int get hashCode => value.hashCode; + int get hashCode => Object.hash(r, g, b, a); @override - String toString() { - return 'MacosColor(0x${value.toRadixString(16).padLeft(8, '0')})'; - } + String toString() => + 'MacosColor(alpha: ${a.toStringAsFixed(4)}, red: ${r.toStringAsFixed(4)}, green: ${g.toStringAsFixed(4)}, blue: ${b.toStringAsFixed(4)}, colorSpace: $colorSpace)'; } extension ColorX on Color { /// Returns a [MacosColor] with the same color values as this [Color]. MacosColor toMacosColor() { - return MacosColor(value); + return MacosColor.fromRGBO( + (r * 255).floor(), + (g * 255).floor(), + (b * 255).floor(), + a, + ); } } @@ -292,9 +287,9 @@ class MacosColors { /// A background for selected text in a non-key window or view. static const unemphasizedSelectedTextBackgroundColor = CupertinoDynamicColor.withBrightness( - color: MacosColor(0xffDCDCDC), - darkColor: MacosColor(0xff464646), - ); + color: MacosColor(0xffDCDCDC), + darkColor: MacosColor(0xff464646), + ); /// Selected text in a non-key window or view. static const unemphasizedSelectedTextColor = MacosColors.white; @@ -314,8 +309,9 @@ class MacosColors { static const selectedControlBackgroundColor = MacosColor(0xff0058d0); /// The selected content in a non-key window or view. - static const unemphasizedSelectedContentBackgroundColor = - MacosColor(0xff464646); + static const unemphasizedSelectedContentBackgroundColor = MacosColor( + 0xff464646, + ); static const alternatingContentBackgroundColor = MacosColor(0xff2e2c31); @@ -358,9 +354,9 @@ class MacosColors { /// the keyboard for interface navigation. static const keyboardFocusIndicatorColor = CupertinoDynamicColor.withBrightness( - color: Color.fromRGBO(0, 103, 244, 0.25), - darkColor: Color.fromRGBO(26, 169, 255, 0.3), - ); + color: Color.fromRGBO(0, 103, 244, 0.25), + darkColor: Color.fromRGBO(26, 169, 255, 0.3), + ); /// The color of the thumb of [MacosSlider]. static const sliderThumbColor = CupertinoDynamicColor.withBrightness( diff --git a/lib/src/theme/macos_dynamic_color.dart b/lib/src/theme/macos_dynamic_color.dart index 4a23b159..feeb511c 100644 --- a/lib/src/theme/macos_dynamic_color.dart +++ b/lib/src/theme/macos_dynamic_color.dart @@ -74,7 +74,7 @@ extension MacosDynamicColor on CupertinoDynamicColor { final CupertinoUserInterfaceLevelData level = isInterfaceElevationDependent ? CupertinoUserInterfaceLevel.maybeOf(context) ?? - CupertinoUserInterfaceLevelData.base + CupertinoUserInterfaceLevelData.base : CupertinoUserInterfaceLevelData.base; final Color resolved; @@ -94,8 +94,9 @@ extension MacosDynamicColor on CupertinoDynamicColor { case Brightness.dark: switch (level) { case CupertinoUserInterfaceLevelData.base: - resolved = - isHighContrastEnabled ? darkHighContrastColor : darkColor; + resolved = isHighContrastEnabled + ? darkHighContrastColor + : darkColor; break; case CupertinoUserInterfaceLevelData.elevated: resolved = isHighContrastEnabled @@ -139,18 +140,24 @@ class ResolvedMacosDynamicColor extends CupertinoDynamicColor { Color darkHighContrastElevatedColor, Element? debugResolveContext, ) : super( - color: color, - darkColor: darkColor, - highContrastColor: highContrastColor, - darkHighContrastColor: darkHighContrastColor, - elevatedColor: elevatedColor, - darkElevatedColor: darkElevatedColor, - highContrastElevatedColor: highContrastElevatedColor, - darkHighContrastElevatedColor: darkHighContrastElevatedColor, - ); + color: color, + darkColor: darkColor, + highContrastColor: highContrastColor, + darkHighContrastColor: darkHighContrastColor, + elevatedColor: elevatedColor, + darkElevatedColor: darkElevatedColor, + highContrastElevatedColor: highContrastElevatedColor, + darkHighContrastElevatedColor: darkHighContrastElevatedColor, + ); final Color resolvedColor; @override - int get value => resolvedColor.value; + double get r => resolvedColor.r; + + @override + double get g => resolvedColor.g; + + @override + double get b => resolvedColor.b; } diff --git a/lib/src/theme/macos_theme.dart b/lib/src/theme/macos_theme.dart index 7b51b3a0..c963d4e1 100644 --- a/lib/src/theme/macos_theme.dart +++ b/lib/src/theme/macos_theme.dart @@ -4,8 +4,8 @@ import 'package:macos_ui/macos_ui.dart'; import 'package:macos_ui/src/library.dart'; CupertinoDynamicColor _kScrollbarColor = CupertinoDynamicColor.withBrightness( - color: MacosColors.systemGrayColor.color.withOpacity(0.8), - darkColor: MacosColors.systemGrayColor.darkColor.withOpacity(0.8), + color: MacosColors.systemGrayColor.color.withValues(alpha: 0.8), + darkColor: MacosColors.systemGrayColor.darkColor.withValues(alpha: 0.8), ); /// Applies a macOS-style theme to descendant macOS widgets. @@ -26,11 +26,7 @@ class MacosTheme extends StatelessWidget { /// Creates a [MacosTheme] to change descendant macOS widgets' styling. /// /// The [data] and [child] parameters must not be null. - const MacosTheme({ - super.key, - required this.data, - required this.child, - }); + const MacosTheme({super.key, required this.data, required this.child}); /// The [MacosThemeData] styling for this theme. final MacosThemeData data; @@ -47,8 +43,8 @@ class MacosTheme extends StatelessWidget { /// Resolves all the colors defined in that [MacosThemeData] against the /// given [BuildContext] on a best-effort basis. static MacosThemeData of(BuildContext context) { - final _InheritedMacosTheme? inheritedTheme = - context.dependOnInheritedWidgetOfExactType<_InheritedMacosTheme>(); + final _InheritedMacosTheme? inheritedTheme = context + .dependOnInheritedWidgetOfExactType<_InheritedMacosTheme>(); return (inheritedTheme?.theme.data ?? MacosThemeData.fallback()); } @@ -59,8 +55,8 @@ class MacosTheme extends StatelessWidget { /// Resolves all the colors defined in that [MacosThemeData] against the /// given [BuildContext] on a best-effort basis. static MacosThemeData? maybeOf(BuildContext context) { - final _InheritedMacosTheme? inheritedTheme = - context.dependOnInheritedWidgetOfExactType<_InheritedMacosTheme>(); + final _InheritedMacosTheme? inheritedTheme = context + .dependOnInheritedWidgetOfExactType<_InheritedMacosTheme>(); return inheritedTheme?.theme.data; } @@ -80,8 +76,8 @@ class MacosTheme extends StatelessWidget { /// * [MacosThemeData.brightness], the property takes precedence over /// [MediaQueryData.platformBrightness] for descendant Cupertino widgets. static Brightness brightnessOf(BuildContext context) { - final _InheritedMacosTheme? inheritedTheme = - context.dependOnInheritedWidgetOfExactType<_InheritedMacosTheme>(); + final _InheritedMacosTheme? inheritedTheme = context + .dependOnInheritedWidgetOfExactType<_InheritedMacosTheme>(); return inheritedTheme?.theme.data.brightness ?? MediaQuery.of(context).platformBrightness; } @@ -102,18 +98,15 @@ class MacosTheme extends StatelessWidget { /// * [brightnessOf], which throws if no valid [MacosTheme] or /// [MediaQuery] exists, instead of returning null. static Brightness? maybeBrightnessOf(BuildContext context) { - final _InheritedMacosTheme? inheritedTheme = - context.dependOnInheritedWidgetOfExactType<_InheritedMacosTheme>(); + final _InheritedMacosTheme? inheritedTheme = context + .dependOnInheritedWidgetOfExactType<_InheritedMacosTheme>(); return inheritedTheme?.theme.data.brightness ?? MediaQuery.maybeOf(context)?.platformBrightness; } @override Widget build(BuildContext context) { - return _InheritedMacosTheme( - theme: this, - child: child, - ); + return _InheritedMacosTheme(theme: this, child: child); } @override @@ -224,12 +217,14 @@ class MacosThemeData extends Equatable with Diagnosticable { canvasColor ??= isDark ? const Color.fromRGBO(40, 40, 40, 1.0) : const Color.fromRGBO(246, 246, 246, 1.0); - typography ??= - isDark ? MacosTypography.lightOpaque() : MacosTypography.darkOpaque(); + typography ??= isDark + ? MacosTypography.lightOpaque() + : MacosTypography.darkOpaque(); pushButtonTheme ??= PushButtonThemeData( color: primaryColor, - secondaryColor: - isDark ? const Color.fromRGBO(110, 109, 112, 1.0) : MacosColors.white, + secondaryColor: isDark + ? const Color.fromRGBO(110, 109, 112, 1.0) + : MacosColors.white, disabledColor: isDark ? const Color.fromRGBO(255, 255, 255, 0.1) : const Color.fromRGBO(244, 245, 245, 1.0), @@ -336,8 +331,9 @@ class MacosThemeData extends Equatable with Diagnosticable { monthViewCurrentDateColor: isDark ? const Color.fromRGBO(0, 88, 208, 1) : const Color.fromRGBO(0, 99, 255, 1), - monthViewSelectedDateColor: - isDark ? const MacosColor(0xff464646) : const MacosColor(0xffDCDCDC), + monthViewSelectedDateColor: isDark + ? const MacosColor(0xff464646) + : const MacosColor(0xffDCDCDC), monthViewHeaderDividerColor: isDark ? const Color.fromRGBO(255, 255, 255, 0.1) : const Color.fromRGBO(0, 0, 0, 0.1), @@ -455,18 +451,14 @@ class MacosThemeData extends Equatable with Diagnosticable { factory MacosThemeData.light({ AccentColor? accentColor, bool? isMainWindow, - }) => - MacosThemeData( - brightness: Brightness.light, - accentColor: accentColor, - isMainWindow: isMainWindow, - ); + }) => MacosThemeData( + brightness: Brightness.light, + accentColor: accentColor, + isMainWindow: isMainWindow, + ); /// A default dark theme. - factory MacosThemeData.dark({ - AccentColor? accentColor, - bool? isMainWindow, - }) => + factory MacosThemeData.dark({AccentColor? accentColor, bool? isMainWindow}) => MacosThemeData( brightness: Brightness.dark, accentColor: accentColor, @@ -477,8 +469,8 @@ class MacosThemeData extends Equatable with Diagnosticable { /// /// This is used by [MacosTheme.of] when no theme has been specified. factory MacosThemeData.fallback() => MacosThemeData.light().copyWith( - visualDensity: VisualDensity.adaptivePlatformDensity, - ); + visualDensity: VisualDensity.adaptivePlatformDensity, + ); /// The overall theme brightness. /// @@ -555,14 +547,23 @@ class MacosThemeData extends Equatable with Diagnosticable { primaryColor: Color.lerp(a.primaryColor, b.primaryColor, t)!, canvasColor: Color.lerp(a.primaryColor, b.primaryColor, t)!, typography: MacosTypography.lerp(a.typography, b.typography, t), - helpButtonTheme: - HelpButtonThemeData.lerp(a.helpButtonTheme, b.helpButtonTheme, t), + helpButtonTheme: HelpButtonThemeData.lerp( + a.helpButtonTheme, + b.helpButtonTheme, + t, + ), pushButtonTheme: a.pushButtonTheme, - tooltipTheme: - MacosTooltipThemeData.lerp(a.tooltipTheme, b.tooltipTheme, t), + tooltipTheme: MacosTooltipThemeData.lerp( + a.tooltipTheme, + b.tooltipTheme, + t, + ), visualDensity: VisualDensity.lerp(a.visualDensity, b.visualDensity, t), - scrollbarTheme: - MacosScrollbarThemeData.lerp(a.scrollbarTheme, b.scrollbarTheme, t), + scrollbarTheme: MacosScrollbarThemeData.lerp( + a.scrollbarTheme, + b.scrollbarTheme, + t, + ), iconButtonTheme: MacosIconButtonThemeData.lerp( a.iconButtonTheme, b.iconButtonTheme, @@ -677,16 +678,21 @@ class MacosThemeData extends Equatable with Diagnosticable { properties.add(ColorProperty('primaryColor', primaryColor)); properties.add(ColorProperty('canvasColor', canvasColor)); properties.add(ColorProperty('dividerColor', dividerColor)); - properties - .add(DiagnosticsProperty('typography', typography)); - properties.add(DiagnosticsProperty( - 'pushButtonTheme', - pushButtonTheme, - )); - properties.add(DiagnosticsProperty( - 'helpButtonTheme', - helpButtonTheme, - )); + properties.add( + DiagnosticsProperty('typography', typography), + ); + properties.add( + DiagnosticsProperty( + 'pushButtonTheme', + pushButtonTheme, + ), + ); + properties.add( + DiagnosticsProperty( + 'helpButtonTheme', + helpButtonTheme, + ), + ); properties.add( DiagnosticsProperty('tooltipTheme', tooltipTheme), ); @@ -733,41 +739,33 @@ class MacosThemeData extends Equatable with Diagnosticable { ), ); properties.add( - DiagnosticsProperty( - 'accentColor', - accentColor, - ), - ); - properties.add( - DiagnosticsProperty( - 'isMainWindow', - isMainWindow, - ), + 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, + primaryColor, + canvasColor, + typography, + pushButtonTheme, + dividerColor, + helpButtonTheme, + tooltipTheme, + visualDensity, + scrollbarTheme, + iconButtonTheme, + iconTheme, + popupButtonTheme, + pulldownButtonTheme, + datePickerTheme, + timePickerTheme, + searchFieldTheme, + accentColor, + isMainWindow, + ]; } /// Brightness extensions diff --git a/lib/src/theme/overlay_filter.dart b/lib/src/theme/overlay_filter.dart index 13ad0ccb..a4676799 100644 --- a/lib/src/theme/overlay_filter.dart +++ b/lib/src/theme/overlay_filter.dart @@ -40,7 +40,8 @@ class MacosOverlayFilter extends StatelessWidget { return WallpaperTintingOverride( child: Container( decoration: BoxDecoration( - color: color ?? + color: + color ?? (brightness.isDark ? const Color.fromRGBO(30, 30, 30, 1) : const Color.fromRGBO(242, 242, 247, 1)), @@ -51,7 +52,7 @@ class MacosOverlayFilter extends StatelessWidget { CupertinoColors.systemGrey.color, CupertinoColors.black, ) - .withOpacity(0.25), + .withValues(alpha: 0.25), offset: const Offset(0, 4), spreadRadius: 4.0, blurRadius: 8.0, @@ -68,10 +69,7 @@ class MacosOverlayFilter extends StatelessWidget { child: ClipRRect( borderRadius: borderRadius, child: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: 20.0, - sigmaY: 20.0, - ), + filter: ImageFilter.blur(sigmaX: 20.0, sigmaY: 20.0), child: child, ), ), diff --git a/lib/src/theme/popup_button_theme.dart b/lib/src/theme/popup_button_theme.dart index 41c710d0..51ba6d84 100644 --- a/lib/src/theme/popup_button_theme.dart +++ b/lib/src/theme/popup_button_theme.dart @@ -31,8 +31,8 @@ class MacosPopupButtonTheme extends InheritedTheme { /// MacosPopupButtonTheme theme = MacosPopupButtonTheme.of(context); /// ``` static MacosPopupButtonThemeData of(BuildContext context) { - final MacosPopupButtonTheme? buttonTheme = - context.dependOnInheritedWidgetOfExactType(); + final MacosPopupButtonTheme? buttonTheme = context + .dependOnInheritedWidgetOfExactType(); return buttonTheme?.data ?? MacosTheme.of(context).popupButtonTheme; } @@ -107,9 +107,9 @@ class MacosPopupButtonThemeData with Diagnosticable { identical(this, other) || other is MacosPopupButtonThemeData && runtimeType == other.runtimeType && - highlightColor?.value == other.highlightColor?.value && - backgroundColor?.value == other.backgroundColor?.value && - popupColor?.value == other.popupColor?.value; + highlightColor == other.highlightColor && + backgroundColor == other.backgroundColor && + popupColor == other.popupColor; @override int get hashCode => highlightColor.hashCode ^ backgroundColor.hashCode; diff --git a/lib/src/theme/pulldown_button_theme.dart b/lib/src/theme/pulldown_button_theme.dart index 49e82700..19c51a26 100644 --- a/lib/src/theme/pulldown_button_theme.dart +++ b/lib/src/theme/pulldown_button_theme.dart @@ -31,8 +31,8 @@ class MacosPulldownButtonTheme extends InheritedTheme { /// MacosPulldownButtonTheme theme = MacosPulldownButtonTheme.of(context); /// ``` static MacosPulldownButtonThemeData of(BuildContext context) { - final MacosPulldownButtonTheme? buttonTheme = - context.dependOnInheritedWidgetOfExactType(); + final MacosPulldownButtonTheme? buttonTheme = context + .dependOnInheritedWidgetOfExactType(); return buttonTheme?.data ?? MacosTheme.of(context).pulldownButtonTheme; } @@ -114,10 +114,10 @@ class MacosPulldownButtonThemeData with Diagnosticable { identical(this, other) || other is MacosPulldownButtonThemeData && runtimeType == other.runtimeType && - highlightColor?.value == other.highlightColor?.value && - backgroundColor?.value == other.backgroundColor?.value && - pulldownColor?.value == other.pulldownColor?.value && - iconColor?.value == other.iconColor?.value; + highlightColor == other.highlightColor && + backgroundColor == other.backgroundColor && + pulldownColor == other.pulldownColor && + iconColor == other.iconColor; @override int get hashCode => highlightColor.hashCode ^ backgroundColor.hashCode; diff --git a/lib/src/theme/push_button_theme.dart b/lib/src/theme/push_button_theme.dart index 0c69aebd..5def6c02 100644 --- a/lib/src/theme/push_button_theme.dart +++ b/lib/src/theme/push_button_theme.dart @@ -9,16 +9,13 @@ import 'package:macos_ui/src/library.dart'; /// * [PushButtonThemeData], which is used to configure this theme. class PushButtonTheme extends InheritedTheme { /// Create a [PushButtonTheme]. - const PushButtonTheme({ - super.key, - required this.data, - required super.child, - }); + const PushButtonTheme({super.key, required this.data, required super.child}); /// The configuration of this theme. @Deprecated( - "'PushButton' no longer uses singular colors and therefore cannot " - "be themed using a 'PushButtonTheme'.") + "'PushButton' no longer uses singular colors and therefore cannot " + "be themed using a 'PushButtonTheme'.", + ) final PushButtonThemeData data; /// The closest instance of this class that encloses the given context. @@ -32,26 +29,29 @@ class PushButtonTheme extends InheritedTheme { /// PushButtonTheme theme = PushButtonTheme.of(context); /// ``` @Deprecated( - "'PushButton' no longer uses singular colors and therefore cannot " - "be themed using a 'PushButtonTheme'.") + "'PushButton' no longer uses singular colors and therefore cannot " + "be themed using a 'PushButtonTheme'.", + ) static PushButtonThemeData of(BuildContext context) { - final PushButtonTheme? buttonTheme = - context.dependOnInheritedWidgetOfExactType(); + final PushButtonTheme? buttonTheme = context + .dependOnInheritedWidgetOfExactType(); return buttonTheme?.data ?? MacosTheme.of(context).pushButtonTheme; } @override @Deprecated( - "'PushButton' no longer uses singular colors and therefore cannot " - "be themed using a 'PushButtonTheme'.") + "'PushButton' no longer uses singular colors and therefore cannot " + "be themed using a 'PushButtonTheme'.", + ) Widget wrap(BuildContext context, Widget child) { return PushButtonTheme(data: data, child: child); } @override @Deprecated( - "'PushButton' no longer uses singular colors and therefore cannot " - "be themed using a 'PushButtonTheme'.") + "'PushButton' no longer uses singular colors and therefore cannot " + "be themed using a 'PushButtonTheme'.", + ) bool updateShouldNotify(PushButtonTheme oldWidget) => data != oldWidget.data; } @@ -74,26 +74,30 @@ class PushButtonThemeData with Diagnosticable { /// The default background color for [PushButton] @Deprecated( - "'PushButton' no longer uses singular colors and therefore cannot " - "be themed using a 'PushButtonTheme'.") + "'PushButton' no longer uses singular colors and therefore cannot " + "be themed using a 'PushButtonTheme'.", + ) final Color? color; /// The default disabled color for [PushButton] @Deprecated( - "'PushButton' no longer uses singular colors and therefore cannot " - "be themed using a 'PushButtonTheme'.") + "'PushButton' no longer uses singular colors and therefore cannot " + "be themed using a 'PushButtonTheme'.", + ) final Color? disabledColor; /// The default secondary color (e.g. Cancel/Go back buttons) for [PushButton] @Deprecated( - "'PushButton' no longer uses singular colors and therefore cannot " - "be themed using a 'PushButtonTheme'.") + "'PushButton' no longer uses singular colors and therefore cannot " + "be themed using a 'PushButtonTheme'.", + ) final Color? secondaryColor; /// Copies this [PushButtonThemeData] into another. @Deprecated( - "'PushButton' no longer uses singular colors and therefore cannot " - "be themed using a 'PushButtonTheme'.") + "'PushButton' no longer uses singular colors and therefore cannot " + "be themed using a 'PushButtonTheme'.", + ) PushButtonThemeData copyWith({ Color? color, Color? disabledColor, @@ -110,8 +114,9 @@ class PushButtonThemeData with Diagnosticable { /// /// All the properties must be non-null. @Deprecated( - "'PushButton' no longer uses singular colors and therefore cannot " - "be themed using a 'PushButtonTheme'.") + "'PushButton' no longer uses singular colors and therefore cannot " + "be themed using a 'PushButtonTheme'.", + ) static PushButtonThemeData lerp( PushButtonThemeData a, PushButtonThemeData b, @@ -126,8 +131,9 @@ class PushButtonThemeData with Diagnosticable { @override @Deprecated( - "'PushButton' no longer uses singular colors and therefore cannot " - "be themed using a 'PushButtonTheme'.") + "'PushButton' no longer uses singular colors and therefore cannot " + "be themed using a 'PushButtonTheme'.", + ) bool operator ==(Object other) => identical(this, other) || other is PushButtonThemeData && @@ -138,14 +144,16 @@ class PushButtonThemeData with Diagnosticable { @override @Deprecated( - "'PushButton' no longer uses singular colors and therefore cannot " - "be themed using a 'PushButtonTheme'.") + "'PushButton' no longer uses singular colors and therefore cannot " + "be themed using a 'PushButtonTheme'.", + ) int get hashCode => color.hashCode ^ disabledColor.hashCode; @override @Deprecated( - "'PushButton' no longer uses singular colors and therefore cannot " - "be themed using a 'PushButtonTheme'.") + "'PushButton' no longer uses singular colors and therefore cannot " + "be themed using a 'PushButtonTheme'.", + ) void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(ColorProperty('color', color)); @@ -155,8 +163,9 @@ class PushButtonThemeData with Diagnosticable { /// Merges this [PushButtonThemeData] with another. @Deprecated( - "'PushButton' no longer uses singular colors and therefore cannot " - "be themed using a 'PushButtonTheme'.") + "'PushButton' no longer uses singular colors and therefore cannot " + "be themed using a 'PushButtonTheme'.", + ) PushButtonThemeData merge(PushButtonThemeData? other) { if (other == null) return this; return copyWith( diff --git a/lib/src/theme/scrollbar_theme.dart b/lib/src/theme/scrollbar_theme.dart index 2655e4de..88180e35 100644 --- a/lib/src/theme/scrollbar_theme.dart +++ b/lib/src/theme/scrollbar_theme.dart @@ -39,8 +39,8 @@ class MacosScrollbarTheme extends InheritedWidget { /// ScrollbarThemeData theme = ScrollbarTheme.of(context); /// ``` static MacosScrollbarThemeData of(BuildContext context) { - final MacosScrollbarTheme? scrollbarTheme = - context.dependOnInheritedWidgetOfExactType(); + final MacosScrollbarTheme? scrollbarTheme = context + .dependOnInheritedWidgetOfExactType(); return scrollbarTheme?.data ?? MacosTheme.of(context).scrollbarTheme; } @@ -180,16 +180,20 @@ class MacosScrollbarThemeData with Diagnosticable { properties.add( DiagnosticsProperty('thickness', thickness, defaultValue: null), ); - properties.add(DiagnosticsProperty( - 'thicknessWhileHovering', - thicknessWhileHovering, - defaultValue: null, - )); - properties.add(DiagnosticsProperty( - 'thumbVisibility', - thumbVisibility, - defaultValue: null, - )); + properties.add( + DiagnosticsProperty( + 'thicknessWhileHovering', + thicknessWhileHovering, + defaultValue: null, + ), + ); + properties.add( + DiagnosticsProperty( + 'thumbVisibility', + thumbVisibility, + defaultValue: null, + ), + ); properties.add( DiagnosticsProperty('radius', radius, defaultValue: null), ); diff --git a/lib/src/theme/search_field_theme.dart b/lib/src/theme/search_field_theme.dart index 0f49d9e0..9efea622 100644 --- a/lib/src/theme/search_field_theme.dart +++ b/lib/src/theme/search_field_theme.dart @@ -31,8 +31,8 @@ class MacosSearchFieldTheme extends InheritedTheme { /// MacosSearchFieldTheme theme = MacosSearchFieldTheme.of(context); /// ``` static MacosSearchFieldThemeData of(BuildContext context) { - final MacosSearchFieldTheme? searchFieldTheme = - context.dependOnInheritedWidgetOfExactType(); + final MacosSearchFieldTheme? searchFieldTheme = context + .dependOnInheritedWidgetOfExactType(); return searchFieldTheme?.data ?? MacosTheme.of(context).searchFieldTheme; } @@ -109,8 +109,8 @@ class MacosSearchFieldThemeData with Diagnosticable { identical(this, other) || other is MacosSearchFieldThemeData && runtimeType == other.runtimeType && - highlightColor?.value == other.highlightColor?.value && - resultsBackgroundColor?.value == other.resultsBackgroundColor?.value; + highlightColor == other.highlightColor && + resultsBackgroundColor == other.resultsBackgroundColor; @override int get hashCode => highlightColor.hashCode ^ resultsBackgroundColor.hashCode; @@ -119,10 +119,9 @@ class MacosSearchFieldThemeData with Diagnosticable { void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(ColorProperty('highlightColor', highlightColor)); - properties.add(ColorProperty( - 'resultsBackgroundColor', - resultsBackgroundColor, - )); + properties.add( + ColorProperty('resultsBackgroundColor', resultsBackgroundColor), + ); } /// Merges this [MacosSearchFieldThemeData] with another. diff --git a/lib/src/theme/time_picker_theme.dart b/lib/src/theme/time_picker_theme.dart index 47777a7d..b3a3f53f 100644 --- a/lib/src/theme/time_picker_theme.dart +++ b/lib/src/theme/time_picker_theme.dart @@ -31,8 +31,8 @@ class MacosTimePickerTheme extends InheritedTheme { /// final theme = MacosTimePickerTheme.of(context); /// ``` static MacosTimePickerThemeData of(BuildContext context) { - final MacosTimePickerTheme? datePickerTheme = - context.dependOnInheritedWidgetOfExactType(); + final MacosTimePickerTheme? datePickerTheme = context + .dependOnInheritedWidgetOfExactType(); return datePickerTheme?.data ?? MacosTheme.of(context).timePickerTheme; } @@ -168,10 +168,16 @@ class MacosTimePickerThemeData with Diagnosticable { ) { return MacosTimePickerThemeData( backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t), - selectedElementColor: - Color.lerp(a.selectedElementColor, b.selectedElementColor, t), - selectedElementTextColor: - Color.lerp(a.selectedElementTextColor, b.selectedElementTextColor, t), + selectedElementColor: Color.lerp( + a.selectedElementColor, + b.selectedElementColor, + t, + ), + selectedElementTextColor: Color.lerp( + a.selectedElementTextColor, + b.selectedElementTextColor, + t, + ), caretColor: Color.lerp(a.caretColor, b.caretColor, t), caretControlsBackgroundColor: Color.lerp( a.caretControlsBackgroundColor, @@ -183,24 +189,15 @@ class MacosTimePickerThemeData with Diagnosticable { b.caretControlsSeparatorColor, t, ), - clockViewBackgroundColor: - Color.lerp(a.clockViewBackgroundColor, b.clockViewBackgroundColor, t), - hourHandColor: Color.lerp(a.hourHandColor, b.hourHandColor, t), - minuteHandColor: Color.lerp( - a.minuteHandColor, - b.minuteHandColor, - t, - ), - secondHandColor: Color.lerp( - a.secondHandColor, - b.secondHandColor, - t, - ), - hourTextColor: Color.lerp( - a.hourTextColor, - b.hourTextColor, + clockViewBackgroundColor: Color.lerp( + a.clockViewBackgroundColor, + b.clockViewBackgroundColor, t, ), + hourHandColor: Color.lerp(a.hourHandColor, b.hourHandColor, t), + minuteHandColor: Color.lerp(a.minuteHandColor, b.minuteHandColor, t), + secondHandColor: Color.lerp(a.secondHandColor, b.secondHandColor, t), + hourTextColor: Color.lerp(a.hourTextColor, b.hourTextColor, t), dayPeriodTextColor: Color.lerp( a.dayPeriodTextColor, b.dayPeriodTextColor, @@ -282,37 +279,32 @@ class MacosTimePickerThemeData with Diagnosticable { ColorProperty('selectedElementTextColor', selectedElementTextColor), ); properties.add(ColorProperty('caretColor', caretColor)); - properties.add(ColorProperty( - 'caretControlsBackgroundColor', - caretControlsBackgroundColor, - )); - properties.add(ColorProperty( - 'caretControlsSeparatorColor', - caretControlsSeparatorColor, - )); - properties - .add(ColorProperty('monthViewControlsColor', clockViewBackgroundColor)); + properties.add( + ColorProperty( + 'caretControlsBackgroundColor', + caretControlsBackgroundColor, + ), + ); + properties.add( + ColorProperty('caretControlsSeparatorColor', caretControlsSeparatorColor), + ); + properties.add( + ColorProperty('monthViewControlsColor', clockViewBackgroundColor), + ); properties.add(ColorProperty('monthViewHeaderColor', hourHandColor)); - properties.add(ColorProperty( - 'monthViewSelectedDateColor', - minuteHandColor, - )); - properties.add(ColorProperty( - 'monthViewSelectedDateTextColor', - secondHandColor, - )); - properties.add(ColorProperty( - 'monthViewCurrentDateColor', - hourTextColor, - )); - properties.add(ColorProperty( - 'monthViewWeekdayHeaderColor', - dayPeriodTextColor, - )); - properties.add(ColorProperty( - 'monthViewHeaderDividerColor', - clockViewBorderColor, - )); + properties.add( + ColorProperty('monthViewSelectedDateColor', minuteHandColor), + ); + properties.add( + ColorProperty('monthViewSelectedDateTextColor', secondHandColor), + ); + properties.add(ColorProperty('monthViewCurrentDateColor', hourTextColor)); + properties.add( + ColorProperty('monthViewWeekdayHeaderColor', dayPeriodTextColor), + ); + properties.add( + ColorProperty('monthViewHeaderDividerColor', clockViewBorderColor), + ); properties.add(ColorProperty('shadowColor', shadowColor)); } } diff --git a/lib/src/theme/tooltip_theme.dart b/lib/src/theme/tooltip_theme.dart index 1551c8bd..bc2bac23 100644 --- a/lib/src/theme/tooltip_theme.dart +++ b/lib/src/theme/tooltip_theme.dart @@ -29,8 +29,8 @@ class MacosTooltipTheme extends InheritedTheme { /// TooltipThemeData theme = TooltipTheme.of(context); /// ``` static MacosTooltipThemeData of(BuildContext context) { - final MacosTooltipTheme? tooltipTheme = - context.dependOnInheritedWidgetOfExactType(); + final MacosTooltipTheme? tooltipTheme = context + .dependOnInheritedWidgetOfExactType(); return tooltipTheme?.data ?? MacosTheme.of(context).tooltipTheme; } @@ -85,16 +85,17 @@ class MacosTooltipThemeData with Diagnosticable { waitDuration: const Duration(seconds: 1), showDuration: const Duration(seconds: 10), textStyle: textStyle.copyWith( - color: - brightness.isDark ? CupertinoColors.white : CupertinoColors.black, + color: brightness.isDark + ? CupertinoColors.white + : CupertinoColors.black, ), decoration: () { const radius = BorderRadius.all(Radius.circular(2.0)); final shadow = [ BoxShadow( color: brightness.isDark - ? CupertinoColors.black.withOpacity(0.5) - : CupertinoColors.systemGrey3.color.withOpacity(0.5), + ? CupertinoColors.black.withValues(alpha: 0.5) + : CupertinoColors.systemGrey3.color.withValues(alpha: 0.5), offset: const Offset(0, 2), spreadRadius: 0.5, blurRadius: 4, @@ -277,17 +278,11 @@ class MacosTooltipThemeData with Diagnosticable { super.debugFillProperties(properties); properties.add(DoubleProperty('height', height)); properties.add(DoubleProperty('verticalOffset', verticalOffset)); + properties.add(DiagnosticsProperty('padding', padding)); + properties.add(DiagnosticsProperty('margin', margin)); properties.add( - DiagnosticsProperty('padding', padding), + FlagProperty('preferBelow', value: preferBelow, ifFalse: 'prefer above'), ); - properties.add( - DiagnosticsProperty('margin', margin), - ); - properties.add(FlagProperty( - 'preferBelow', - value: preferBelow, - ifFalse: 'prefer above', - )); properties.add(DiagnosticsProperty('decoration', decoration)); properties.add(DiagnosticsProperty('waitDuration', waitDuration)); properties.add(DiagnosticsProperty('showDuration', showDuration)); diff --git a/lib/src/theme/typography.dart b/lib/src/theme/typography.dart index 462e332e..2604f62c 100644 --- a/lib/src/theme/typography.dart +++ b/lib/src/theme/typography.dart @@ -242,77 +242,99 @@ class MacosTypography extends Equatable with Diagnosticable { void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); final defaultStyle = MacosTypography.darkOpaque(); - properties.add(DiagnosticsProperty( - 'largeTitle', - largeTitle, - defaultValue: defaultStyle.largeTitle, - )); - properties.add(DiagnosticsProperty( - 'title1', - title1, - defaultValue: defaultStyle.title1, - )); - properties.add(DiagnosticsProperty( - 'title2', - title2, - defaultValue: defaultStyle.title2, - )); - properties.add(DiagnosticsProperty( - 'title3', - title3, - defaultValue: defaultStyle.title3, - )); - properties.add(DiagnosticsProperty( - 'headline', - headline, - defaultValue: defaultStyle.headline, - )); - properties.add(DiagnosticsProperty( - 'subheadline', - subheadline, - defaultValue: defaultStyle.subheadline, - )); - properties.add(DiagnosticsProperty( - 'body', - body, - defaultValue: defaultStyle.body, - )); - properties.add(DiagnosticsProperty( - 'callout', - callout, - defaultValue: defaultStyle.callout, - )); - properties.add(DiagnosticsProperty( - 'footnote', - footnote, - defaultValue: defaultStyle.footnote, - )); - properties.add(DiagnosticsProperty( - 'caption1', - caption1, - defaultValue: defaultStyle.caption1, - )); - properties.add(DiagnosticsProperty( - 'caption2', - caption2, - defaultValue: defaultStyle.caption2, - )); - } - - @override - List get props => [ - body, - callout, - caption1, - caption2, - footnote, - headline, + properties.add( + DiagnosticsProperty( + 'largeTitle', largeTitle, - subheadline, + defaultValue: defaultStyle.largeTitle, + ), + ); + properties.add( + DiagnosticsProperty( + 'title1', title1, + defaultValue: defaultStyle.title1, + ), + ); + properties.add( + DiagnosticsProperty( + 'title2', title2, + defaultValue: defaultStyle.title2, + ), + ); + properties.add( + DiagnosticsProperty( + 'title3', title3, - ]; + defaultValue: defaultStyle.title3, + ), + ); + properties.add( + DiagnosticsProperty( + 'headline', + headline, + defaultValue: defaultStyle.headline, + ), + ); + properties.add( + DiagnosticsProperty( + 'subheadline', + subheadline, + defaultValue: defaultStyle.subheadline, + ), + ); + properties.add( + DiagnosticsProperty( + 'body', + body, + defaultValue: defaultStyle.body, + ), + ); + properties.add( + DiagnosticsProperty( + 'callout', + callout, + defaultValue: defaultStyle.callout, + ), + ); + properties.add( + DiagnosticsProperty( + 'footnote', + footnote, + defaultValue: defaultStyle.footnote, + ), + ); + properties.add( + DiagnosticsProperty( + 'caption1', + caption1, + defaultValue: defaultStyle.caption1, + ), + ); + properties.add( + DiagnosticsProperty( + 'caption2', + caption2, + 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. @@ -431,9 +453,11 @@ class MacosFontWeight implements FontWeight { if (a == null && b == null) { return null; } - return values[_lerpInt((a ?? normal).index, (b ?? normal).index, t) - .round() - .clamp(0, 8)]; + return values[_lerpInt( + (a ?? normal).index, + (b ?? normal).index, + t, + ).round().clamp(0, 8)]; } @override diff --git a/lib/src/utils/accent_color_listener.dart b/lib/src/utils/accent_color_listener.dart index 5965e3ab..b861e8c1 100644 --- a/lib/src/utils/accent_color_listener.dart +++ b/lib/src/utils/accent_color_listener.dart @@ -93,20 +93,20 @@ class AccentColorListener { void _initSystemColorObserver() { assert(_systemColorObserverStreamSubscription == null); - _systemColorObserverStreamSubscription = - AppkitUiElementColors.systemColorObserver.stream.listen((_) { - _initCurrentAccentColor(); - _accentColorStreamController.add(null); - }); + _systemColorObserverStreamSubscription = AppkitUiElementColors + .systemColorObserver + .stream + .listen((_) { + _initCurrentAccentColor(); + _accentColorStreamController.add(null); + }); } /// Returns the hue component of the active accent color selection on macOS. Future _getHueComponent() async { final color = await AppkitUiElementColors.getColorComponents( uiElementColor: UiElementColor.controlAccentColor, - components: const { - NSColorComponent.hueComponent, - }, + components: const {NSColorComponent.hueComponent}, colorSpace: NSColorSpace.genericRGB, appearance: NSAppearanceName.aqua, ); diff --git a/lib/src/utils/utils.dart b/lib/src/utils/utils.dart index 29be5e12..160b6540 100644 --- a/lib/src/utils/utils.dart +++ b/lib/src/utils/utils.dart @@ -45,11 +45,11 @@ Color textLuminance(Color backgroundColor) { Color helpIconLuminance(Color backgroundColor, bool isDark) { return !isDark ? backgroundColor.computeLuminance() > 0.5 - ? CupertinoColors.black - : CupertinoColors.white + ? CupertinoColors.black + : CupertinoColors.white : backgroundColor.computeLuminance() < 0.5 - ? CupertinoColors.black - : CupertinoColors.white; + ? CupertinoColors.black + : CupertinoColors.white; } Color iconLuminance(Color backgroundColor, bool isDark) { diff --git a/lib/src/utils/window_main_state_listener.dart b/lib/src/utils/window_main_state_listener.dart index c926f2b3..7d50da15 100644 --- a/lib/src/utils/window_main_state_listener.dart +++ b/lib/src/utils/window_main_state_listener.dart @@ -42,12 +42,23 @@ class WindowMainStateListener { /// Whether the window is currently the main window. bool _isMainWindow = true; + /// Overrides the value of [_isMainWindow]. + bool? _isMainWindowOverride; + /// Whether the window is currently the main window. - bool get isMainWindow => _isMainWindow; + bool get isMainWindow => _isMainWindowOverride ?? _isMainWindow; /// Notifies listeners when the windowโ€™s main state changes. final _windowMainStateStreamController = StreamController.broadcast(); + /// Overrides the value of [isMainWindow]. + /// + /// Passing `null` will remove the override. + void overrideIsMainWindow(bool? value) { + _isMainWindowOverride = value; + _windowMainStateStreamController.add(isMainWindow); + } + /// A stream of the windowโ€™s main state. Emits a new value whenever the state /// changes. Stream get onChanged => _windowMainStateStreamController.stream; diff --git a/macos/macos_ui.podspec b/macos/macos_ui.podspec index 947c74a3..265e4548 100644 --- a/macos/macos_ui.podspec +++ b/macos/macos_ui.podspec @@ -7,13 +7,15 @@ Pod::Spec.new do |s| s.version = '0.1.0' s.summary = 'Native functionality for the macos_ui Flutter package.' s.description = <<-DESC -A new flutter plugin project. +macos_ui is a Flutter package that provides widgets and themes implementing the current macOS design language. DESC s.homepage = 'https://github.com/macosui/macos_ui' - s.license = { :file => '../LICENSE' } + s.license = { :file => '../LICENSE', :type => 'MIT' } s.author = { 'GroovinChip' => 'groovinchip@gmail.com' } - s.source = { :path => '.' } - s.source_files = 'Classes/**/*' + s.source = { :git => 'https://github.com/macosui/macos_ui.git', + :tag => s.version.to_s } + s.source_files = 'macos_ui/Sources/macos_ui/**/*.swift' + s.resource_bundles = {'macos_ui_privacy' => ['macos_ui/Sources/macos_ui/Resources/PrivacyInfo.xcprivacy']} s.dependency 'FlutterMacOS' s.platform = :osx, '10.11' diff --git a/macos/macos_ui/Package.swift b/macos/macos_ui/Package.swift new file mode 100644 index 00000000..29cb697f --- /dev/null +++ b/macos/macos_ui/Package.swift @@ -0,0 +1,24 @@ +// swift-tools-version: 5.9 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "macos_ui", + platforms: [ + .macOS("10.14") + ], + products: [ + .library(name: "macos-ui", targets: ["macos_ui"]) + ], + dependencies: [], + targets: [ + .target( + name: "macos_ui", + dependencies: [], + resources: [ + .process("Resources"), + ] + ) + ] +) \ No newline at end of file diff --git a/macos/Classes/ColorPanelProvider.swift b/macos/macos_ui/Sources/macos_ui/ColorPanelProvider.swift similarity index 100% rename from macos/Classes/ColorPanelProvider.swift rename to macos/macos_ui/Sources/macos_ui/ColorPanelProvider.swift diff --git a/macos/Classes/MacosUiPlugin.swift b/macos/macos_ui/Sources/macos_ui/MacosUiPlugin.swift similarity index 100% rename from macos/Classes/MacosUiPlugin.swift rename to macos/macos_ui/Sources/macos_ui/MacosUiPlugin.swift diff --git a/macos/macos_ui/Sources/macos_ui/Resources/PrivacyInfo.xcprivacy b/macos/macos_ui/Sources/macos_ui/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 00000000..c88e30ff --- /dev/null +++ b/macos/macos_ui/Sources/macos_ui/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,12 @@ + + + + + NSPrivacyTrackingDomains + + NSPrivacyCollectedDataTypes + + NSPrivacyTracking + + + \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index cf35ae3d..bc4e7b02 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,66 +5,66 @@ packages: dependency: "direct main" description: name: appkit_ui_element_colors - sha256: c3e50f900aae314d339de489535736238627071457c4a4a2dbbb1545b4f04f22 + sha256: b88a7c35d440fa3ac75222d0e2b7e3259200e531e33b5d2468e358119f3481dc url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.0.1" async: dependency: transitive description: name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" url: "https://pub.dev" source: hosted - version: "2.11.0" + version: "2.13.0" boolean_selector: dependency: transitive description: name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" characters: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" clock: dependency: transitive description: name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" collection: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.1" equatable: dependency: "direct main" description: name: equatable - sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7" url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.0.7" fake_async: dependency: transitive description: name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.3" flutter: dependency: "direct main" description: flutter @@ -74,10 +74,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" + sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "6.0.0" flutter_test: dependency: "direct dev" description: flutter @@ -87,58 +87,58 @@ packages: dependency: "direct main" description: name: gradient_borders - sha256: b1cd969552c83f458ff755aa68e13a0327d09f06c3f42f471b423b01427f21f8 + sha256: "492bc88ab8d88a4117a7f00e525a669b65f19973bea7ee677f9d9de7603bf037" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.0.2" leak_tracker: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "11.0.2" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" lints: dependency: transitive description: name: lints - sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" + sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0 url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "6.0.0" macos_window_utils: dependency: "direct main" description: name: macos_window_utils - sha256: "230be594d26f6dee92c5a1544f4242d25138a5bfb9f185b27f14de3949ef0be8" + sha256: d4df3501fd32ac0d2d7590cb6a8e4758337d061c8fa0db816fdd636be63a8438 url: "https://pub.dev" source: hosted - version: "1.5.0" + version: "1.9.0" matcher: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.17" material_color_utilities: dependency: transitive description: @@ -151,10 +151,10 @@ packages: dependency: transitive description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.16.0" mocktail: dependency: "direct dev" description: @@ -167,10 +167,10 @@ packages: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" plugin_platform_interface: dependency: transitive description: @@ -183,71 +183,71 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.10.1" stack_trace: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" string_scanner: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.4.1" term_glyph: dependency: transitive description: name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" test_api: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.6" vector_math: - dependency: transitive + dependency: "direct main" description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 url: "https://pub.dev" source: hosted - version: "14.2.5" + version: "15.0.0" sdks: - dart: ">=3.5.3 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" + dart: ">=3.9.2 <4.0.0" + flutter: ">=3.35.0" diff --git a/pubspec.yaml b/pubspec.yaml index ca5712a3..886bb6b4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,24 +1,26 @@ name: macos_ui description: Flutter widgets and themes implementing the current macOS design language. -version: 2.1.0 +version: 2.2.2 homepage: "https://macosui.dev" repository: "https://github.com/GroovinChip/macos_ui" environment: - sdk: ">=3.5.3 <4.0.0" + sdk: ">=3.9.2 <4.0.0" + flutter: ">=3.35.0" dependencies: flutter: sdk: flutter - macos_window_utils: ^1.5.0 - gradient_borders: ^1.0.1 - appkit_ui_element_colors: ^1.0.0 - equatable: ^2.0.5 + macos_window_utils: ^1.9.0 + gradient_borders: ^1.0.2 + appkit_ui_element_colors: ^1.0.1 + equatable: ^2.0.7 + vector_math: ^2.2.0 dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^4.0.0 + flutter_lints: ^6.0.0 mocktail: ^1.0.4 flutter: diff --git a/test/buttons/back_button_test.dart b/test/buttons/back_button_test.dart index cd709ee1..9ff6c181 100644 --- a/test/buttons/back_button_test.dart +++ b/test/buttons/back_button_test.dart @@ -18,15 +18,9 @@ void main() { await tester.pumpWidget( MacosApp( - navigatorObservers: [ - navigatorObserver, - ], + navigatorObservers: [navigatorObserver], home: const MacosWindow( - child: MacosScaffold( - toolBar: ToolBar( - leading: MacosBackButton(), - ), - ), + child: MacosScaffold(toolBar: ToolBar(leading: MacosBackButton())), ), ), ); @@ -80,14 +74,11 @@ void main() { .map((node) => node.toString()) .toList(); - expect( - description, - [ - 'fillColor: null', - 'hoverColor: null', - 'semanticLabel: null', - 'disabled', - ], - ); + expect(description, [ + 'fillColor: null', + 'hoverColor: null', + 'semanticLabel: null', + 'disabled', + ]); }); } diff --git a/test/buttons/checkbox_test.dart b/test/buttons/checkbox_test.dart index 7ba24553..cb7ca980 100644 --- a/test/buttons/checkbox_test.dart +++ b/test/buttons/checkbox_test.dart @@ -57,17 +57,14 @@ void main() { .map((node) => node.toString()) .toList(); - expect( - description, - [ - 'state: "unchecked"', - 'enabled', - 'size: 14.0', - 'activeColor: null', - 'disabledColor: quaternaryLabel(*color = Color(0x2d3c3c43)*, darkColor = Color(0x28ebebf5), highContrastColor = Color(0x423c3c43), darkHighContrastColor = Color(0x3debebf5), resolved by: UNRESOLVED)', - 'offBorderColor: tertiaryLabel(*color = Color(0x4c3c3c43)*, darkColor = Color(0x4cebebf5), highContrastColor = Color(0x603c3c43), darkHighContrastColor = Color(0x60ebebf5), resolved by: UNRESOLVED)', - 'semanticLabel: null', - ], - ); + expect(description, [ + 'state: "unchecked"', + 'enabled', + 'size: 14.0', + 'activeColor: null', + 'disabledColor: quaternaryLabel(*color = Color(alpha: 0.1765, red: 0.2353, green: 0.2353, blue: 0.2627, colorSpace: ColorSpace.sRGB)*, darkColor = Color(alpha: 0.1569, red: 0.9216, green: 0.9216, blue: 0.9608, colorSpace: ColorSpace.sRGB), highContrastColor = Color(alpha: 0.2588, red: 0.2353, green: 0.2353, blue: 0.2627, colorSpace: ColorSpace.sRGB), darkHighContrastColor = Color(alpha: 0.2392, red: 0.9216, green: 0.9216, blue: 0.9608, colorSpace: ColorSpace.sRGB), resolved by: UNRESOLVED)', + 'offBorderColor: tertiaryLabel(*color = Color(alpha: 0.2980, red: 0.2353, green: 0.2353, blue: 0.2627, colorSpace: ColorSpace.sRGB)*, darkColor = Color(alpha: 0.2980, red: 0.9216, green: 0.9216, blue: 0.9608, colorSpace: ColorSpace.sRGB), highContrastColor = Color(alpha: 0.3765, red: 0.2353, green: 0.2353, blue: 0.2627, colorSpace: ColorSpace.sRGB), darkHighContrastColor = Color(alpha: 0.3765, red: 0.9216, green: 0.9216, blue: 0.9608, colorSpace: ColorSpace.sRGB), resolved by: UNRESOLVED)', + 'semanticLabel: null', + ]); }); } diff --git a/test/buttons/disclosure_button_test.dart b/test/buttons/disclosure_button_test.dart index b00087a3..23d2e148 100644 --- a/test/buttons/disclosure_button_test.dart +++ b/test/buttons/disclosure_button_test.dart @@ -46,14 +46,11 @@ void main() { .map((node) => node.toString()) .toList(); - expect( - description, - [ - 'fillColor: null', - 'hoverColor: null', - 'semanticLabel: null', - 'disabled', - ], - ); + expect(description, [ + 'fillColor: null', + 'hoverColor: null', + 'semanticLabel: null', + 'disabled', + ]); }); } diff --git a/test/buttons/help_button_test.dart b/test/buttons/help_button_test.dart index a18b7cf9..b03fc32d 100644 --- a/test/buttons/help_button_test.dart +++ b/test/buttons/help_button_test.dart @@ -25,9 +25,7 @@ void main() { children: [ ContentArea( builder: (context, _) { - return HelpButton( - onPressed: mockOnPressedFunction.handler, - ); + return HelpButton(onPressed: mockOnPressedFunction.handler); }, ), ], @@ -85,16 +83,13 @@ void main() { .map((node) => node.toString()) .toList(); - expect( - description, - [ - 'color: null', - 'disabledColor: null', - 'pressedOpacity: 0.4', - 'alignment: Alignment.center', - 'semanticLabel: null', - ], - ); + expect(description, [ + 'color: null', + 'disabledColor: null', + 'pressedOpacity: 0.4', + 'alignment: Alignment.center', + 'semanticLabel: null', + ]); }); }); } diff --git a/test/buttons/icon_button_test.dart b/test/buttons/icon_button_test.dart index 8e52e106..d819afbd 100644 --- a/test/buttons/icon_button_test.dart +++ b/test/buttons/icon_button_test.dart @@ -81,17 +81,14 @@ void main() { .map((node) => node.toString()) .toList(); - expect( - description, - [ - 'backgroundColor: null', - 'disabledColor: null', - 'hoverColor: null', - 'pressedOpacity: 0.4', - 'alignment: Alignment.center', - 'padding: null', - 'semanticLabel: null', - ], - ); + expect(description, [ + 'backgroundColor: null', + 'disabledColor: null', + 'hoverColor: null', + 'pressedOpacity: 0.4', + 'alignment: Alignment.center', + 'padding: null', + 'semanticLabel: null', + ]); }); } diff --git a/test/buttons/popup_button_test.dart b/test/buttons/popup_button_test.dart index 704501ef..d2e682ff 100644 --- a/test/buttons/popup_button_test.dart +++ b/test/buttons/popup_button_test.dart @@ -7,136 +7,125 @@ const List menuItems = ['one', 'two', 'three', 'four']; void main() { group('MacosPopupButton tests', () { - testWidgets( - 'Can tap the MacosPopupButton and select a menu item', - (tester) async { - String? value = 'two'; - await tester.pumpWidget( - MacosApp( - home: MacosWindow( - child: MacosScaffold( - children: [ - ContentArea( - builder: (context, _) { - return StatefulBuilder( - builder: (context, setState) { - return MacosPopupButton( - value: value, - onChanged: (String? newValue) { - setState(() { - value = newValue!; - }); - }, - items: menuItems.map>( - (String value) { - return MacosPopupMenuItem( - value: value, - child: Text(value), - ); - }, - ).toList(), - ); - }, - ); - }, - ), - ], - ), + testWidgets('Can tap the MacosPopupButton and select a menu item', ( + tester, + ) async { + String? value = 'two'; + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + children: [ + ContentArea( + builder: (context, _) { + return StatefulBuilder( + builder: (context, setState) { + return MacosPopupButton( + value: value, + onChanged: (String? newValue) { + setState(() { + value = newValue!; + }); + }, + items: menuItems.map>(( + String value, + ) { + return MacosPopupMenuItem( + value: value, + child: Text(value), + ); + }).toList(), + ); + }, + ); + }, + ), + ], ), ), - ); + ), + ); - await tester.tap(find.text("two").first); - await tester.pumpAndSettle(); - await tester.tap(find.text('one').last); - await tester.pumpAndSettle(); - expect(value, equals('one')); + await tester.tap(find.text("two").first); + await tester.pumpAndSettle(); + await tester.tap(find.text('one').last); + await tester.pumpAndSettle(); + expect(value, equals('one')); - await tester.tap(find.text('one').first); - await tester.pumpAndSettle(); - await tester.tap(find.text('three').last); - await tester.pumpAndSettle(); - expect(value, equals('three')); - }, - ); + await tester.tap(find.text('one').first); + await tester.pumpAndSettle(); + await tester.tap(find.text('three').last); + await tester.pumpAndSettle(); + expect(value, equals('three')); + }); - testWidgets( - 'MacosPopupButton does not allow duplicate item values', - (WidgetTester tester) async { - final List> itemsWithDuplicateValues = - [ - 'a', - 'b', - 'c', - 'c', - ].map>((String value) { - return MacosPopupMenuItem( - value: value, - child: Text(value), - ); - }).toList(); + testWidgets('MacosPopupButton does not allow duplicate item values', ( + WidgetTester tester, + ) async { + final List> itemsWithDuplicateValues = + ['a', 'b', 'c', 'c'].map>(( + String value, + ) { + return MacosPopupMenuItem(value: value, child: Text(value)); + }).toList(); - await expectLater( - () => tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: MacosPopupButton( - value: 'c', - onChanged: (String? newValue) {}, - items: itemsWithDuplicateValues, - ), + await expectLater( + () => tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: MacosPopupButton( + value: 'c', + onChanged: (String? newValue) {}, + items: itemsWithDuplicateValues, ), ), ), - throwsA(isAssertionError.having( + ), + throwsA( + isAssertionError.having( (AssertionError error) => error.toString(), '.toString()', contains( "There should be exactly one item with [MacosPopupButton]'s value", ), - )), - ); - }, - ); + ), + ), + ); + }); - testWidgets( - 'MacosPopupButton value should only appear in one menu item', - (WidgetTester tester) async { - final List> itemsWithDuplicateValues = - [ - 'a', - 'b', - 'c', - 'd', - ].map>((String value) { - return MacosPopupMenuItem( - value: value, - child: Text(value), - ); - }).toList(); + testWidgets('MacosPopupButton value should only appear in one menu item', ( + WidgetTester tester, + ) async { + final List> itemsWithDuplicateValues = + ['a', 'b', 'c', 'd'].map>(( + String value, + ) { + return MacosPopupMenuItem(value: value, child: Text(value)); + }).toList(); - await expectLater( - () => tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: MacosPopupButton( - value: 'e', - onChanged: (String? newValue) {}, - items: itemsWithDuplicateValues, - ), + await expectLater( + () => tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: MacosPopupButton( + value: 'e', + onChanged: (String? newValue) {}, + items: itemsWithDuplicateValues, ), ), ), - throwsA(isAssertionError.having( + ), + throwsA( + isAssertionError.having( (AssertionError error) => error.toString(), '.toString()', contains( "There should be exactly one item with [MacosPopupButton]'s value", ), - )), - ); - }, - ); + ), + ), + ); + }); testWidgets('debugFillProperties', (tester) async { final builder = DiagnosticPropertiesBuilder(); @@ -147,10 +136,7 @@ void main() { value = newValue!; }, items: menuItems.map>((String value) { - return MacosPopupMenuItem( - value: value, - child: Text(value), - ); + return MacosPopupMenuItem(value: value, child: Text(value)); }).toList(), ).debugFillProperties(builder); @@ -160,16 +146,13 @@ void main() { .toList(); // ignore: avoid_print print(description); - expect( - description, - [ - 'itemHeight: 24.0', - 'noAutofocus', - 'popupColor: null', - 'menuMaxHeight: null', - 'alignment: AlignmentDirectional.centerStart', - ], - ); + expect(description, [ + 'itemHeight: 24.0', + 'noAutofocus', + 'popupColor: null', + 'menuMaxHeight: null', + 'alignment: AlignmentDirectional.centerStart', + ]); }); }); } diff --git a/test/buttons/pulldown_button_test.dart b/test/buttons/pulldown_button_test.dart index 668914d0..c61d5388 100644 --- a/test/buttons/pulldown_button_test.dart +++ b/test/buttons/pulldown_button_test.dart @@ -1,3 +1,5 @@ +// ignore_for_file: prefer-trailing-comma + import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -13,11 +15,51 @@ void main() { }); group('MacosPulldownButton tests', () { - testWidgets( - 'Can tap the MacosPulldownButton and select a menu item', - (tester) async { - await tester.pumpWidget( - MacosApp( + testWidgets('Can tap the MacosPulldownButton and select a menu item', ( + tester, + ) async { + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + children: [ + ContentArea( + builder: (context, _) { + return Center( + child: MacosPulldownButton( + title: "test", + items: [ + MacosPulldownMenuItem( + title: const Text('one'), + onTap: mockOnPressedFunction.handler, + ), + const MacosPulldownMenuItem( + title: Text('two'), + onTap: null, + ), + ], + ), + ); + }, + ), + ], + ), + ), + ), + ); + + final pulldownButton = find.byType(MacosPulldownButton); + await tester.tap(pulldownButton); + await tester.pumpAndSettle(); + await tester.tap(find.text("one")); + await tester.pumpAndSettle(); + + expect(mockOnPressedFunction.called, 2); + }); + + testWidgets('MacosPulldownButton displays correctly items ', + (WidgetTester tester) async { + await tester.pumpWidget(MacosApp( home: MacosWindow( child: MacosScaffold( children: [ @@ -25,15 +67,15 @@ void main() { builder: (context, _) { return Center( child: MacosPulldownButton( - title: "test", + title: "Menu", items: [ MacosPulldownMenuItem( - title: const Text('one'), - onTap: mockOnPressedFunction.handler, + title: const Text('New folder'), + onTap: () {}, ), - const MacosPulldownMenuItem( - title: Text('two'), - onTap: null, + MacosPulldownMenuItem( + title: const Text('Document'), + onTap: () {}, ), ], ), @@ -43,18 +85,19 @@ void main() { ], ), ), - ), - ); + )); - final pulldownButton = find.byType(MacosPulldownButton); - await tester.tap(pulldownButton); - await tester.pumpAndSettle(); - await tester.tap(find.text("one")); - await tester.pumpAndSettle(); + // Verify that the title is rendered on the button. + expect(find.text('Menu'), findsOneWidget); - expect(mockOnPressedFunction.called, 2); - }, - ); + // tap on the button to open the pulldown menu. + await tester.tap(find.text('Menu')); + await tester.pumpAndSettle(); + + // Verify that the menu items are displayed. + expect(find.text('New folder'), findsOneWidget); + expect(find.text('Document'), findsOneWidget); + }); testWidgets( 'MacosPulldownButtonItems\' onTap callback is called when defined', @@ -84,9 +127,7 @@ void main() { menuItemTapCounters[1] += 1; }, ), - const MacosPulldownMenuItem( - title: Text('no tap'), - ), + const MacosPulldownMenuItem(title: Text('no tap')), ], ), ); @@ -131,30 +172,22 @@ void main() { test( "MacosPulldownButton's label and icon properties cannot be simultaneously defined", () { - expect( - () { - MacosPulldownButton( - icon: CupertinoIcons.eyedropper, - title: "test label", - items: const [], - ); - }, - throwsAssertionError, - ); + expect(() { + MacosPulldownButton( + icon: CupertinoIcons.eyedropper, + title: "test label", + items: const [], + ); + }, throwsAssertionError); }, ); test( "MacosPulldownButton's label and icon properties cannot be simultaneously missing", () { - expect( - () { - MacosPulldownButton( - items: const [], - ); - }, - throwsAssertionError, - ); + expect(() { + MacosPulldownButton(items: const []); + }, throwsAssertionError); }, ); @@ -170,15 +203,68 @@ void main() { .map((node) => node.toString()) .toList(); - expect( - description, - [ - 'itemHeight: 20.0', - 'noAutofocus', - 'alignment: AlignmentDirectional.centerStart', - 'menuAlignment: PulldownMenuAlignment.left', - ], + expect(description, [ + 'itemHeight: 20.0', + 'noAutofocus', + 'alignment: AlignmentDirectional.centerStart', + 'menuAlignment: PulldownMenuAlignment.left', + ]); + }); + + testWidgets('MacosPulldownMenuItem.onTap shows alert dialog', ( + WidgetTester tester, + ) async { + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + children: [ + ContentArea( + builder: (context, _) { + return Center( + child: MacosPulldownButton( + title: "test", + items: [ + MacosPulldownMenuItem( + title: const Text('Open Alert Dialog'), + onTap: () => showMacosAlertDialog( + context: context, + builder: (context) => MacosAlertDialog( + appIcon: const MacosIcon( + CupertinoIcons.eyedropper, + ), + title: const Text('Title'), + message: const Text('Message'), + primaryButton: PushButton( + controlSize: ControlSize.large, + onPressed: Navigator.of(context).pop, + child: const Text('Close'), + ), + ), + ), + ), + ], + ), + ); + }, + ), + ], + ), + ), + ), ); + + // Tap the pulldown button. + await tester.tap(find.text('test')); + await tester.pumpAndSettle(); + // Tap the menu item to show the alert dialog. + await tester.tap(find.text('Open Alert Dialog')); + await tester.pumpAndSettle(); + + expect(find.text('Open Alert Dialog'), findsNothing); + expect(find.text('Title'), findsOneWidget); + expect(find.text('Message'), findsOneWidget); + expect(find.text('Close'), findsOneWidget); }); }); } diff --git a/test/buttons/push_button_test.dart b/test/buttons/push_button_test.dart index 981c21df..5e08c9d0 100644 --- a/test/buttons/push_button_test.dart +++ b/test/buttons/push_button_test.dart @@ -93,19 +93,16 @@ void main() { .map((node) => node.toString()) .toList(); - expect( - description, - [ - 'controlSize: regular', - 'color: null', - 'disabledColor: null', - 'alignment: Alignment.center', - 'semanticLabel: null', - 'borderRadius: BorderRadius.circular(4.0)', - 'disabled', - 'secondary: null', - ], - ); + expect(description, [ + 'controlSize: regular', + 'color: null', + 'disabledColor: null', + 'alignment: Alignment.center', + 'semanticLabel: null', + 'borderRadius: BorderRadius.circular(4.0)', + 'disabled', + 'secondary: null', + ]); }); }); } diff --git a/test/buttons/radio_button_test.dart b/test/buttons/radio_button_test.dart index 7d878d1c..b1518122 100644 --- a/test/buttons/radio_button_test.dart +++ b/test/buttons/radio_button_test.dart @@ -3,11 +3,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:macos_ui/macos_ui.dart'; import 'package:macos_ui/src/library.dart'; -enum TestOptions { - first, - second, - third, -} +enum TestOptions { first, second, third } Type typeOf() => T; @@ -93,16 +89,13 @@ void main() { .map((node) => node.toString()) .toList(); - expect( - description, - [ - 'enabled', - 'size: 16.0', - 'onColor: null', - 'offColor: tertiaryLabel(*color = Color(0x4c3c3c43)*, darkColor = Color(0x4cebebf5), highContrastColor = Color(0x603c3c43), darkHighContrastColor = Color(0x60ebebf5), resolved by: UNRESOLVED)', - 'innerColor: null', - 'semanticLabel: null', - ], - ); + expect(description, [ + 'enabled', + 'size: 16.0', + 'onColor: null', + 'offColor: tertiaryLabel(*color = Color(alpha: 0.2980, red: 0.2353, green: 0.2353, blue: 0.2627, colorSpace: ColorSpace.sRGB)*, darkColor = Color(alpha: 0.2980, red: 0.9216, green: 0.9216, blue: 0.9608, colorSpace: ColorSpace.sRGB), highContrastColor = Color(alpha: 0.3765, red: 0.2353, green: 0.2353, blue: 0.2627, colorSpace: ColorSpace.sRGB), darkHighContrastColor = Color(alpha: 0.3765, red: 0.9216, green: 0.9216, blue: 0.9608, colorSpace: ColorSpace.sRGB), resolved by: UNRESOLVED)', + 'innerColor: null', + 'semanticLabel: null', + ]); }); } diff --git a/test/buttons/segmented_control_test.dart b/test/buttons/segmented_control_test.dart index 62d19796..d956a1a1 100644 --- a/test/buttons/segmented_control_test.dart +++ b/test/buttons/segmented_control_test.dart @@ -19,15 +19,9 @@ void main() { child: MacosSegmentedControl( controller: controller, tabs: const [ - MacosTab( - label: 'Tab 1', - ), - MacosTab( - label: 'Tab 2', - ), - MacosTab( - label: 'Tab 3', - ), + MacosTab(label: 'Tab 1'), + MacosTab(label: 'Tab 2'), + MacosTab(label: 'Tab 3'), ], ), ); @@ -49,49 +43,42 @@ void main() { }, ); - testWidgets( - 'Tapping the currently selected item does nothing', - (tester) async { - final controller = MacosTabController(length: 3, initialIndex: 0); - await tester.pumpWidget( - MacosApp( - home: MacosWindow( - child: MacosScaffold( - children: [ - ContentArea( - builder: (context, _) { - return Center( - child: MacosSegmentedControl( - controller: controller, - tabs: const [ - MacosTab( - label: 'Tab 1', - ), - MacosTab( - label: 'Tab 2', - ), - MacosTab( - label: 'Tab 3', - ), - ], - ), - ); - }, - ), - ], - ), + testWidgets('Tapping the currently selected item does nothing', ( + tester, + ) async { + final controller = MacosTabController(length: 3, initialIndex: 0); + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + children: [ + ContentArea( + builder: (context, _) { + return Center( + child: MacosSegmentedControl( + controller: controller, + tabs: const [ + MacosTab(label: 'Tab 1'), + MacosTab(label: 'Tab 2'), + MacosTab(label: 'Tab 3'), + ], + ), + ); + }, + ), + ], ), ), - ); + ), + ); - final macosSegmentedControl = find.byType(MacosSegmentedControl); - expect(macosSegmentedControl, findsOneWidget); - final firstTab = find.byType(MacosTab).first; - expect(firstTab, findsOneWidget); - await tester.tap(firstTab); - await tester.pumpAndSettle(); - expect(controller.index, 0); - }, - ); + final macosSegmentedControl = find.byType(MacosSegmentedControl); + expect(macosSegmentedControl, findsOneWidget); + final firstTab = find.byType(MacosTab).first; + expect(firstTab, findsOneWidget); + await tester.tap(firstTab); + await tester.pumpAndSettle(); + expect(controller.index, 0); + }); }); } diff --git a/test/buttons/switch_test.dart b/test/buttons/switch_test.dart index a02bc40b..5433d2d1 100644 --- a/test/buttons/switch_test.dart +++ b/test/buttons/switch_test.dart @@ -48,18 +48,15 @@ void main() { .map((node) => node.toString()) .toList(); - expect( - description, - [ - 'unchecked', - 'size: regular', - 'dragStartBehavior: start', - 'disabled', - 'activeColor: null', - 'trackColor: null', - 'knobColor: null', - 'semanticLabel: null', - ], - ); + expect(description, [ + 'unchecked', + 'size: regular', + 'dragStartBehavior: start', + 'disabled', + 'activeColor: null', + 'trackColor: null', + 'knobColor: null', + 'semanticLabel: null', + ]); }); } diff --git a/test/buttons/toolbar_icon_button_test.dart b/test/buttons/toolbar_icon_button_test.dart new file mode 100644 index 00000000..bab17458 --- /dev/null +++ b/test/buttons/toolbar_icon_button_test.dart @@ -0,0 +1,259 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:macos_ui/macos_ui.dart'; +import 'package:macos_window_utils/widgets/macos_toolbar_passthrough.dart'; + +import '../mocks.dart'; + +void main() { + late MockOnPressedFunction mockOnPressedFunction; + + setUp(() { + mockOnPressedFunction = MockOnPressedFunction(); + }); + + group('ToolBarIconButton tests', () { + testWidgets( + 'ToolBarIconButton is wrapped with MacosToolbarPassthrough when in toolbar', + (tester) async { + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + toolBar: ToolBar( + title: const Text('Test'), + actions: [ + ToolBarIconButton( + label: 'Add', + icon: const MacosIcon(CupertinoIcons.add), + showLabel: false, + onPressed: mockOnPressedFunction.handler, + ), + ], + ), + children: [ + ContentArea( + builder: (context, _) { + return const Center(child: Text('Content')); + }, + ), + ], + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + // Verify that MacosToolbarPassthrough is present in the widget tree + expect(find.byType(MacosToolbarPassthrough), findsWidgets); + + // Verify that the button itself is still present + expect(find.byType(MacosIconButton), findsWidgets); + }, + ); + + testWidgets( + 'ToolBarIconButton with label is wrapped with MacosToolbarPassthrough', + (tester) async { + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + toolBar: ToolBar( + title: const Text('Test'), + actions: [ + ToolBarIconButton( + label: 'Add', + icon: const MacosIcon(CupertinoIcons.add), + showLabel: true, + onPressed: mockOnPressedFunction.handler, + ), + ], + ), + children: [ + ContentArea( + builder: (context, _) { + return const Center(child: Text('Content')); + }, + ), + ], + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + // Verify that MacosToolbarPassthrough is present + expect(find.byType(MacosToolbarPassthrough), findsWidgets); + + // Verify the label is displayed + expect(find.text('Add'), findsOneWidget); + }, + ); + + testWidgets( + 'ToolBarIconButton with tooltip is wrapped with MacosToolbarPassthrough', + (tester) async { + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + toolBar: ToolBar( + title: const Text('Test'), + actions: [ + ToolBarIconButton( + label: 'Add', + icon: const MacosIcon(CupertinoIcons.add), + showLabel: false, + tooltipMessage: 'Add item', + onPressed: mockOnPressedFunction.handler, + ), + ], + ), + children: [ + ContentArea( + builder: (context, _) { + return const Center(child: Text('Content')); + }, + ), + ], + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + // Verify that MacosToolbarPassthrough is present + expect(find.byType(MacosToolbarPassthrough), findsWidgets); + + // Verify tooltip is present + expect(find.byType(MacosTooltip), findsOneWidget); + }, + ); + + testWidgets( + 'ToolBarIconButton still functions when wrapped with MacosToolbarPassthrough', + (tester) async { + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + toolBar: ToolBar( + title: const Text('Test'), + actions: [ + ToolBarIconButton( + label: 'Add', + icon: const MacosIcon(CupertinoIcons.add), + showLabel: false, + onPressed: mockOnPressedFunction.handler, + ), + ], + ), + children: [ + ContentArea( + builder: (context, _) { + return const Center(child: Text('Content')); + }, + ), + ], + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + // Verify that MacosToolbarPassthrough is present + expect(find.byType(MacosToolbarPassthrough), findsWidgets); + + // Verify that the button is present and functional + expect(find.byType(MacosIconButton), findsWidgets); + }, + ); + + testWidgets( + 'Multiple ToolBarIconButtons each have their own MacosToolbarPassthrough', + (tester) async { + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + toolBar: ToolBar( + title: const Text('Test'), + actions: [ + ToolBarIconButton( + label: 'Add', + icon: const MacosIcon(CupertinoIcons.add), + showLabel: false, + onPressed: mockOnPressedFunction.handler, + ), + ToolBarIconButton( + label: 'Remove', + icon: const MacosIcon(CupertinoIcons.minus), + showLabel: false, + onPressed: mockOnPressedFunction.handler, + ), + ], + ), + children: [ + ContentArea( + builder: (context, _) { + return const Center(child: Text('Content')); + }, + ), + ], + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + // Each button should have its own MacosToolbarPassthrough wrapper + expect(find.byType(MacosToolbarPassthrough), findsWidgets); + expect(find.byType(MacosIconButton), findsWidgets); + }, + ); + + testWidgets( + 'Disabled ToolBarIconButton is still wrapped with MacosToolbarPassthrough', + (tester) async { + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + toolBar: const ToolBar( + title: Text('Test'), + actions: [ + ToolBarIconButton( + label: 'Add', + icon: MacosIcon(CupertinoIcons.add), + showLabel: false, + onPressed: null, + ), + ], + ), + children: [ + ContentArea( + builder: (context, _) { + return const Center(child: Text('Content')); + }, + ), + ], + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + // Disabled button should still be wrapped + expect(find.byType(MacosToolbarPassthrough), findsWidgets); + expect(find.byType(MacosIconButton), findsWidgets); + }, + ); + }); +} diff --git a/test/buttons/toolbar_pulldown_button_test.dart b/test/buttons/toolbar_pulldown_button_test.dart new file mode 100644 index 00000000..e4cf51e8 --- /dev/null +++ b/test/buttons/toolbar_pulldown_button_test.dart @@ -0,0 +1,303 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:macos_ui/macos_ui.dart'; +import 'package:macos_window_utils/widgets/macos_toolbar_passthrough.dart'; + +import '../mocks.dart'; + +void main() { + late MockOnPressedFunction mockOnPressedFunction; + + setUp(() { + mockOnPressedFunction = MockOnPressedFunction(); + }); + + group('ToolBarPullDownButton tests', () { + testWidgets( + 'ToolBarPullDownButton is wrapped with MacosToolbarPassthrough when in toolbar', + (tester) async { + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + toolBar: ToolBar( + title: const Text('Test'), + actions: [ + ToolBarPullDownButton( + label: 'Actions', + icon: CupertinoIcons.ellipsis_circle, + items: [ + MacosPulldownMenuItem( + label: 'Item 1', + title: const Text('Item 1'), + onTap: mockOnPressedFunction.handler, + ), + MacosPulldownMenuItem( + label: 'Item 2', + title: const Text('Item 2'), + onTap: mockOnPressedFunction.handler, + ), + ], + ), + ], + ), + children: [ + ContentArea( + builder: (context, _) { + return const Center(child: Text('Content')); + }, + ), + ], + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + // Verify that MacosToolbarPassthrough is present in the widget tree + expect(find.byType(MacosToolbarPassthrough), findsWidgets); + + // Verify that the pulldown button itself is still present + expect(find.byType(MacosPulldownButton), findsOneWidget); + }, + ); + + testWidgets( + 'ToolBarPullDownButton with tooltip is wrapped with MacosToolbarPassthrough', + (tester) async { + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + toolBar: ToolBar( + title: const Text('Test'), + actions: [ + ToolBarPullDownButton( + label: 'Actions', + icon: CupertinoIcons.ellipsis_circle, + tooltipMessage: 'More actions', + items: [ + MacosPulldownMenuItem( + label: 'Item 1', + title: const Text('Item 1'), + onTap: mockOnPressedFunction.handler, + ), + ], + ), + ], + ), + children: [ + ContentArea( + builder: (context, _) { + return const Center(child: Text('Content')); + }, + ), + ], + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + // Verify that MacosToolbarPassthrough is present + expect(find.byType(MacosToolbarPassthrough), findsWidgets); + + // Verify tooltip is present + expect(find.byType(MacosTooltip), findsOneWidget); + }, + ); + + testWidgets( + 'ToolBarPullDownButton still functions when wrapped with MacosToolbarPassthrough', + (tester) async { + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + toolBar: ToolBar( + title: const Text('Test'), + actions: [ + ToolBarPullDownButton( + label: 'Actions', + icon: CupertinoIcons.ellipsis_circle, + items: [ + MacosPulldownMenuItem( + label: 'Item 1', + title: const Text('Item 1'), + onTap: mockOnPressedFunction.handler, + ), + MacosPulldownMenuItem( + label: 'Item 2', + title: const Text('Item 2'), + onTap: mockOnPressedFunction.handler, + ), + ], + ), + ], + ), + children: [ + ContentArea( + builder: (context, _) { + return const Center(child: Text('Content')); + }, + ), + ], + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + // Verify that MacosToolbarPassthrough is present + expect(find.byType(MacosToolbarPassthrough), findsWidgets); + + // Verify that the pulldown button is present and functional + expect(find.byType(MacosPulldownButton), findsWidgets); + }, + ); + + testWidgets( + 'Disabled ToolBarPullDownButton is still wrapped with MacosToolbarPassthrough', + (tester) async { + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + toolBar: const ToolBar( + title: Text('Test'), + actions: [ + ToolBarPullDownButton( + label: 'Actions', + icon: CupertinoIcons.ellipsis_circle, + items: null, + ), + ], + ), + children: [ + ContentArea( + builder: (context, _) { + return const Center(child: Text('Content')); + }, + ), + ], + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + // Disabled pulldown button should still be wrapped + expect(find.byType(MacosToolbarPassthrough), findsWidgets); + expect(find.byType(MacosPulldownButton), findsOneWidget); + }, + ); + + testWidgets( + 'Multiple ToolBarPullDownButtons each have their own MacosToolbarPassthrough', + (tester) async { + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + toolBar: ToolBar( + title: const Text('Test'), + actions: [ + ToolBarPullDownButton( + label: 'Actions', + icon: CupertinoIcons.ellipsis_circle, + items: [ + MacosPulldownMenuItem( + label: 'Item 1', + title: const Text('Item 1'), + onTap: mockOnPressedFunction.handler, + ), + ], + ), + ToolBarPullDownButton( + label: 'More', + icon: CupertinoIcons.gear, + items: [ + MacosPulldownMenuItem( + label: 'Item 2', + title: const Text('Item 2'), + onTap: mockOnPressedFunction.handler, + ), + ], + ), + ], + ), + children: [ + ContentArea( + builder: (context, _) { + return const Center(child: Text('Content')); + }, + ), + ], + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + // Each pulldown button should have its own MacosToolbarPassthrough wrapper + expect(find.byType(MacosToolbarPassthrough), findsWidgets); + expect(find.byType(MacosPulldownButton), findsWidgets); + }, + ); + + testWidgets( + 'Mixed toolbar with icon and pulldown buttons have correct MacosToolbarPassthrough wrappers', + (tester) async { + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + toolBar: ToolBar( + title: const Text('Test'), + actions: [ + ToolBarIconButton( + label: 'Add', + icon: const MacosIcon(CupertinoIcons.add), + showLabel: false, + onPressed: mockOnPressedFunction.handler, + ), + ToolBarPullDownButton( + label: 'Actions', + icon: CupertinoIcons.ellipsis_circle, + items: [ + MacosPulldownMenuItem( + label: 'Item 1', + title: const Text('Item 1'), + onTap: mockOnPressedFunction.handler, + ), + ], + ), + ], + ), + children: [ + ContentArea( + builder: (context, _) { + return const Center(child: Text('Content')); + }, + ), + ], + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + // Both items should be wrapped with MacosToolbarPassthrough + expect(find.byType(MacosToolbarPassthrough), findsWidgets); + expect(find.byType(MacosIconButton), findsWidgets); + expect(find.byType(MacosPulldownButton), findsWidgets); + }, + ); + }); +} diff --git a/test/fields/search_field_test.dart b/test/fields/search_field_test.dart index 4fdbc863..f032cd29 100644 --- a/test/fields/search_field_test.dart +++ b/test/fields/search_field_test.dart @@ -3,77 +3,77 @@ import 'package:macos_ui/macos_ui.dart'; import 'package:macos_ui/src/library.dart'; void main() { - testWidgets( - 'Can input a search query and display suggestions accordingly', - (tester) async { - const List kOptions = [ - 'aardvark', - 'bobcat', - 'chameleon', - 'dingo', - 'elephant', - 'flamingo', - 'goose', - 'hippopotamus', - 'iguana', - 'jaguar', - 'koala', - 'lemur', - 'mouse', - 'northern white rhinoceros', - ]; - final controller = TextEditingController(); - await tester.pumpWidget( - MacosApp( - home: MacosWindow( - child: MacosScaffold( - children: [ - ContentArea( - builder: (context, _) { - return Center( - child: SizedBox( - width: 300.0, - height: 500.0, - child: MacosSearchField( - results: - kOptions.map((e) => SearchResultItem(e)).toList(), - controller: controller, - ), + testWidgets('Can input a search query and display suggestions accordingly', ( + tester, + ) async { + const List kOptions = [ + 'aardvark', + 'bobcat', + 'chameleon', + 'dingo', + 'elephant', + 'flamingo', + 'goose', + 'hippopotamus', + 'iguana', + 'jaguar', + 'koala', + 'lemur', + 'mouse', + 'northern white rhinoceros', + ]; + final controller = TextEditingController(); + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + children: [ + ContentArea( + builder: (context, _) { + return Center( + child: SizedBox( + width: 300.0, + height: 500.0, + child: MacosSearchField( + results: kOptions + .map((e) => SearchResultItem(e)) + .toList(), + controller: controller, ), - ); - }, - ), - ], - ), + ), + ); + }, + ), + ], ), ), - ); + ), + ); - // The field is always rendered, but the options are not unless needed. - expect(find.byType(MacosSearchField), findsOneWidget); - expect(find.byType(ListView), findsNothing); + // The field is always rendered, but the options are not unless needed. + expect(find.byType(MacosSearchField), findsOneWidget); + expect(find.byType(ListView), findsNothing); - // Focus the empty MacosTextField (contained within MacosSearchField). - await tester.tap(find.byType(MacosTextField)); - // Enter text. The options are filtered by the text. - await tester.enterText(find.byType(MacosTextField), 'ele'); - await tester.pump(); - expect(controller.text, 'ele'); - await tester.pumpAndSettle(); - expect(find.byType(MacosTextField), findsOneWidget); - expect(find.byType(ListView), findsOneWidget); - ListView list = find.byType(ListView).evaluate().first.widget as ListView; - // 'chameleon' and 'elephant' are displayed. - expect(list.semanticChildCount, 2); + // Focus the empty MacosTextField (contained within MacosSearchField). + await tester.tap(find.byType(MacosTextField)); + // Enter text. The options are filtered by the text. + await tester.enterText(find.byType(MacosTextField), 'ele'); + await tester.pump(); + expect(controller.text, 'ele'); + await tester.pumpAndSettle(); + expect(find.byType(MacosTextField), findsOneWidget); + expect(find.byType(ListView), findsOneWidget); + ListView list = find.byType(ListView).evaluate().first.widget as ListView; + // 'chameleon' and 'elephant' are displayed. + expect(list.semanticChildCount, 2); - await tester.ensureVisible(find.text('elephant')); - await tester.pump(); + await tester.ensureVisible(find.text('elephant')); + await tester.pump(); - await tester.tap(find.text('elephant')); - await tester.pump(); + await tester.tap(find.text('elephant')); + await tester.pump(); - expect(controller.text, 'elephant'); - expect(find.byType(ListView), findsNothing); - }, - ); + expect(controller.text, 'elephant'); + expect(find.byType(ListView), findsNothing); + }); } diff --git a/test/fields/text_field_test.dart b/test/fields/text_field_test.dart index 71b12568..25d034ef 100644 --- a/test/fields/text_field_test.dart +++ b/test/fields/text_field_test.dart @@ -13,11 +13,7 @@ void main() { children: [ ContentArea( builder: (context, _) { - return Center( - child: MacosTextField( - controller: controller, - ), - ); + return Center(child: MacosTextField(controller: controller)); }, ), ], diff --git a/test/indicators/capacity_indicators_test.dart b/test/indicators/capacity_indicators_test.dart index 1780a362..74c50cfc 100644 --- a/test/indicators/capacity_indicators_test.dart +++ b/test/indicators/capacity_indicators_test.dart @@ -5,33 +5,28 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:macos_ui/macos_ui.dart'; -// TODO(): Remove once mock_canvas in flutter_test reaches stable. +// TODO: Remove once mock_canvas in flutter_test reaches stable. import '../mock_canvas.dart'; void main() { testWidgets('debugFillProperties', (tester) async { final builder = DiagnosticPropertiesBuilder(); - const CapacityIndicator( - value: 50, - ).debugFillProperties(builder); + const CapacityIndicator(value: 50).debugFillProperties(builder); final description = builder.properties .where((node) => !node.isFiltered(DiagnosticLevel.info)) .map((node) => node.toString()) .toList(); - expect( - description, - [ - 'value: 50.0', - 'continuous', - 'splits: 10', - 'color: systemGreen(*color = Color(0xff34c759)*, darkColor = Color(0xff30d158), highContrastColor = Color(0xff248a3d), darkHighContrastColor = Color(0xff30db5b), resolved by: UNRESOLVED)', - 'backgroundColor: tertiarySystemGroupedBackground(*color = Color(0xfff2f2f7)*, darkColor = Color(0xff2c2c2e), highContrastColor = Color(0xffebebf0), darkHighContrastColor = Color(0xff363638), *elevatedColor = Color(0xfff2f2f7)*, darkElevatedColor = Color(0xff3a3a3c), highContrastElevatedColor = Color(0xffebebf0), darkHighContrastElevatedColor = Color(0xff444446), resolved by: UNRESOLVED)', - 'borderColor: tertiaryLabel(*color = Color(0x4c3c3c43)*, darkColor = Color(0x4cebebf5), highContrastColor = Color(0x603c3c43), darkHighContrastColor = Color(0x60ebebf5), resolved by: UNRESOLVED)', - 'semanticLabel: null', - ], - ); + expect(description, [ + 'value: 50.0', + 'continuous', + 'splits: 10', + 'color: systemGreen(*color = Color(alpha: 1.0000, red: 0.2039, green: 0.7804, blue: 0.3490, colorSpace: ColorSpace.sRGB)*, darkColor = Color(alpha: 1.0000, red: 0.1882, green: 0.8196, blue: 0.3451, colorSpace: ColorSpace.sRGB), highContrastColor = Color(alpha: 1.0000, red: 0.1412, green: 0.5412, blue: 0.2392, colorSpace: ColorSpace.sRGB), darkHighContrastColor = Color(alpha: 1.0000, red: 0.1882, green: 0.8588, blue: 0.3569, colorSpace: ColorSpace.sRGB), resolved by: UNRESOLVED)', + 'backgroundColor: tertiarySystemGroupedBackground(*color = Color(alpha: 1.0000, red: 0.9490, green: 0.9490, blue: 0.9686, colorSpace: ColorSpace.sRGB)*, darkColor = Color(alpha: 1.0000, red: 0.1725, green: 0.1725, blue: 0.1804, colorSpace: ColorSpace.sRGB), highContrastColor = Color(alpha: 1.0000, red: 0.9216, green: 0.9216, blue: 0.9412, colorSpace: ColorSpace.sRGB), darkHighContrastColor = Color(alpha: 1.0000, red: 0.2118, green: 0.2118, blue: 0.2196, colorSpace: ColorSpace.sRGB), *elevatedColor = Color(alpha: 1.0000, red: 0.9490, green: 0.9490, blue: 0.9686, colorSpace: ColorSpace.sRGB)*, darkElevatedColor = Color(alpha: 1.0000, red: 0.2275, green: 0.2275, blue: 0.2353, colorSpace: ColorSpace.sRGB), highContrastElevatedColor = Color(alpha: 1.0000, red: 0.9216, green: 0.9216, blue: 0.9412, colorSpace: ColorSpace.sRGB), darkHighContrastElevatedColor = Color(alpha: 1.0000, red: 0.2667, green: 0.2667, blue: 0.2745, colorSpace: ColorSpace.sRGB), resolved by: UNRESOLVED)', + 'borderColor: tertiaryLabel(*color = Color(alpha: 0.2980, red: 0.2353, green: 0.2353, blue: 0.2627, colorSpace: ColorSpace.sRGB)*, darkColor = Color(alpha: 0.2980, red: 0.9216, green: 0.9216, blue: 0.9608, colorSpace: ColorSpace.sRGB), highContrastColor = Color(alpha: 0.3765, red: 0.2353, green: 0.2353, blue: 0.2627, colorSpace: ColorSpace.sRGB), darkHighContrastColor = Color(alpha: 0.3765, red: 0.9216, green: 0.9216, blue: 0.9608, colorSpace: ColorSpace.sRGB), resolved by: UNRESOLVED)', + 'semanticLabel: null', + ]); }); testWidgets('debugFillProperties with discrete splits = 20', (tester) async { @@ -47,45 +42,37 @@ void main() { .map((node) => node.toString()) .toList(); - expect( - description, - [ - 'value: 50.0', - 'splits: 20', - 'color: systemGreen(*color = Color(0xff34c759)*, darkColor = Color(0xff30d158), highContrastColor = Color(0xff248a3d), darkHighContrastColor = Color(0xff30db5b), resolved by: UNRESOLVED)', - 'backgroundColor: tertiarySystemGroupedBackground(*color = Color(0xfff2f2f7)*, darkColor = Color(0xff2c2c2e), highContrastColor = Color(0xffebebf0), darkHighContrastColor = Color(0xff363638), *elevatedColor = Color(0xfff2f2f7)*, darkElevatedColor = Color(0xff3a3a3c), highContrastElevatedColor = Color(0xffebebf0), darkHighContrastElevatedColor = Color(0xff444446), resolved by: UNRESOLVED)', - 'borderColor: tertiaryLabel(*color = Color(0x4c3c3c43)*, darkColor = Color(0x4cebebf5), highContrastColor = Color(0x603c3c43), darkHighContrastColor = Color(0x60ebebf5), resolved by: UNRESOLVED)', - 'semanticLabel: null', - ], - ); + expect(description, [ + 'value: 50.0', + 'splits: 20', + 'color: systemGreen(*color = Color(alpha: 1.0000, red: 0.2039, green: 0.7804, blue: 0.3490, colorSpace: ColorSpace.sRGB)*, darkColor = Color(alpha: 1.0000, red: 0.1882, green: 0.8196, blue: 0.3451, colorSpace: ColorSpace.sRGB), highContrastColor = Color(alpha: 1.0000, red: 0.1412, green: 0.5412, blue: 0.2392, colorSpace: ColorSpace.sRGB), darkHighContrastColor = Color(alpha: 1.0000, red: 0.1882, green: 0.8588, blue: 0.3569, colorSpace: ColorSpace.sRGB), resolved by: UNRESOLVED)', + 'backgroundColor: tertiarySystemGroupedBackground(*color = Color(alpha: 1.0000, red: 0.9490, green: 0.9490, blue: 0.9686, colorSpace: ColorSpace.sRGB)*, darkColor = Color(alpha: 1.0000, red: 0.1725, green: 0.1725, blue: 0.1804, colorSpace: ColorSpace.sRGB), highContrastColor = Color(alpha: 1.0000, red: 0.9216, green: 0.9216, blue: 0.9412, colorSpace: ColorSpace.sRGB), darkHighContrastColor = Color(alpha: 1.0000, red: 0.2118, green: 0.2118, blue: 0.2196, colorSpace: ColorSpace.sRGB), *elevatedColor = Color(alpha: 1.0000, red: 0.9490, green: 0.9490, blue: 0.9686, colorSpace: ColorSpace.sRGB)*, darkElevatedColor = Color(alpha: 1.0000, red: 0.2275, green: 0.2275, blue: 0.2353, colorSpace: ColorSpace.sRGB), highContrastElevatedColor = Color(alpha: 1.0000, red: 0.9216, green: 0.9216, blue: 0.9412, colorSpace: ColorSpace.sRGB), darkHighContrastElevatedColor = Color(alpha: 1.0000, red: 0.2667, green: 0.2667, blue: 0.2745, colorSpace: ColorSpace.sRGB), resolved by: UNRESOLVED)', + 'borderColor: tertiaryLabel(*color = Color(alpha: 0.2980, red: 0.2353, green: 0.2353, blue: 0.2627, colorSpace: ColorSpace.sRGB)*, darkColor = Color(alpha: 0.2980, red: 0.9216, green: 0.9216, blue: 0.9608, colorSpace: ColorSpace.sRGB), highContrastColor = Color(alpha: 0.3765, red: 0.2353, green: 0.2353, blue: 0.2627, colorSpace: ColorSpace.sRGB), darkHighContrastColor = Color(alpha: 0.3765, red: 0.9216, green: 0.9216, blue: 0.9608, colorSpace: ColorSpace.sRGB), resolved by: UNRESOLVED)', + 'semanticLabel: null', + ]); }); - testWidgets( - 'CapacityIndicator paints the correct number of segments', - (WidgetTester tester) async { - await tester.pumpWidget( - const Directionality( - textDirection: TextDirection.ltr, - child: Center( - child: SizedBox( - width: 200.0, - child: CapacityIndicator( - value: 50, - splits: 20, - discrete: true, - ), - ), + testWidgets('CapacityIndicator paints the correct number of segments', ( + WidgetTester tester, + ) async { + await tester.pumpWidget( + const Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: SizedBox( + width: 200.0, + child: CapacityIndicator(value: 50, splits: 20, discrete: true), ), ), - ); + ), + ); - expect( - find.byType(CapacityIndicator), - // each discrete segment is drawn 3 times, two times with fill, last time with stroke - paintedExactlyCountTimes(#drawRRect, 20 * 3), - ); - }, - ); + expect( + find.byType(CapacityIndicator), + // each discrete segment is drawn 3 times, two times with fill, last time with stroke + paintedExactlyCountTimes(#drawRRect, 20 * 3), + ); + }); testWidgets( 'CapacityIndicator paints two filled segments for value=10 and 20 segments', @@ -96,11 +83,7 @@ void main() { child: Center( child: SizedBox( width: 200.0, - child: CapacityIndicator( - value: 10, - splits: 20, - discrete: true, - ), + child: CapacityIndicator(value: 10, splits: 20, discrete: true), ), ), ), diff --git a/test/indicators/progress_indicator_test.dart b/test/indicators/progress_indicator_test.dart index 739e4b46..adb9139c 100644 --- a/test/indicators/progress_indicator_test.dart +++ b/test/indicators/progress_indicator_test.dart @@ -5,47 +5,37 @@ import 'package:macos_ui/macos_ui.dart'; void main() { testWidgets('ProgressBar debugFillProperties', (tester) async { final builder = DiagnosticPropertiesBuilder(); - const ProgressBar( - value: 50, - ).debugFillProperties(builder); + const ProgressBar(value: 50).debugFillProperties(builder); final description = builder.properties .where((node) => !node.isFiltered(DiagnosticLevel.info)) .map((node) => node.toString()) .toList(); - expect( - description, - [ - 'value: 50.0', - 'height: 4.5', - 'trackColor: null', - 'backgroundColor: null', - 'semanticLabel: null', - ], - ); + expect(description, [ + 'value: 50.0', + 'height: 4.5', + 'trackColor: null', + 'backgroundColor: null', + 'semanticLabel: null', + ]); }); testWidgets('ProgressCircle debugFillProperties', (tester) async { final builder = DiagnosticPropertiesBuilder(); - const ProgressCircle( - value: 50, - ).debugFillProperties(builder); + const ProgressCircle(value: 50).debugFillProperties(builder); final description = builder.properties .where((node) => !node.isFiltered(DiagnosticLevel.info)) .map((node) => node.toString()) .toList(); - expect( - description, - [ - 'value: 50.0', - 'radius: 10.0', - 'innerColor: null', - 'borderColor: null', - 'semanticLabel: null', - ], - ); + expect(description, [ + 'value: 50.0', + 'radius: 10.0', + 'innerColor: null', + 'borderColor: null', + 'semanticLabel: null', + ]); }); } diff --git a/test/indicators/rating_indicator_test.dart b/test/indicators/rating_indicator_test.dart index a04b3d2d..561ca10b 100644 --- a/test/indicators/rating_indicator_test.dart +++ b/test/indicators/rating_indicator_test.dart @@ -5,27 +5,21 @@ import 'package:macos_ui/macos_ui.dart'; void main() { testWidgets('debugFillProperties', (tester) async { final builder = DiagnosticPropertiesBuilder(); - const RatingIndicator( - value: 50, - amount: 100, - ).debugFillProperties(builder); + const RatingIndicator(value: 50, amount: 100).debugFillProperties(builder); final description = builder.properties .where((node) => !node.isFiltered(DiagnosticLevel.info)) .map((node) => node.toString()) .toList(); - expect( - description, - [ - 'ratedIcon: IconData(U+0F822)', - 'unratedIcon: IconData(U+0F81F)', - 'iconColor: null', - 'iconSize: 16.0', - 'amount: 100', - 'value: 50.0', - 'semanticLabel: null', - ], - ); + expect(description, [ + 'ratedIcon: IconData(U+0F822)', + 'unratedIcon: IconData(U+0F81F)', + 'iconColor: null', + 'iconSize: 16.0', + 'amount: 100', + 'value: 50.0', + 'semanticLabel: null', + ]); }); } diff --git a/test/indicators/scrollbar_test.dart b/test/indicators/scrollbar_test.dart index 1173e096..28361c08 100644 --- a/test/indicators/scrollbar_test.dart +++ b/test/indicators/scrollbar_test.dart @@ -13,54 +13,54 @@ void main() { const double scaleFactor = 2; final ScrollController scrollController = ScrollController(); - testWidgets( - 'Scrollbar changes position when scrolled with the mouse wheel', - (tester) async { - final Size screenSize = - tester.view.physicalSize / tester.view.devicePixelRatio; + testWidgets('Scrollbar changes position when scrolled with the mouse wheel', ( + tester, + ) async { + final Size screenSize = + tester.view.physicalSize / tester.view.devicePixelRatio; - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: const MediaQueryData(), - child: PrimaryScrollController( - controller: scrollController, - child: MacosTheme( - data: MacosThemeData.light(), - child: MacosScrollbar( - thickness: thickness, - thicknessWhileHovering: thicknessWhenDragging, - child: SingleChildScrollView( - child: SizedBox( - width: screenSize.width * scaleFactor, - height: screenSize.height * scaleFactor, - ), + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: const MediaQueryData(), + child: PrimaryScrollController( + controller: scrollController, + child: MacosTheme( + data: MacosThemeData.light(), + child: MacosScrollbar( + thickness: thickness, + thicknessWhileHovering: thicknessWhenDragging, + child: SingleChildScrollView( + child: SizedBox( + width: screenSize.width * scaleFactor, + height: screenSize.height * scaleFactor, ), ), ), ), ), ), - ); + ), + ); - const Offset scrollAmount = Offset(0.0, 5.0); - const Offset reverseScrollAmount = Offset(0.0, -5.0); - Offset finalPosition = Offset.zero; - final Offset scrollEventLocation = - tester.getCenter(find.byType(SingleChildScrollView)); - final TestPointer testPointer = TestPointer(1, PointerDeviceKind.mouse); + const Offset scrollAmount = Offset(0.0, 5.0); + const Offset reverseScrollAmount = Offset(0.0, -5.0); + Offset finalPosition = Offset.zero; + final Offset scrollEventLocation = tester.getCenter( + find.byType(SingleChildScrollView), + ); + final TestPointer testPointer = TestPointer(1, PointerDeviceKind.mouse); - testPointer.hover(scrollEventLocation); + testPointer.hover(scrollEventLocation); - // Scroll down - await tester.sendEventToBinding(testPointer.scroll(scrollAmount)); - await tester.pumpAndSettle(); - expect(scrollController.offset, scrollAmount.dy); - // Scroll back up - await tester.sendEventToBinding(testPointer.scroll(reverseScrollAmount)); - await tester.pumpAndSettle(); - expect(scrollController.offset, finalPosition.dy); - }, - ); + // Scroll down + await tester.sendEventToBinding(testPointer.scroll(scrollAmount)); + await tester.pumpAndSettle(); + expect(scrollController.offset, scrollAmount.dy); + // Scroll back up + await tester.sendEventToBinding(testPointer.scroll(reverseScrollAmount)); + await tester.pumpAndSettle(); + expect(scrollController.offset, finalPosition.dy); + }); } diff --git a/test/indicators/slider_test.dart b/test/indicators/slider_test.dart index 99f963ff..0d0a866f 100644 --- a/test/indicators/slider_test.dart +++ b/test/indicators/slider_test.dart @@ -16,21 +16,18 @@ void main() { .map((node) => node.toString()) .toList(); - expect( - description, - [ - 'value: 0.5', - 'has onChanged', - 'min: 0.0', - 'max: 1.0', - 'color: systemBlue(*color = Color(0xff007aff)*, darkColor = Color(0xff0a84ff), highContrastColor = Color(0xff0040dd), darkHighContrastColor = Color(0xff409cff), resolved by: UNRESOLVED)', - 'backgroundColor: CupertinoDynamicColor(*color = Color(0x19000000)*, darkColor = Color(0x19ffffff), resolved by: UNRESOLVED)', - 'tickBackgroundColor: CupertinoDynamicColor(*color = Color(0xffdcdcdc)*, darkColor = Color(0xff464646), resolved by: UNRESOLVED)', - 'thumbColor: CupertinoDynamicColor(*color = Color(0xffffffff)*, darkColor = Color(0xff98989d), resolved by: UNRESOLVED)', - 'splits: 15', - 'semanticLabel: null', - ], - ); + expect(description, [ + 'value: 0.5', + 'has onChanged', + 'min: 0.0', + 'max: 1.0', + 'color: systemBlue(*color = Color(alpha: 1.0000, red: 0.0000, green: 0.4784, blue: 1.0000, colorSpace: ColorSpace.sRGB)*, darkColor = Color(alpha: 1.0000, red: 0.0392, green: 0.5176, blue: 1.0000, colorSpace: ColorSpace.sRGB), highContrastColor = Color(alpha: 1.0000, red: 0.0000, green: 0.2510, blue: 0.8667, colorSpace: ColorSpace.sRGB), darkHighContrastColor = Color(alpha: 1.0000, red: 0.2510, green: 0.6118, blue: 1.0000, colorSpace: ColorSpace.sRGB), resolved by: UNRESOLVED)', + 'backgroundColor: CupertinoDynamicColor(*color = Color(alpha: 0.1000, red: 0.0000, green: 0.0000, blue: 0.0000, colorSpace: ColorSpace.sRGB)*, darkColor = Color(alpha: 0.1000, red: 1.0000, green: 1.0000, blue: 1.0000, colorSpace: ColorSpace.sRGB), resolved by: UNRESOLVED)', + 'tickBackgroundColor: CupertinoDynamicColor(*color = Color(alpha: 1.0000, red: 0.8627, green: 0.8627, blue: 0.8627, colorSpace: ColorSpace.sRGB)*, darkColor = Color(alpha: 1.0000, red: 0.2745, green: 0.2745, blue: 0.2745, colorSpace: ColorSpace.sRGB), resolved by: UNRESOLVED)', + 'thumbColor: CupertinoDynamicColor(*color = Color(alpha: 1.0000, red: 1.0000, green: 1.0000, blue: 1.0000, colorSpace: ColorSpace.sRGB)*, darkColor = Color(alpha: 1.0000, red: 0.5961, green: 0.5961, blue: 0.6157, colorSpace: ColorSpace.sRGB), resolved by: UNRESOLVED)', + 'splits: 15', + 'semanticLabel: null', + ]); }); testWidgets('Continuous slider can move when tapped', (tester) async { diff --git a/test/labels/tooltip_test.dart b/test/labels/tooltip_test.dart index db226e69..a3ae4455 100644 --- a/test/labels/tooltip_test.dart +++ b/test/labels/tooltip_test.dart @@ -52,10 +52,7 @@ void main() { child: MacosTooltip( key: key, message: tooltipText, - child: const SizedBox( - width: 0, - height: 0, - ), + child: const SizedBox(width: 0, height: 0), ), ), ], @@ -69,9 +66,9 @@ void main() { ); _ensureTooltipVisible(key); - await tester.pump(const Duration( - seconds: 2, - )); // faded in, show timer started (and at 0.0) + await tester.pump( + const Duration(seconds: 2), + ); // faded in, show timer started (and at 0.0) final RenderBox tip = tester.renderObject( _findTooltipContainer(tooltipText), diff --git a/test/layout/custom_toolbar_item_test.dart b/test/layout/custom_toolbar_item_test.dart new file mode 100644 index 00000000..5c8bd1b1 --- /dev/null +++ b/test/layout/custom_toolbar_item_test.dart @@ -0,0 +1,291 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:macos_ui/macos_ui.dart'; +import 'package:macos_window_utils/widgets/macos_toolbar_passthrough.dart'; + +import '../mocks.dart'; + +void main() { + late MockOnPressedFunction mockOnPressedFunction; + + setUp(() { + mockOnPressedFunction = MockOnPressedFunction(); + }); + + group('CustomToolbarItem tests', () { + testWidgets( + 'CustomToolbarItem is wrapped with MacosToolbarPassthrough when in toolbar', + (tester) async { + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + toolBar: ToolBar( + title: const Text('Test'), + actions: [ + CustomToolbarItem( + inToolbarBuilder: (context) => Container( + width: 100, + height: 30, + color: CupertinoColors.systemBlue, + child: const Center(child: Text('Custom Widget')), + ), + ), + ], + ), + children: [ + ContentArea( + builder: (context, _) { + return const Center(child: Text('Content')); + }, + ), + ], + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + // Verify that MacosToolbarPassthrough is present in the widget tree + expect(find.byType(MacosToolbarPassthrough), findsWidgets); + + // Verify that the custom widget is still present + expect(find.text('Custom Widget'), findsOneWidget); + }, + ); + + testWidgets( + 'CustomToolbarItem with MacosSearchField is wrapped with MacosToolbarPassthrough', + (tester) async { + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + toolBar: ToolBar( + title: const Text('Test'), + actions: [ + CustomToolbarItem( + inToolbarBuilder: (context) => + const SizedBox(width: 200, child: MacosSearchField()), + ), + ], + ), + children: [ + ContentArea( + builder: (context, _) { + return const Center(child: Text('Content')); + }, + ), + ], + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + // Verify that MacosToolbarPassthrough is present + expect(find.byType(MacosToolbarPassthrough), findsWidgets); + + // Verify that the search field is present + expect(find.byType(MacosSearchField), findsOneWidget); + }, + ); + + testWidgets( + 'CustomToolbarItem with tooltip is wrapped with MacosToolbarPassthrough', + (tester) async { + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + toolBar: ToolBar( + title: const Text('Test'), + actions: [ + CustomToolbarItem( + tooltipMessage: 'Custom Tooltip', + inToolbarBuilder: (context) => Container( + width: 100, + height: 30, + color: CupertinoColors.systemBlue, + child: const Center(child: Text('Custom Widget')), + ), + ), + ], + ), + children: [ + ContentArea( + builder: (context, _) { + return const Center(child: Text('Content')); + }, + ), + ], + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + // Verify that MacosToolbarPassthrough is present + expect(find.byType(MacosToolbarPassthrough), findsWidgets); + + // Verify tooltip is present + expect(find.byType(MacosTooltip), findsOneWidget); + }, + ); + + testWidgets('CustomToolbarItem interaction still works when wrapped', ( + tester, + ) async { + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + toolBar: ToolBar( + title: const Text('Test'), + actions: [ + CustomToolbarItem( + inToolbarBuilder: (context) => GestureDetector( + onTap: mockOnPressedFunction.handler, + child: Container( + width: 100, + height: 30, + color: CupertinoColors.systemBlue, + child: const Center(child: Text('Tap Me')), + ), + ), + ), + ], + ), + children: [ + ContentArea( + builder: (context, _) { + return const Center(child: Text('Content')); + }, + ), + ], + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + // Find and tap the custom widget + final customWidget = find.text('Tap Me'); + expect(customWidget, findsOneWidget); + + await tester.tap(customWidget); + await tester.pumpAndSettle(); + + // Verify the callback was called + expect(mockOnPressedFunction.called, greaterThan(0)); + }); + + testWidgets( + 'Multiple CustomToolbarItems each have their own MacosToolbarPassthrough', + (tester) async { + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + toolBar: ToolBar( + title: const Text('Test'), + actions: [ + CustomToolbarItem( + inToolbarBuilder: (context) => Container( + width: 100, + height: 30, + color: CupertinoColors.systemBlue, + child: const Center(child: Text('Custom 1')), + ), + ), + CustomToolbarItem( + inToolbarBuilder: (context) => Container( + width: 100, + height: 30, + color: CupertinoColors.systemGreen, + child: const Center(child: Text('Custom 2')), + ), + ), + ], + ), + children: [ + ContentArea( + builder: (context, _) { + return const Center(child: Text('Content')); + }, + ), + ], + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + // Each custom item should have its own MacosToolbarPassthrough wrapper + expect(find.byType(MacosToolbarPassthrough), findsWidgets); + expect(find.text('Custom 1'), findsOneWidget); + expect(find.text('Custom 2'), findsOneWidget); + }, + ); + + testWidgets( + 'Mixed toolbar with custom, icon, and pulldown items all have MacosToolbarPassthrough', + (tester) async { + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + toolBar: ToolBar( + title: const Text('Test'), + actions: [ + ToolBarIconButton( + label: 'Add', + icon: const MacosIcon(CupertinoIcons.add), + showLabel: false, + onPressed: mockOnPressedFunction.handler, + ), + CustomToolbarItem( + inToolbarBuilder: (context) => + const SizedBox(width: 150, child: MacosSearchField()), + ), + ToolBarPullDownButton( + label: 'Actions', + icon: CupertinoIcons.ellipsis_circle, + items: [ + MacosPulldownMenuItem( + label: 'Item 1', + title: const Text('Item 1'), + onTap: mockOnPressedFunction.handler, + ), + ], + ), + ], + ), + children: [ + ContentArea( + builder: (context, _) { + return const Center(child: Text('Content')); + }, + ), + ], + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + // All three toolbar items should be wrapped with MacosToolbarPassthrough + expect(find.byType(MacosToolbarPassthrough), findsWidgets); + expect(find.byType(MacosIconButton), findsWidgets); + expect(find.byType(MacosSearchField), findsWidgets); + expect(find.byType(MacosPulldownButton), findsWidgets); + }, + ); + }); +} diff --git a/test/layout/resizeable_pane_test.dart b/test/layout/resizeable_pane_test.dart index f3ac9f83..9697ef3d 100644 --- a/test/layout/resizeable_pane_test.dart +++ b/test/layout/resizeable_pane_test.dart @@ -38,9 +38,7 @@ void main() { children: [ const Flexible( fit: FlexFit.loose, - child: Center( - child: Text('Hello there'), - ), + child: Center(child: Text('Hello there')), ), resizablePane, ], @@ -90,8 +88,9 @@ void main() { testWidgets('initial size equals startSize', (tester) async { await tester.pumpWidget(view); - var resizablePaneRenderObject = - tester.renderObject(resizablePaneFinder); + var resizablePaneRenderObject = tester.renderObject( + resizablePaneFinder, + ); var initialSize = verticallyResizable ? resizablePaneRenderObject.size.height : resizablePaneRenderObject.size.width; @@ -108,8 +107,9 @@ void main() { ); await tester.pump(); - var resizablePaneRenderObject = - tester.renderObject(resizablePaneFinder); + var resizablePaneRenderObject = tester.renderObject( + resizablePaneFinder, + ); expect( verticallyResizable ? resizablePaneRenderObject.size.height @@ -129,42 +129,43 @@ void main() { ); await tester.pump(); - var resizablePaneRenderObject = - tester.renderObject(resizablePaneFinder); + var resizablePaneRenderObject = tester.renderObject( + resizablePaneFinder, + ); var currentSize = verticallyResizable ? resizablePaneRenderObject.size.height : resizablePaneRenderObject.size.width; expect(currentSize, maxSize); }); - testWidgets( - 'drag events past maxSize have no effect $side', - (tester) async { - await tester.pumpWidget(view); + testWidgets('drag events past maxSize have no effect $side', ( + tester, + ) async { + await tester.pumpWidget(view); - final dragStartLocation = tester.getCenter(dragFinder); - final drag = await tester.startGesture(dragStartLocation); - await drag.moveBy( - verticallyResizable - ? Offset(0, overflowDelta) - : Offset(overflowDelta, 0), - ); - await drag.moveBy( - verticallyResizable - ? Offset(0, -10.0 * directionModifier) - : Offset(-10.0 * directionModifier, 0), - ); - await drag.up(); - await tester.pump(); - - var resizablePaneRenderObject = - tester.renderObject(resizablePaneFinder); - var currentSize = verticallyResizable - ? resizablePaneRenderObject.size.height - : resizablePaneRenderObject.size.width; - expect(currentSize, maxSize); - }, - ); + final dragStartLocation = tester.getCenter(dragFinder); + final drag = await tester.startGesture(dragStartLocation); + await drag.moveBy( + verticallyResizable + ? Offset(0, overflowDelta) + : Offset(overflowDelta, 0), + ); + await drag.moveBy( + verticallyResizable + ? Offset(0, -10.0 * directionModifier) + : Offset(-10.0 * directionModifier, 0), + ); + await drag.up(); + await tester.pump(); + + var resizablePaneRenderObject = tester.renderObject( + resizablePaneFinder, + ); + var currentSize = verticallyResizable + ? resizablePaneRenderObject.size.height + : resizablePaneRenderObject.size.width; + expect(currentSize, maxSize); + }); testWidgets('dragging narrower works', (tester) async { await tester.pumpWidget(view); @@ -177,15 +178,13 @@ void main() { ); await tester.pump(); - var resizablePaneRenderObject = - tester.renderObject(resizablePaneFinder); + var resizablePaneRenderObject = tester.renderObject( + resizablePaneFinder, + ); var currentSize = verticallyResizable ? resizablePaneRenderObject.size.height : resizablePaneRenderObject.size.width; - expect( - currentSize, - startSize - safeDelta * directionModifier, - ); + expect(currentSize, startSize - safeDelta * directionModifier); }); testWidgets('dragging narrower respects minSize', (tester) async { @@ -199,42 +198,43 @@ void main() { ); await tester.pump(); - var resizablePaneRenderObject = - tester.renderObject(resizablePaneFinder); + var resizablePaneRenderObject = tester.renderObject( + resizablePaneFinder, + ); var currentSize = verticallyResizable ? resizablePaneRenderObject.size.height : resizablePaneRenderObject.size.width; expect(currentSize, minSize); }); - testWidgets( - 'drag events past minSize have no effect', - (tester) async { - await tester.pumpWidget(view); + testWidgets('drag events past minSize have no effect', ( + tester, + ) async { + await tester.pumpWidget(view); - final dragStartLocation = tester.getCenter(dragFinder); - final drag = await tester.startGesture(dragStartLocation); - await drag.moveBy( - verticallyResizable - ? Offset(0, -overflowDelta) - : Offset(-overflowDelta, 0), - ); - await drag.moveBy( - verticallyResizable - ? Offset(0, 10.0 * directionModifier) - : Offset(10.0 * directionModifier, 0), - ); - await drag.up(); - await tester.pump(); - - var resizablePaneRenderObject = - tester.renderObject(resizablePaneFinder); - var currentSize = verticallyResizable - ? resizablePaneRenderObject.size.height - : resizablePaneRenderObject.size.width; - expect(currentSize, minSize); - }, - ); + final dragStartLocation = tester.getCenter(dragFinder); + final drag = await tester.startGesture(dragStartLocation); + await drag.moveBy( + verticallyResizable + ? Offset(0, -overflowDelta) + : Offset(-overflowDelta, 0), + ); + await drag.moveBy( + verticallyResizable + ? Offset(0, 10.0 * directionModifier) + : Offset(10.0 * directionModifier, 0), + ); + await drag.up(); + await tester.pump(); + + var resizablePaneRenderObject = tester.renderObject( + resizablePaneFinder, + ); + var currentSize = verticallyResizable + ? resizablePaneRenderObject.size.height + : resizablePaneRenderObject.size.width; + expect(currentSize, minSize); + }); }, ); group( @@ -262,9 +262,7 @@ void main() { children: [ const Flexible( fit: FlexFit.loose, - child: Center( - child: Text('Hello there'), - ), + child: Center(child: Text('Hello there')), ), resizablePane, ], @@ -314,8 +312,9 @@ void main() { testWidgets('initial size equals startSize', (tester) async { await tester.pumpWidget(view); - var resizablePaneRenderObject = - tester.renderObject(resizablePaneFinder); + var resizablePaneRenderObject = tester.renderObject( + resizablePaneFinder, + ); var initialSize = verticallyResizable ? resizablePaneRenderObject.size.height : resizablePaneRenderObject.size.width; @@ -332,8 +331,9 @@ void main() { ); await tester.pump(); - var resizablePaneRenderObject = - tester.renderObject(resizablePaneFinder); + var resizablePaneRenderObject = tester.renderObject( + resizablePaneFinder, + ); expect( verticallyResizable ? resizablePaneRenderObject.size.height @@ -353,42 +353,43 @@ void main() { ); await tester.pump(); - var resizablePaneRenderObject = - tester.renderObject(resizablePaneFinder); + var resizablePaneRenderObject = tester.renderObject( + resizablePaneFinder, + ); var currentSize = verticallyResizable ? resizablePaneRenderObject.size.height : resizablePaneRenderObject.size.width; expect(currentSize, maxSize); }); - testWidgets( - 'drag events past maxSize have no effect $side', - (tester) async { - await tester.pumpWidget(view); + testWidgets('drag events past maxSize have no effect $side', ( + tester, + ) async { + await tester.pumpWidget(view); - final dragStartLocation = tester.getCenter(dragFinder); - final drag = await tester.startGesture(dragStartLocation); - await drag.moveBy( - verticallyResizable - ? Offset(0, overflowDelta) - : Offset(overflowDelta, 0), - ); - await drag.moveBy( - verticallyResizable - ? Offset(0, -10.0 * directionModifier) - : Offset(-10.0 * directionModifier, 0), - ); - await drag.up(); - await tester.pump(); - - var resizablePaneRenderObject = - tester.renderObject(resizablePaneFinder); - var currentSize = verticallyResizable - ? resizablePaneRenderObject.size.height - : resizablePaneRenderObject.size.width; - expect(currentSize, maxSize); - }, - ); + final dragStartLocation = tester.getCenter(dragFinder); + final drag = await tester.startGesture(dragStartLocation); + await drag.moveBy( + verticallyResizable + ? Offset(0, overflowDelta) + : Offset(overflowDelta, 0), + ); + await drag.moveBy( + verticallyResizable + ? Offset(0, -10.0 * directionModifier) + : Offset(-10.0 * directionModifier, 0), + ); + await drag.up(); + await tester.pump(); + + var resizablePaneRenderObject = tester.renderObject( + resizablePaneFinder, + ); + var currentSize = verticallyResizable + ? resizablePaneRenderObject.size.height + : resizablePaneRenderObject.size.width; + expect(currentSize, maxSize); + }); testWidgets('dragging narrower works', (tester) async { await tester.pumpWidget(view); @@ -401,15 +402,13 @@ void main() { ); await tester.pump(); - var resizablePaneRenderObject = - tester.renderObject(resizablePaneFinder); + var resizablePaneRenderObject = tester.renderObject( + resizablePaneFinder, + ); var currentSize = verticallyResizable ? resizablePaneRenderObject.size.height : resizablePaneRenderObject.size.width; - expect( - currentSize, - startSize - safeDelta * directionModifier, - ); + expect(currentSize, startSize - safeDelta * directionModifier); }); testWidgets('dragging narrower respects minSize', (tester) async { @@ -423,42 +422,43 @@ void main() { ); await tester.pump(); - var resizablePaneRenderObject = - tester.renderObject(resizablePaneFinder); + var resizablePaneRenderObject = tester.renderObject( + resizablePaneFinder, + ); var currentSize = verticallyResizable ? resizablePaneRenderObject.size.height : resizablePaneRenderObject.size.width; expect(currentSize, minSize); }); - testWidgets( - 'drag events past minSize have no effect', - (tester) async { - await tester.pumpWidget(view); + testWidgets('drag events past minSize have no effect', ( + tester, + ) async { + await tester.pumpWidget(view); - final dragStartLocation = tester.getCenter(dragFinder); - final drag = await tester.startGesture(dragStartLocation); - await drag.moveBy( - verticallyResizable - ? Offset(0, -overflowDelta) - : Offset(-overflowDelta, 0), - ); - await drag.moveBy( - verticallyResizable - ? Offset(0, 10.0 * directionModifier) - : Offset(10.0 * directionModifier, 0), - ); - await drag.up(); - await tester.pump(); - - var resizablePaneRenderObject = - tester.renderObject(resizablePaneFinder); - var currentSize = verticallyResizable - ? resizablePaneRenderObject.size.height - : resizablePaneRenderObject.size.width; - expect(currentSize, minSize); - }, - ); + final dragStartLocation = tester.getCenter(dragFinder); + final drag = await tester.startGesture(dragStartLocation); + await drag.moveBy( + verticallyResizable + ? Offset(0, -overflowDelta) + : Offset(-overflowDelta, 0), + ); + await drag.moveBy( + verticallyResizable + ? Offset(0, 10.0 * directionModifier) + : Offset(10.0 * directionModifier, 0), + ); + await drag.up(); + await tester.pump(); + + var resizablePaneRenderObject = tester.renderObject( + resizablePaneFinder, + ); + var currentSize = verticallyResizable + ? resizablePaneRenderObject.size.height + : resizablePaneRenderObject.size.width; + expect(currentSize, minSize); + }); }, ); } diff --git a/test/layout/sliver_toolbar_test.dart b/test/layout/sliver_toolbar_test.dart index 0d693771..a97a16e4 100644 --- a/test/layout/sliver_toolbar_test.dart +++ b/test/layout/sliver_toolbar_test.dart @@ -26,9 +26,7 @@ void main() { floating: floating, toolbarOpacity: 0.9, ), - const SliverToBoxAdapter( - child: SizedBox(height: 1200), - ), + const SliverToBoxAdapter(child: SizedBox(height: 1200)), ], ); }, @@ -39,91 +37,80 @@ void main() { ); } - testWidgets( - 'MediaQuery bottom padding is removed as expected', - (tester) async { - final Key leadingKey = GlobalKey(); - final Key titleKey = GlobalKey(); - await tester.pumpWidget( - MacosApp( - home: MediaQuery( - data: const MediaQueryData( - padding: EdgeInsets.only( - bottom: 30.0, + testWidgets('MediaQuery bottom padding is removed as expected', ( + tester, + ) async { + final Key leadingKey = GlobalKey(); + final Key titleKey = GlobalKey(); + await tester.pumpWidget( + MacosApp( + home: MediaQuery( + data: const MediaQueryData(padding: EdgeInsets.only(bottom: 30.0)), + child: MacosScaffold( + children: [ + ContentArea( + builder: (context, scrollController) { + return CustomScrollView( + controller: scrollController, + slivers: [ + SliverToolBar( + leading: Placeholder(key: leadingKey), + title: Text('Title', key: titleKey), + ), + const SliverToBoxAdapter(child: SizedBox(height: 1200)), + ], + ); + }, ), - ), - child: MacosScaffold( - children: [ - ContentArea( - builder: (context, scrollController) { - return CustomScrollView( - controller: scrollController, - slivers: [ - SliverToolBar( - leading: Placeholder(key: leadingKey), - title: Text('Title', key: titleKey), - ), - const SliverToBoxAdapter( - child: SizedBox(height: 1200), - ), - ], - ); - }, - ), - ], - ), + ], ), ), - ); + ), + ); - // location of bottomLeft is unchanged by applying padding - expect( - tester.getBottomLeft(find.byKey(leadingKey)), - const Offset(8.0, 47.0), - ); + // location of bottomLeft is unchanged by applying padding + expect( + tester.getBottomLeft(find.byKey(leadingKey)), + const Offset(8.0, 47.0), + ); - await tester.pump(Duration.zero); - }, - ); + await tester.pump(Duration.zero); + }); - testWidgets( - 'Y-Offsets and sizes are correct', - (tester) async { - final ScrollController controller = ScrollController(); - await pumpScrollableWithSliverToolbar(tester, controller); + testWidgets('Y-Offsets and sizes are correct', (tester) async { + final ScrollController controller = ScrollController(); + await pumpScrollableWithSliverToolbar(tester, controller); - final toolbar = find.byType(ToolBar); - final navToolbar = find.byType(NavigationToolbar); + final toolbar = find.byType(ToolBar); + final navToolbar = find.byType(NavigationToolbar); - expect(tester.getTopLeft(toolbar).dy, 0.0); - expect(tester.getTopLeft(navToolbar).dy, 4.0); - expect(tester.getSize(toolbar).height, 52.0); - expect(tester.getSize(navToolbar).height, 43.0); + expect(tester.getTopLeft(toolbar).dy, 0.0); + expect(tester.getTopLeft(navToolbar).dy, 4.0); + expect(tester.getSize(toolbar).height, 52.0); + expect(tester.getSize(navToolbar).height, 43.0); - await tester.pump(Duration.zero); - }, - ); + await tester.pump(Duration.zero); + }); - testWidgets( - 'Scrolling down while pinned=true keeps the toolbar in view', - (tester) async { - final ScrollController controller = ScrollController(); - await pumpScrollableWithSliverToolbar(tester, controller); + testWidgets('Scrolling down while pinned=true keeps the toolbar in view', ( + tester, + ) async { + final ScrollController controller = ScrollController(); + await pumpScrollableWithSliverToolbar(tester, controller); - final toolbar = find.byType(ToolBar); - final navToolbar = find.byType(NavigationToolbar); + final toolbar = find.byType(ToolBar); + final navToolbar = find.byType(NavigationToolbar); - expect(controller.offset, 0.0); + expect(controller.offset, 0.0); - controller.jumpTo(600.0); - await tester.pump(); + controller.jumpTo(600.0); + await tester.pump(); - expect(tester.getTopLeft(toolbar).dy, 0.0); - expect(tester.getTopLeft(navToolbar).dy, 4.0); + expect(tester.getTopLeft(toolbar).dy, 0.0); + expect(tester.getTopLeft(navToolbar).dy, 4.0); - await tester.pump(Duration.zero); - }, - ); + await tester.pump(Duration.zero); + }); testWidgets( 'Scrolling down while pinned=false does not keep the toolbar in view', @@ -172,12 +159,14 @@ void main() { expect(toolbar, findsNothing); expect(navToolbar, findsNothing); - final Offset scrollEventLocation = - tester.getCenter(find.byType(CustomScrollView)); + final Offset scrollEventLocation = tester.getCenter( + find.byType(CustomScrollView), + ); final TestPointer testPointer = TestPointer(1, PointerDeviceKind.mouse); testPointer.hover(scrollEventLocation); - await tester - .sendEventToBinding(testPointer.scroll(const Offset(0.0, -52.0))); + await tester.sendEventToBinding( + testPointer.scroll(const Offset(0.0, -52.0)), + ); await tester.pumpAndSettle(); expect(controller.offset, 548.0); diff --git a/test/layout/tab_view_test.dart b/test/layout/tab_view_test.dart index 2fb09c07..67047420 100644 --- a/test/layout/tab_view_test.dart +++ b/test/layout/tab_view_test.dart @@ -4,61 +4,46 @@ import 'package:macos_ui/src/library.dart'; void main() { group('MacosTabView tests', () { - testWidgets( - 'Tapping a tab changes the child in view', - (tester) async { - final controller = MacosTabController(length: 3, initialIndex: 0); - await tester.pumpWidget( - MacosApp( - home: MacosWindow( - child: MacosScaffold( - children: [ - ContentArea( - builder: (context, _) { - return Padding( - padding: const EdgeInsets.all(24.0), - child: MacosTabView( - controller: controller, - tabs: const [ - MacosTab( - label: 'Tab 1', - ), - MacosTab( - label: 'Tab 2', - ), - MacosTab( - label: 'Tab 3', - ), - ], - children: const [ - Center( - child: Text('Tab child 1'), - ), - Center( - child: Text('Tab child 2'), - ), - Center( - child: Text('Tab child 3'), - ), - ], - ), - ); - }, - ), - ], - ), + testWidgets('Tapping a tab changes the child in view', (tester) async { + final controller = MacosTabController(length: 3, initialIndex: 0); + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + children: [ + ContentArea( + builder: (context, _) { + return Padding( + padding: const EdgeInsets.all(24.0), + child: MacosTabView( + controller: controller, + tabs: const [ + MacosTab(label: 'Tab 1'), + MacosTab(label: 'Tab 2'), + MacosTab(label: 'Tab 3'), + ], + children: const [ + Center(child: Text('Tab child 1')), + Center(child: Text('Tab child 2')), + Center(child: Text('Tab child 3')), + ], + ), + ); + }, + ), + ], ), ), - ); + ), + ); - final segmentedControl = find.byType(MacosSegmentedControl); - expect(segmentedControl, findsOneWidget); - final secondTab = find.byType(MacosTab).at(1); - expect(secondTab, findsOneWidget); - await tester.tap(secondTab); - await tester.pumpAndSettle(); - expect(controller.index, 1); - }, - ); + final segmentedControl = find.byType(MacosSegmentedControl); + expect(segmentedControl, findsOneWidget); + final secondTab = find.byType(MacosTab).at(1); + expect(secondTab, findsOneWidget); + await tester.tap(secondTab); + await tester.pumpAndSettle(); + expect(controller.index, 1); + }); }); } diff --git a/test/layout/window_test.dart b/test/layout/window_test.dart index 92f1a80a..1d9bb9ec 100644 --- a/test/layout/window_test.dart +++ b/test/layout/window_test.dart @@ -32,9 +32,7 @@ void main() { home: MacosWindow( disableWallpaperTinting: true, sidebar: sidebar, - child: const MacosScaffold( - children: [], - ), + child: const MacosScaffold(children: []), ), ); } @@ -44,14 +42,8 @@ void main() { final backgroundFinder = find.byType(AnimatedPositioned).at(0); expectSidebarOpen(tester, {required double width}) { - expect( - tester.widget(sidebarFinder).width, - width, - ); - expect( - tester.widget(backgroundFinder).left, - width, - ); + expect(tester.widget(sidebarFinder).width, width); + expect(tester.widget(backgroundFinder).left, width); } expectSidebarClosed(tester) { @@ -59,10 +51,7 @@ void main() { tester.widget(sidebarFinder).width, minWidth, ); - expect( - tester.widget(backgroundFinder).left, - 0, - ); + expect(tester.widget(backgroundFinder).left, 0); } testWidgets('initial width equals startWidth', (tester) async { @@ -105,8 +94,9 @@ void main() { testWidgets('drag events past maxWidth have no effect', (tester) async { final view = viewBuilder(sidebarBuilder()); await tester.pumpWidget(view); - final gesture = - await tester.startGesture(tester.getCenter(resizerFinder)); + final gesture = await tester.startGesture( + tester.getCenter(resizerFinder), + ); await gesture.moveBy(const Offset(overflowDelta, 0)); await gesture.moveBy(const Offset(-safeDelta, 0)); await gesture.up(); @@ -133,8 +123,9 @@ void main() { 'dragging narrower past minWidth but before minWidth - dragClosedBuffer does not close the sidebar', (tester) async { const dragClosedBuffer = 20.0; - final view = - viewBuilder(sidebarBuilder(dragClosedBuffer: dragClosedBuffer)); + final view = viewBuilder( + sidebarBuilder(dragClosedBuffer: dragClosedBuffer), + ); await tester.pumpWidget(view); await tester.drag( resizerFinder, @@ -150,27 +141,27 @@ void main() { await tester.pump(Duration.zero); }, ); - testWidgets( - 'dragging narrower past minWidth closes the sidebar', - (tester) async { - final view = viewBuilder(sidebarBuilder()); - await tester.pumpWidget(view); - await tester.drag(resizerFinder, const Offset(-overflowDelta, 0)); - await tester.pump(); + testWidgets('dragging narrower past minWidth closes the sidebar', ( + tester, + ) async { + final view = viewBuilder(sidebarBuilder()); + await tester.pumpWidget(view); + await tester.drag(resizerFinder, const Offset(-overflowDelta, 0)); + await tester.pump(); - expectSidebarClosed(tester); + expectSidebarClosed(tester); - await tester.pump(Duration.zero); - }, - ); + await tester.pump(Duration.zero); + }); testWidgets( 'dragging narrower past minWidth and then back reopens the sidebar', (tester) async { final view = viewBuilder(sidebarBuilder()); await tester.pumpWidget(view); - final gesture = - await tester.startGesture(tester.getCenter(resizerFinder)); + final gesture = await tester.startGesture( + tester.getCenter(resizerFinder), + ); for (var moved = 0; moved < overflowDelta; moved += 10) { await gesture.moveBy(const Offset(-10, 0)); } @@ -178,9 +169,11 @@ void main() { expectSidebarClosed(tester); - for (var moved = 0; - moved < overflowDelta - safeDelta; - moved += 10) { + for ( + var moved = 0; + moved < overflowDelta - safeDelta; + moved += 10 + ) { await gesture.moveBy(const Offset(10, 0)); } await gesture.up(); @@ -195,8 +188,9 @@ void main() { testWidgets('drag events past minWidth have no effect', (tester) async { final view = viewBuilder(sidebarBuilder()); await tester.pumpWidget(view); - final gesture = - await tester.startGesture(tester.getCenter(resizerFinder)); + final gesture = await tester.startGesture( + tester.getCenter(resizerFinder), + ); await gesture.moveBy(const Offset(-overflowDelta, 0)); await gesture.moveBy(const Offset(safeDelta, 0)); await gesture.up(); @@ -226,8 +220,9 @@ void main() { testWidgets('drag events past minWidth have no effect', (tester) async { final view = viewBuilder(sidebarBuilder(dragClosed: false)); await tester.pumpWidget(view); - final gesture = - await tester.startGesture(tester.getCenter(resizerFinder)); + final gesture = await tester.startGesture( + tester.getCenter(resizerFinder), + ); await gesture.moveBy(const Offset(-overflowDelta, 0)); await gesture.moveBy(const Offset(safeDelta, 0)); await gesture.up(); @@ -246,14 +241,13 @@ void main() { 'dragging from startWidth has no effect until it passes snapToStartBuffer', (tester) async { final view = viewBuilder( - sidebarBuilder( - snapToStartBuffer: snapToStartBuffer, - ), + sidebarBuilder(snapToStartBuffer: snapToStartBuffer), ); await tester.pumpWidget(view); - final gesture = - await tester.startGesture(tester.getCenter(resizerFinder)); + final gesture = await tester.startGesture( + tester.getCenter(resizerFinder), + ); await gesture.moveBy(const Offset(snapToStartBuffer, 0)); await tester.pump(); @@ -275,9 +269,7 @@ void main() { 'dragging from outside to within startWidth +/- snapToStartBuffer sets width to startWidth', (tester) async { final view = viewBuilder( - sidebarBuilder( - snapToStartBuffer: snapToStartBuffer, - ), + sidebarBuilder(snapToStartBuffer: snapToStartBuffer), ); await tester.pumpWidget(view); diff --git a/test/mock_canvas.dart b/test/mock_canvas.dart index ee18e4f3..dc1ebc34 100644 --- a/test/mock_canvas.dart +++ b/test/mock_canvas.dart @@ -64,12 +64,12 @@ Matcher paintedExactlyCountTimes(Symbol methodName, int count) { /// ```dart /// if (methodName == #drawCircle) { ... } /// ``` -typedef PaintPatternPredicate = bool Function( - Symbol methodName, List arguments); +typedef PaintPatternPredicate = + bool Function(Symbol methodName, List arguments); /// The signature of [RenderObject.paint] functions. -typedef _ContextPainterFunction = void Function( - PaintingContext context, Offset offset); +typedef _ContextPainterFunction = + void Function(PaintingContext context, Offset offset); /// The signature of functions that paint directly on a canvas. typedef _CanvasPainterFunction = void Function(Canvas canvas); @@ -195,12 +195,13 @@ abstract class PaintPattern { /// painting has completed, not at the time of the call. If the same [Paint] /// object is reused multiple times, then this may not match the actual /// arguments as they were seen by the method. - void rect( - {Rect? rect, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}); + void rect({ + Rect? rect, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }); /// Indicates that a rounded rectangle clip is expected next. /// @@ -230,12 +231,13 @@ abstract class PaintPattern { /// painting has completed, not at the time of the call. If the same [Paint] /// object is reused multiple times, then this may not match the actual /// arguments as they were seen by the method. - void rrect( - {RRect? rrect, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}); + void rrect({ + RRect? rrect, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }); /// Indicates that a rounded rectangle outline is expected next. /// @@ -253,13 +255,14 @@ abstract class PaintPattern { /// painting has completed, not at the time of the call. If the same [Paint] /// object is reused multiple times, then this may not match the actual /// arguments as they were seen by the method. - void drrect( - {RRect? outer, - RRect? inner, - Color? color, - double strokeWidth, - bool hasMaskFilter, - PaintingStyle style}); + void drrect({ + RRect? outer, + RRect? inner, + Color? color, + double strokeWidth, + bool hasMaskFilter, + PaintingStyle style, + }); /// Indicates that a circle is expected next. /// @@ -277,14 +280,15 @@ abstract class PaintPattern { /// painting has completed, not at the time of the call. If the same [Paint] /// object is reused multiple times, then this may not match the actual /// arguments as they were seen by the method. - void circle( - {double? x, - double? y, - double? radius, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}); + void circle({ + double? x, + double? y, + double? radius, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }); /// Indicates that a path is expected next. /// @@ -307,13 +311,14 @@ abstract class PaintPattern { /// painting has completed, not at the time of the call. If the same [Paint] /// object is reused multiple times, then this may not match the actual /// arguments as they were seen by the method. - void path( - {Iterable? includes, - Iterable? excludes, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}); + void path({ + Iterable? includes, + Iterable? excludes, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }); /// Indicates that a line is expected next. /// @@ -331,13 +336,14 @@ abstract class PaintPattern { /// painting has completed, not at the time of the call. If the same [Paint] /// object is reused multiple times, then this may not match the actual /// arguments as they were seen by the method. - void line( - {Offset? p1, - Offset? p2, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}); + void line({ + Offset? p1, + Offset? p2, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }); /// Indicates that an arc is expected next. /// @@ -355,11 +361,12 @@ abstract class PaintPattern { /// painting has completed, not at the time of the call. If the same [Paint] /// object is reused multiple times, then this may not match the actual /// arguments as they were seen by the method. - void arc( - {Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}); + void arc({ + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }); /// Indicates that a paragraph is expected next. /// @@ -396,12 +403,13 @@ abstract class PaintPattern { /// /// Any calls made between the last matched call (if any) and the /// [Canvas.drawShadow] call are ignored. - void shadow( - {Iterable? includes, - Iterable? excludes, - Color? color, - double? elevation, - bool? transparentOccluder}); + void shadow({ + Iterable? includes, + Iterable? excludes, + Color? color, + double? elevation, + bool? transparentOccluder, + }); /// Indicates that an image is expected next. /// @@ -419,14 +427,15 @@ abstract class PaintPattern { /// painting has completed, not at the time of the call. If the same [Paint] /// object is reused multiple times, then this may not match the actual /// arguments as they were seen by the method. - void image( - {ui.Image? image, - double? x, - double? y, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}); + void image({ + ui.Image? image, + double? x, + double? y, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }); /// Indicates that an image subsection is expected next. /// @@ -444,14 +453,15 @@ abstract class PaintPattern { /// painting has completed, not at the time of the call. If the same [Paint] /// object is reused multiple times, then this may not match the actual /// arguments as they were seen by the method. - void drawImageRect( - {ui.Image? image, - Rect? source, - Rect? destination, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}); + void drawImageRect({ + ui.Image? image, + Rect? source, + Rect? destination, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }); /// Provides a custom matcher. /// @@ -546,7 +556,8 @@ class _PathMatcher extends Matcher { } return description.add( - 'A Path that contains ${points(includes)} but does not contain ${points(excludes)}.'); + 'A Path that contains ${points(includes)} but does not contain ${points(excludes)}.', + ); } @override @@ -594,8 +605,7 @@ abstract class _TestRecordingCanvasMatcher extends Matcher { @override bool matches(Object? object, Map matchState) { final TestRecordCanvas canvas = TestRecordCanvas(); - final TestRecordPaintingContext context = - TestRecordPaintingContext(canvas); + final TestRecordPaintingContext context = TestRecordPaintingContext(canvas); final StringBuffer description = StringBuffer(); String prefixMessage = 'unexpectedly failed.'; bool result = false; @@ -628,7 +638,9 @@ abstract class _TestRecordingCanvasMatcher extends Matcher { } bool _evaluatePredicates( - Iterable calls, StringBuffer description); + Iterable calls, + StringBuffer description, + ); @override Description describeMismatch( @@ -644,21 +656,24 @@ abstract class _TestRecordingCanvasMatcher extends Matcher { class _TestRecordingCanvasPaintsCountMatcher extends _TestRecordingCanvasMatcher { _TestRecordingCanvasPaintsCountMatcher(Symbol methodName, int count) - : _methodName = methodName, - _count = count; + : _methodName = methodName, + _count = count; final Symbol _methodName; final int _count; @override Description describe(Description description) { - return description - .add('Object or closure painting $_methodName exactly $_count times'); + return description.add( + 'Object or closure painting $_methodName exactly $_count times', + ); } @override bool _evaluatePredicates( - Iterable calls, StringBuffer description) { + Iterable calls, + StringBuffer description, + ) { int count = 0; for (final RecordInvocation call in calls) { if (call.invocation.isMethod && @@ -668,7 +683,8 @@ class _TestRecordingCanvasPaintsCountMatcher } if (count != _count) { description.write( - 'It painted $_methodName $count times instead of $_count times.'); + 'It painted $_methodName $count times instead of $_count times.', + ); } return count == _count; } @@ -683,9 +699,10 @@ class _TestRecordingCanvasPaintsNothingMatcher @override bool _evaluatePredicates( - Iterable calls, StringBuffer description) { - final Iterable paintingCalls = - _filterCanvasCalls(calls); + Iterable calls, + StringBuffer description, + ) { + final Iterable paintingCalls = _filterCanvasCalls(calls); if (paintingCalls.isEmpty) { return true; } @@ -696,14 +713,12 @@ class _TestRecordingCanvasPaintsNothingMatcher return false; } - static const List _nonPaintingOperations = [ - #save, - #restore, - ]; + static const List _nonPaintingOperations = [#save, #restore]; // Filters out canvas calls that are not painting anything. static Iterable _filterCanvasCalls( - Iterable canvasCalls) { + Iterable canvasCalls, + ) { return canvasCalls.where( (RecordInvocation canvasCall) => !_nonPaintingOperations.contains(canvasCall.invocation.memberName), @@ -715,8 +730,7 @@ class _TestRecordingCanvasPaintsAssertionMatcher extends Matcher { @override bool matches(Object? object, Map matchState) { final TestRecordCanvas canvas = TestRecordCanvas(); - final TestRecordPaintingContext context = - TestRecordPaintingContext(canvas); + final TestRecordPaintingContext context = TestRecordPaintingContext(canvas); final StringBuffer description = StringBuffer(); String prefixMessage = 'unexpectedly failed.'; bool result = false; @@ -749,8 +763,9 @@ class _TestRecordingCanvasPaintsAssertionMatcher extends Matcher { @override Description describe(Description description) { - return description - .add('An object or closure that asserts when it tries to paint.'); + return description.add( + 'An object or closure that asserts when it tries to paint.', + ); } @override @@ -814,18 +829,22 @@ class _TestRecordingCanvasPatternMatcher extends _TestRecordingCanvasMatcher } @override - void rect( - {Rect? rect, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}) { - _predicates.add(_RectPaintPredicate( + void rect({ + Rect? rect, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }) { + _predicates.add( + _RectPaintPredicate( rect: rect, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, - style: style)); + style: style, + ), + ); } @override @@ -834,160 +853,197 @@ class _TestRecordingCanvasPatternMatcher extends _TestRecordingCanvasMatcher } @override - void rrect( - {RRect? rrect, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}) { - _predicates.add(_RRectPaintPredicate( + void rrect({ + RRect? rrect, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }) { + _predicates.add( + _RRectPaintPredicate( rrect: rrect, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, - style: style)); + style: style, + ), + ); } @override - void drrect( - {RRect? outer, - RRect? inner, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}) { - _predicates.add(_DRRectPaintPredicate( + void drrect({ + RRect? outer, + RRect? inner, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }) { + _predicates.add( + _DRRectPaintPredicate( outer: outer, inner: inner, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, - style: style)); + style: style, + ), + ); } @override - void circle( - {double? x, - double? y, - double? radius, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}) { - _predicates.add(_CirclePaintPredicate( + void circle({ + double? x, + double? y, + double? radius, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }) { + _predicates.add( + _CirclePaintPredicate( x: x, y: y, radius: radius, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, - style: style)); + style: style, + ), + ); } @override - void path( - {Iterable? includes, - Iterable? excludes, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}) { - _predicates.add(_PathPaintPredicate( + void path({ + Iterable? includes, + Iterable? excludes, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }) { + _predicates.add( + _PathPaintPredicate( includes: includes, excludes: excludes, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, - style: style)); + style: style, + ), + ); } @override - void line( - {Offset? p1, - Offset? p2, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}) { - _predicates.add(_LinePaintPredicate( + void line({ + Offset? p1, + Offset? p2, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }) { + _predicates.add( + _LinePaintPredicate( p1: p1, p2: p2, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, - style: style)); + style: style, + ), + ); } @override - void arc( - {Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}) { - _predicates.add(_ArcPaintPredicate( + void arc({ + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }) { + _predicates.add( + _ArcPaintPredicate( color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, - style: style)); + style: style, + ), + ); } @override void paragraph({ui.Paragraph? paragraph, dynamic offset}) { _predicates.add( - _FunctionPaintPredicate(#drawParagraph, [paragraph, offset])); + _FunctionPaintPredicate(#drawParagraph, [paragraph, offset]), + ); } @override - void shadow( - {Iterable? includes, - Iterable? excludes, - Color? color, - double? elevation, - bool? transparentOccluder}) { - _predicates.add(_ShadowPredicate( + void shadow({ + Iterable? includes, + Iterable? excludes, + Color? color, + double? elevation, + bool? transparentOccluder, + }) { + _predicates.add( + _ShadowPredicate( includes: includes, excludes: excludes, color: color, elevation: elevation, - transparentOccluder: transparentOccluder)); + transparentOccluder: transparentOccluder, + ), + ); } @override - void image( - {ui.Image? image, - double? x, - double? y, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}) { - _predicates.add(_DrawImagePaintPredicate( + void image({ + ui.Image? image, + double? x, + double? y, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }) { + _predicates.add( + _DrawImagePaintPredicate( image: image, x: x, y: y, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, - style: style)); + style: style, + ), + ); } @override - void drawImageRect( - {ui.Image? image, - Rect? source, - Rect? destination, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}) { - _predicates.add(_DrawImageRectPaintPredicate( + void drawImageRect({ + ui.Image? image, + Rect? source, + Rect? destination, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }) { + _predicates.add( + _DrawImageRectPaintPredicate( image: image, source: source, destination: destination, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, - style: style)); + style: style, + ), + ); } @override @@ -1010,14 +1066,17 @@ class _TestRecordingCanvasPatternMatcher extends _TestRecordingCanvasMatcher '', '\n', '', - _predicates - .map((_PaintPredicate predicate) => predicate.toString()), + _predicates.map( + (_PaintPredicate predicate) => predicate.toString(), + ), ); } @override bool _evaluatePredicates( - Iterable calls, StringBuffer description) { + Iterable calls, + StringBuffer description, + ) { if (calls.isEmpty) { description.writeln('It painted nothing.'); return false; @@ -1045,7 +1104,8 @@ class _TestRecordingCanvasPatternMatcher extends _TestRecordingCanvasMatcher description.writeln(s); try { description.write( - 'The stack of the offending call was:\n${call.current.stackToString(indent: " ")}\n'); + 'The stack of the offending call was:\n${call.current.stackToString(indent: " ")}\n', + ); } on TypeError catch (_) { // All calls have been evaluated } @@ -1181,15 +1241,15 @@ class _OneParameterPaintPredicate extends _DrawCommandPaintPredicate { required bool? hasMaskFilter, required PaintingStyle? style, }) : super( - symbol, - name, - 2, - 1, - color: color, - strokeWidth: strokeWidth, - hasMaskFilter: hasMaskFilter, - style: style, - ); + symbol, + name, + 2, + 1, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); final T? expected; @@ -1226,15 +1286,15 @@ class _TwoParameterPaintPredicate extends _DrawCommandPaintPredicate { required bool? hasMaskFilter, required PaintingStyle? style, }) : super( - symbol, - name, - 3, - 2, - color: color, - strokeWidth: strokeWidth, - hasMaskFilter: hasMaskFilter, - style: style, - ); + symbol, + name, + 3, + 2, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); final T1? expected1; @@ -1274,40 +1334,40 @@ class _TwoParameterPaintPredicate extends _DrawCommandPaintPredicate { } class _RectPaintPredicate extends _OneParameterPaintPredicate { - _RectPaintPredicate( - {Rect? rect, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}) - : super( - #drawRect, - 'a rectangle', - expected: rect, - color: color, - strokeWidth: strokeWidth, - hasMaskFilter: hasMaskFilter, - style: style, - ); + _RectPaintPredicate({ + Rect? rect, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }) : super( + #drawRect, + 'a rectangle', + expected: rect, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); } class _RRectPaintPredicate extends _DrawCommandPaintPredicate { - _RRectPaintPredicate( - {this.rrect, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}) - : super( - #drawRRect, - 'a rounded rectangle', - 2, - 1, - color: color, - strokeWidth: strokeWidth, - hasMaskFilter: hasMaskFilter, - style: style, - ); + _RRectPaintPredicate({ + this.rrect, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }) : super( + #drawRRect, + 'a rounded rectangle', + 2, + 1, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); final RRect? rrect; @@ -1343,44 +1403,44 @@ class _RRectPaintPredicate extends _DrawCommandPaintPredicate { } class _DRRectPaintPredicate extends _TwoParameterPaintPredicate { - _DRRectPaintPredicate( - {RRect? inner, - RRect? outer, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}) - : super( - #drawDRRect, - 'a rounded rectangle outline', - expected1: outer, - expected2: inner, - color: color, - strokeWidth: strokeWidth, - hasMaskFilter: hasMaskFilter, - style: style, - ); + _DRRectPaintPredicate({ + RRect? inner, + RRect? outer, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }) : super( + #drawDRRect, + 'a rounded rectangle outline', + expected1: outer, + expected2: inner, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); } class _CirclePaintPredicate extends _DrawCommandPaintPredicate { - _CirclePaintPredicate( - {this.x, - this.y, - this.radius, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}) - : super( - #drawCircle, - 'a circle', - 3, - 2, - color: color, - strokeWidth: strokeWidth, - hasMaskFilter: hasMaskFilter, - style: style, - ); + _CirclePaintPredicate({ + this.x, + this.y, + this.radius, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }) : super( + #drawCircle, + 'a circle', + 3, + 2, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); final double? x; final double? y; @@ -1429,23 +1489,23 @@ class _CirclePaintPredicate extends _DrawCommandPaintPredicate { } class _PathPaintPredicate extends _DrawCommandPaintPredicate { - _PathPaintPredicate( - {this.includes, - this.excludes, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}) - : super( - #drawPath, - 'a path', - 2, - 1, - color: color, - strokeWidth: strokeWidth, - hasMaskFilter: hasMaskFilter, - style: style, - ); + _PathPaintPredicate({ + this.includes, + this.excludes, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }) : super( + #drawPath, + 'a path', + 2, + 1, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); final Iterable? includes; final Iterable? excludes; @@ -1485,23 +1545,23 @@ class _PathPaintPredicate extends _DrawCommandPaintPredicate { // TODO(ianh): add arguments to test the length, angle, that kind of thing class _LinePaintPredicate extends _DrawCommandPaintPredicate { - _LinePaintPredicate( - {this.p1, - this.p2, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}) - : super( - #drawLine, - 'a line', - 3, - 2, - color: color, - strokeWidth: strokeWidth, - hasMaskFilter: hasMaskFilter, - style: style, - ); + _LinePaintPredicate({ + this.p1, + this.p2, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }) : super( + #drawLine, + 'a line', + 3, + 2, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); final Offset? p1; final Offset? p2; @@ -1535,30 +1595,31 @@ class _LinePaintPredicate extends _DrawCommandPaintPredicate { } class _ArcPaintPredicate extends _DrawCommandPaintPredicate { - _ArcPaintPredicate( - {Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}) - : super( - #drawArc, - 'an arc', - 5, - 4, - color: color, - strokeWidth: strokeWidth, - hasMaskFilter: hasMaskFilter, - style: style, - ); + _ArcPaintPredicate({ + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }) : super( + #drawArc, + 'an arc', + 5, + 4, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); } class _ShadowPredicate extends _PaintPredicate { - _ShadowPredicate( - {this.includes, - this.excludes, - this.color, - this.elevation, - this.transparentOccluder}); + _ShadowPredicate({ + this.includes, + this.excludes, + this.color, + this.elevation, + this.transparentOccluder, + }); final Iterable? includes; final Iterable? excludes; @@ -1644,24 +1705,24 @@ class _ShadowPredicate extends _PaintPredicate { } class _DrawImagePaintPredicate extends _DrawCommandPaintPredicate { - _DrawImagePaintPredicate( - {this.image, - this.x, - this.y, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}) - : super( - #drawImage, - 'an image', - 3, - 2, - color: color, - strokeWidth: strokeWidth, - hasMaskFilter: hasMaskFilter, - style: style, - ); + _DrawImagePaintPredicate({ + this.image, + this.x, + this.y, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }) : super( + #drawImage, + 'an image', + 3, + 2, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); final ui.Image? image; final double? x; @@ -1710,24 +1771,24 @@ class _DrawImagePaintPredicate extends _DrawCommandPaintPredicate { } class _DrawImageRectPaintPredicate extends _DrawCommandPaintPredicate { - _DrawImageRectPaintPredicate( - {this.image, - this.source, - this.destination, - Color? color, - double? strokeWidth, - bool? hasMaskFilter, - PaintingStyle? style}) - : super( - #drawImageRect, - 'an image', - 4, - 3, - color: color, - strokeWidth: strokeWidth, - hasMaskFilter: hasMaskFilter, - style: style, - ); + _DrawImageRectPaintPredicate({ + this.image, + this.source, + this.destination, + Color? color, + double? strokeWidth, + bool? hasMaskFilter, + PaintingStyle? style, + }) : super( + #drawImageRect, + 'an image', + 4, + 3, + color: color, + strokeWidth: strokeWidth, + hasMaskFilter: hasMaskFilter, + style: style, + ); final ui.Image? image; final Rect? source; @@ -1784,8 +1845,10 @@ class _SomethingPaintPredicate extends _PaintPredicate { throw 'It called $currentCall, which was not a method, when the paint pattern expected a method call'; } testedAllCalls = !call.moveNext(); - } while (!_runPredicate(currentCall.invocation.memberName, - currentCall.invocation.positionalArguments)); + } while (!_runPredicate( + currentCall.invocation.memberName, + currentCall.invocation.positionalArguments, + )); } bool _runPredicate(Symbol methodName, List arguments) { @@ -1813,8 +1876,10 @@ class _EverythingPaintPredicate extends _PaintPredicate { if (!currentCall.invocation.isMethod) { throw 'It called $currentCall, which was not a method, when the paint pattern expected a method call'; } - if (!_runPredicate(currentCall.invocation.memberName, - currentCall.invocation.positionalArguments)) { + if (!_runPredicate( + currentCall.invocation.memberName, + currentCall.invocation.positionalArguments, + )) { throw 'It painted something that the predicate passed to an "everything" step ' 'in the paint pattern considered incorrect.\n'; } diff --git a/test/recording_canvas.dart b/test/recording_canvas.dart index 8ff6abe4..4629139a 100644 --- a/test/recording_canvas.dart +++ b/test/recording_canvas.dart @@ -66,16 +66,20 @@ class TestRecordCanvas implements Canvas { @override void save() { _saveCount += 1; - invocations - .add(RecordInvocation(_MethodCall(#save), stack: StackTrace.current)); + invocations.add( + RecordInvocation(_MethodCall(#save), stack: StackTrace.current), + ); } @override void saveLayer(Rect? bounds, Paint paint) { _saveCount += 1; - invocations.add(RecordInvocation( + invocations.add( + RecordInvocation( _MethodCall(#saveLayer, [bounds, paint]), - stack: StackTrace.current)); + stack: StackTrace.current, + ), + ); } @override @@ -83,7 +87,8 @@ class TestRecordCanvas implements Canvas { _saveCount -= 1; assert(_saveCount >= 0); invocations.add( - RecordInvocation(_MethodCall(#restore), stack: StackTrace.current)); + RecordInvocation(_MethodCall(#restore), stack: StackTrace.current), + ); } @override @@ -93,8 +98,7 @@ class TestRecordCanvas implements Canvas { } /// A [PaintingContext] for tests that use [TestRecordingCanvas]. -class TestRecordPaintingContext extends ClipContext - implements PaintingContext { +class TestRecordPaintingContext extends ClipContext implements PaintingContext { /// Creates a [PaintingContext] for tests that use [TestRecordingCanvas]. TestRecordPaintingContext(this.canvas); @@ -115,8 +119,12 @@ class TestRecordPaintingContext extends ClipContext Clip clipBehavior = Clip.hardEdge, ClipRectLayer? oldLayer, }) { - clipRectAndPaint(clipRect.shift(offset), clipBehavior, - clipRect.shift(offset), () => painter(this, offset)); + clipRectAndPaint( + clipRect.shift(offset), + clipBehavior, + clipRect.shift(offset), + () => painter(this, offset), + ); return null; } @@ -130,8 +138,12 @@ class TestRecordPaintingContext extends ClipContext Clip clipBehavior = Clip.antiAlias, ClipRRectLayer? oldLayer, }) { - clipRRectAndPaint(clipRRect.shift(offset), clipBehavior, - bounds.shift(offset), () => painter(this, offset)); + clipRRectAndPaint( + clipRRect.shift(offset), + clipBehavior, + bounds.shift(offset), + () => painter(this, offset), + ); return null; } @@ -145,8 +157,12 @@ class TestRecordPaintingContext extends ClipContext Clip clipBehavior = Clip.antiAlias, ClipPathLayer? oldLayer, }) { - clipPathAndPaint(clipPath.shift(offset), clipBehavior, bounds.shift(offset), - () => painter(this, offset)); + clipPathAndPaint( + clipPath.shift(offset), + clipBehavior, + bounds.shift(offset), + () => painter(this, offset), + ); return null; } diff --git a/test/selectors/date_picker_test.dart b/test/selectors/date_picker_test.dart index f0996546..3cc477c3 100644 --- a/test/selectors/date_picker_test.dart +++ b/test/selectors/date_picker_test.dart @@ -5,107 +5,105 @@ import 'package:macos_ui/macos_ui.dart'; void main() { group('MacosDatePicker tests', () { - testWidgets( - 'Textual MacosDatePicker renders the expected initial date', - (tester) async { - final initialDate = DateTime.now().add(const Duration(days: 30)); - await tester.pumpWidget( - MacosApp( - home: MacosWindow( - disableWallpaperTinting: true, - child: MacosScaffold( - children: [ - ContentArea( - builder: (context, _) { - return Center( - child: MacosDatePicker( - onDateChanged: (date) {}, - initialDate: initialDate, - style: DatePickerStyle.textual, - ), - ); - }, - ), - ], - ), + testWidgets('Textual MacosDatePicker renders the expected initial date', ( + tester, + ) async { + final initialDate = DateTime.now().add(const Duration(days: 30)); + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + disableWallpaperTinting: true, + child: MacosScaffold( + children: [ + ContentArea( + builder: (context, _) { + return Center( + child: MacosDatePicker( + onDateChanged: (date) {}, + initialDate: initialDate, + style: DatePickerStyle.textual, + ), + ); + }, + ), + ], ), ), - ); + ), + ); - expect(find.text('/'), findsNWidgets(2)); - expect(find.text('${initialDate.year}'), findsOneWidget); - if (initialDate.month == initialDate.day) { - expect(find.text('${initialDate.day}'), findsNWidgets(2)); - expect(find.text('${initialDate.month}'), findsNWidgets(2)); - } else { - expect(find.text('${initialDate.day}'), findsOneWidget); - expect(find.text('${initialDate.month}'), findsOneWidget); - } - }, - ); + expect(find.text('/'), findsNWidgets(2)); + expect(find.text('${initialDate.year}'), findsOneWidget); + if (initialDate.month == initialDate.day) { + expect(find.text('${initialDate.day}'), findsNWidgets(2)); + expect(find.text('${initialDate.month}'), findsNWidgets(2)); + } else { + expect(find.text('${initialDate.day}'), findsOneWidget); + expect(find.text('${initialDate.month}'), findsOneWidget); + } + }); - testWidgets( - "Textual MacosDatePicker renders the today's date by default", - (tester) async { - final today = DateTime.now(); - await tester.pumpWidget( - MacosApp( - home: MacosWindow( - disableWallpaperTinting: true, - child: MacosScaffold( - children: [ - ContentArea( - builder: (context, _) { - return Center( - child: MacosDatePicker( - onDateChanged: (date) {}, - style: DatePickerStyle.textual, - ), - ); - }, - ), - ], - ), + testWidgets("Textual MacosDatePicker renders the today's date by default", ( + tester, + ) async { + final today = DateTime.now(); + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + disableWallpaperTinting: true, + child: MacosScaffold( + children: [ + ContentArea( + builder: (context, _) { + return Center( + child: MacosDatePicker( + onDateChanged: (date) {}, + style: DatePickerStyle.textual, + ), + ); + }, + ), + ], ), ), - ); + ), + ); - expect(find.text('/'), findsNWidgets(2)); - expect(find.text('${today.year}'), findsOneWidget); - if (today.month == today.day) { - expect(find.text('${today.day}'), findsNWidgets(2)); - expect(find.text('${today.month}'), findsNWidgets(2)); - } else { - expect(find.text('${today.day}'), findsOneWidget); - expect(find.text('${today.month}'), findsOneWidget); - } - }, - ); + expect(find.text('/'), findsNWidgets(2)); + expect(find.text('${today.year}'), findsOneWidget); + if (today.month == today.day) { + expect(find.text('${today.day}'), findsNWidgets(2)); + expect(find.text('${today.month}'), findsNWidgets(2)); + } else { + expect(find.text('${today.day}'), findsOneWidget); + expect(find.text('${today.month}'), findsOneWidget); + } + }); testWidgets( 'Textual MacosDatePicker renders the date with respect to "dateFormat" property', (tester) async { renderWidget(String dateFormat) => MacosApp( - home: MacosWindow( - disableWallpaperTinting: true, - child: MacosScaffold( - children: [ - ContentArea( - builder: (context, _) { - return Center( - child: MacosDatePicker( - initialDate: DateTime.parse('2023-04-01'), - onDateChanged: (date) {}, - dateFormat: dateFormat, - style: DatePickerStyle.textual, - ), - ); - }, - ), - ], + home: MacosWindow( + disableWallpaperTinting: true, + child: MacosScaffold( + children: [ + ContentArea( + builder: (context, _) { + return Center( + child: MacosDatePicker( + initialDate: DateTime.parse('2023-04-01'), + onDateChanged: (date) {}, + dateFormat: dateFormat, + style: DatePickerStyle.textual, + ), + ); + }, ), - ), - ); + ], + ), + ), + ); getNthTextFromWidget(int index) => (find.byType(Text).at(index).evaluate().first.widget as Text).data @@ -137,175 +135,165 @@ void main() { }, ); - testWidgets( - 'Can select the date field element and change the value', - (tester) async { - final today = DateTime.now(); - await tester.pumpWidget( - MacosApp( - home: MacosWindow( - child: MacosScaffold( - children: [ - ContentArea( - builder: (context, _) { - return Center( - child: MacosDatePicker( - onDateChanged: (date) {}, - ), - ); - }, - ), - ], - ), + testWidgets('Can select the date field element and change the value', ( + tester, + ) async { + final today = DateTime.now(); + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + children: [ + ContentArea( + builder: (context, _) { + return Center( + child: MacosDatePicker(onDateChanged: (date) {}), + ); + }, + ), + ], ), ), - ); + ), + ); - int day = today.day; - final dayFieldElement = find.text('${today.day}').first; - final upCaretControl = find.byType(CustomPaint).first; - final downCaretControl = find.byType(CustomPaint).last; - await tester.tap(dayFieldElement); - await tester.pumpAndSettle(); - await tester.tap(upCaretControl); - await tester.pumpAndSettle(); - day++; - expect(day, today.day + 1); - await tester.tap(downCaretControl); - await tester.pumpAndSettle(); - day--; - expect(day, today.day); - await tester.tap(downCaretControl); - await tester.pumpAndSettle(); - day--; - expect(day, today.day - 1); - }, - ); + int day = today.day; + final dayFieldElement = find.text('${today.day}').first; + final upCaretControl = find.byType(CustomPaint).first; + final downCaretControl = find.byType(CustomPaint).last; + await tester.tap(dayFieldElement); + await tester.pumpAndSettle(); + await tester.tap(upCaretControl); + await tester.pumpAndSettle(); + day++; + expect(day, today.day + 1); + await tester.tap(downCaretControl); + await tester.pumpAndSettle(); + day--; + expect(day, today.day); + await tester.tap(downCaretControl); + await tester.pumpAndSettle(); + day--; + expect(day, today.day - 1); + }); - testWidgets( - 'Can select the month field element and change the value', - (tester) async { - final today = DateTime.now(); - await tester.pumpWidget( - MacosApp( - home: MacosWindow( - child: MacosScaffold( - children: [ - ContentArea( - builder: (context, _) { - return Center( - child: MacosDatePicker( - onDateChanged: (date) {}, - ), - ); - }, - ), - ], - ), + testWidgets('Can select the month field element and change the value', ( + tester, + ) async { + final today = DateTime.now(); + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + children: [ + ContentArea( + builder: (context, _) { + return Center( + child: MacosDatePicker(onDateChanged: (date) {}), + ); + }, + ), + ], ), ), - ); + ), + ); - int month = today.month; - final monthFieldElement = find.text('${today.month}').first; - final upCaretControl = find.byType(CustomPaint).first; - final downCaretControl = find.byType(CustomPaint).last; - await tester.tap(monthFieldElement); - await tester.pumpAndSettle(); - await tester.tap(upCaretControl); - await tester.pumpAndSettle(); - month++; - expect(month, today.month + 1); - await tester.tap(downCaretControl); - await tester.pumpAndSettle(); - month--; - expect(month, today.month); - await tester.tap(downCaretControl); - await tester.pumpAndSettle(); - month--; - expect(month, today.month - 1); - }, - ); + int month = today.month; + final monthFieldElement = find.text('${today.month}').first; + final upCaretControl = find.byType(CustomPaint).first; + final downCaretControl = find.byType(CustomPaint).last; + await tester.tap(monthFieldElement); + await tester.pumpAndSettle(); + await tester.tap(upCaretControl); + await tester.pumpAndSettle(); + month++; + expect(month, today.month + 1); + await tester.tap(downCaretControl); + await tester.pumpAndSettle(); + month--; + expect(month, today.month); + await tester.tap(downCaretControl); + await tester.pumpAndSettle(); + month--; + expect(month, today.month - 1); + }); - testWidgets( - 'Can select the month field element and change the value', - (tester) async { - final today = DateTime.now(); - await tester.pumpWidget( - MacosApp( - home: MacosWindow( - child: MacosScaffold( - children: [ - ContentArea( - builder: (context, _) { - return Center( - child: MacosDatePicker( - onDateChanged: (date) {}, - ), - ); - }, - ), - ], - ), + testWidgets('Can select the month field element and change the value', ( + tester, + ) async { + final today = DateTime.now(); + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + children: [ + ContentArea( + builder: (context, _) { + return Center( + child: MacosDatePicker(onDateChanged: (date) {}), + ); + }, + ), + ], ), ), - ); + ), + ); - int year = today.year; - final yearFieldElement = find.text('${today.year}'); - final upCaretControl = find.byType(CustomPaint).first; - final downCaretControl = find.byType(CustomPaint).last; - await tester.tap(yearFieldElement); - await tester.pumpAndSettle(); - await tester.tap(upCaretControl); - await tester.pumpAndSettle(); - year++; - expect(year, today.year + 1); - await tester.tap(downCaretControl); - await tester.pumpAndSettle(); - year--; - expect(year, today.year); - await tester.tap(downCaretControl); - await tester.pumpAndSettle(); - year--; - expect(year, today.year - 1); - }, - ); + int year = today.year; + final yearFieldElement = find.text('${today.year}'); + final upCaretControl = find.byType(CustomPaint).first; + final downCaretControl = find.byType(CustomPaint).last; + await tester.tap(yearFieldElement); + await tester.pumpAndSettle(); + await tester.tap(upCaretControl); + await tester.pumpAndSettle(); + year++; + expect(year, today.year + 1); + await tester.tap(downCaretControl); + await tester.pumpAndSettle(); + year--; + expect(year, today.year); + await tester.tap(downCaretControl); + await tester.pumpAndSettle(); + year--; + expect(year, today.year - 1); + }); - testWidgets( - 'The selected calendar day matches the expected value', - (tester) async { - final today = DateTime.now(); - int selectedDay = 0; - await tester.pumpWidget( - MacosApp( - home: MacosWindow( - child: MacosScaffold( - children: [ - ContentArea( - builder: (context, _) { - return Center( - child: MacosDatePicker( - onDateChanged: (date) { - selectedDay = date.day; - }, - ), - ); - }, - ), - ], - ), + testWidgets('The selected calendar day matches the expected value', ( + tester, + ) async { + final today = DateTime.now(); + int selectedDay = 0; + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + children: [ + ContentArea( + builder: (context, _) { + return Center( + child: MacosDatePicker( + onDateChanged: (date) { + selectedDay = date.day; + }, + ), + ); + }, + ), + ], ), ), - ); + ), + ); - int dayToFind = today.day == 21 ? 22 : 21; - final dayToSelect = find.text(dayToFind.toString()); - await tester.tap(dayToSelect); - await tester.pumpAndSettle(); - expect(selectedDay, dayToFind); - }, - ); + int dayToFind = today.day == 21 ? 22 : 21; + final dayToSelect = find.text(dayToFind.toString()); + await tester.tap(dayToSelect); + await tester.pumpAndSettle(); + expect(selectedDay, dayToFind); + }); testWidgets( 'Can change the month by clicking the left and right calendar view controls', @@ -480,9 +468,7 @@ void main() { (tester) async { await tester.pumpWidget( MacosApp( - supportedLocales: const [ - Locale('en', 'PL'), - ], + supportedLocales: const [Locale('en', 'PL')], home: MacosWindow( child: MacosScaffold( children: [ diff --git a/test/src/theme/macos_theme_test.dart b/test/src/theme/macos_theme_test.dart index 92df987c..3d6da80b 100644 --- a/test/src/theme/macos_theme_test.dart +++ b/test/src/theme/macos_theme_test.dart @@ -21,28 +21,24 @@ void main() { testWidgets('macos theme MacosThemeData equality 3', (tester) async { final macosThemeData1 = MacosThemeData( - helpButtonTheme: const HelpButtonThemeData( - color: MacosColors.appleRed, - )); + helpButtonTheme: const HelpButtonThemeData(color: MacosColors.appleRed), + ); final macosThemeData2 = MacosThemeData( - helpButtonTheme: const HelpButtonThemeData( - color: MacosColors.appleGreen, - )); + 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, - )); + helpButtonTheme: const HelpButtonThemeData(color: MacosColors.appleRed), + ); final macosThemeData2 = MacosThemeData( - helpButtonTheme: const HelpButtonThemeData( - color: MacosColors.appleRed, - )); + 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 index 9524a6d2..8ee599b5 100644 --- a/test/src/theme/typography_test.dart +++ b/test/src/theme/typography_test.dart @@ -22,14 +22,10 @@ void main() { testWidgets('typography equality 3', (tester) async { final typography1 = Typography( - englishLike: const TextTheme( - bodyLarge: TextStyle(fontSize: 10), - ), + englishLike: const TextTheme(bodyLarge: TextStyle(fontSize: 10)), ); final typography2 = Typography( - englishLike: const TextTheme( - bodyLarge: TextStyle(fontSize: 10), - ), + englishLike: const TextTheme(bodyLarge: TextStyle(fontSize: 10)), ); expect(typography1, equals(typography2)); @@ -37,14 +33,10 @@ void main() { testWidgets('typography equality 4', (tester) async { final typography1 = Typography( - englishLike: const TextTheme( - bodyLarge: TextStyle(fontSize: 10), - ), + englishLike: const TextTheme(bodyLarge: TextStyle(fontSize: 10)), ); final typography2 = Typography( - englishLike: const TextTheme( - bodyLarge: TextStyle(fontSize: 12), - ), + englishLike: const TextTheme(bodyLarge: TextStyle(fontSize: 12)), ); expect(typography1, isNot(equals(typography2))); @@ -52,14 +44,10 @@ void main() { testWidgets('typography equality 5', (tester) async { final typography1 = Typography( - englishLike: const TextTheme( - headlineLarge: TextStyle(fontSize: 10), - ), + englishLike: const TextTheme(headlineLarge: TextStyle(fontSize: 10)), ); final typography2 = Typography( - englishLike: const TextTheme( - headlineLarge: TextStyle(fontSize: 12), - ), + englishLike: const TextTheme(headlineLarge: TextStyle(fontSize: 12)), ); expect(typography1, isNot(equals(typography2))); @@ -67,14 +55,10 @@ void main() { testWidgets('typography equality 6', (tester) async { final typography1 = Typography( - englishLike: const TextTheme( - headlineLarge: TextStyle(fontSize: 10), - ), + englishLike: const TextTheme(headlineLarge: TextStyle(fontSize: 10)), ); final typography2 = Typography( - englishLike: const TextTheme( - headlineLarge: TextStyle(fontSize: 10), - ), + englishLike: const TextTheme(headlineLarge: TextStyle(fontSize: 10)), ); expect(typography1, equals(typography2)); diff --git a/test/theme/help_button_theme_test.dart b/test/theme/help_button_theme_test.dart index 1e127f80..e7ed2e39 100644 --- a/test/theme/help_button_theme_test.dart +++ b/test/theme/help_button_theme_test.dart @@ -6,15 +6,21 @@ import 'package:macos_ui/src/library.dart'; void main() { group('HelpButtonTheme tests', () { test('lerps from light to dark', () { - final actual = - HelpButtonThemeData.lerp(_helpButtonTheme, _helpButtonThemeDark, 1); + final actual = HelpButtonThemeData.lerp( + _helpButtonTheme, + _helpButtonThemeDark, + 1, + ); expect(actual, _helpButtonThemeDark); }); test('lerps from dark to light', () { - final actual = - HelpButtonThemeData.lerp(_helpButtonThemeDark, _helpButtonTheme, 1); + final actual = HelpButtonThemeData.lerp( + _helpButtonThemeDark, + _helpButtonTheme, + 1, + ); expect(actual, _helpButtonTheme); }); @@ -42,13 +48,10 @@ void main() { .map((node) => node.toString()) .toList(); - expect( - description, - [ - 'color: MacosColor(0xff0433ff)', - 'disabledColor: MacosColor(0xff8e8e93)', - ], - ); + expect(description, [ + 'color: MacosColor(alpha: 1.0000, red: 0.0157, green: 0.2000, blue: 1.0000, colorSpace: ColorSpace.sRGB)', + 'disabledColor: MacosColor(alpha: 1.0000, red: 0.5569, green: 0.5569, blue: 0.5765, colorSpace: ColorSpace.sRGB)', + ]); }); testWidgets('Default values in widget tree', (tester) async { diff --git a/test/theme/icon_button_theme_test.dart b/test/theme/icon_button_theme_test.dart index 7d42593e..065e3f5e 100644 --- a/test/theme/icon_button_theme_test.dart +++ b/test/theme/icon_button_theme_test.dart @@ -44,18 +44,15 @@ void main() { .map((node) => node.toString()) .toList(); - expect( - description, - [ - 'backgroundColor: null', - 'disabledColor: null', - 'hoverColor: null', - 'shape: null', - 'borderRadius: null', - 'boxConstraints: null', - 'padding: null', - ], - ); + expect(description, [ + 'backgroundColor: null', + 'disabledColor: null', + 'hoverColor: null', + 'shape: null', + 'borderRadius: null', + 'boxConstraints: null', + 'padding: null', + ]); }); testWidgets('Default values in widget tree', (tester) async { diff --git a/test/theme/icon_theme_test.dart b/test/theme/icon_theme_test.dart index 7efe67fa..b2fa068a 100644 --- a/test/theme/icon_theme_test.dart +++ b/test/theme/icon_theme_test.dart @@ -5,10 +5,7 @@ import 'package:macos_ui/src/library.dart'; void main() { test('copyWith, ==, hashcode basics', () { - expect( - const MacosIconThemeData(), - const MacosIconThemeData().copyWith(), - ); + expect(const MacosIconThemeData(), const MacosIconThemeData().copyWith()); expect( const MacosIconThemeData().hashCode, const MacosIconThemeData().copyWith().hashCode, @@ -16,21 +13,13 @@ void main() { }); test('lerps from light to dark', () { - final actual = MacosIconThemeData.lerp( - _iconTheme, - _iconThemeDark, - 1, - ); + final actual = MacosIconThemeData.lerp(_iconTheme, _iconThemeDark, 1); expect(actual, _iconThemeDark); }); test('lerps from dark to light', () { - final actual = MacosIconThemeData.lerp( - _iconThemeDark, - _iconTheme, - 1, - ); + final actual = MacosIconThemeData.lerp(_iconThemeDark, _iconTheme, 1); expect(actual, _iconTheme); }); @@ -48,14 +37,11 @@ void main() { .map((node) => node.toString()) .toList(); - expect( - description, - [ - 'MacosColor: MacosColor(0xffffffff)', - 'opacity: 0.0', - 'size: 20.0', - ], - ); + expect(description, [ + 'MacosColor: MacosColor(alpha: 1.0000, red: 1.0000, green: 1.0000, blue: 1.0000, colorSpace: ColorSpace.sRGB)', + 'opacity: 0.0', + 'size: 20.0', + ]); }); testWidgets('Default values in widget tree', (tester) async { @@ -69,9 +55,7 @@ void main() { ContentArea( builder: (context, _) { capturedContext = context; - return const MacosIcon( - CupertinoIcons.add, - ); + return const MacosIcon(CupertinoIcons.add); }, ), ], @@ -81,15 +65,11 @@ void main() { ); final theme = MacosIconTheme.of(capturedContext); - expect(theme.color, const MacosColor(0xbe0981ff)); + expect(theme.color, const MacosColor.fromRGBO(9, 129, 255, 0.749)); expect(theme.size, 20); }); } -const _iconTheme = MacosIconThemeData( - color: MacosColors.black, -); +const _iconTheme = MacosIconThemeData(color: MacosColors.black); -const _iconThemeDark = MacosIconThemeData( - color: MacosColors.white, -); +const _iconThemeDark = MacosIconThemeData(color: MacosColors.white); diff --git a/test/theme/popup_button_theme_test.dart b/test/theme/popup_button_theme_test.dart index f704da09..aae65538 100644 --- a/test/theme/popup_button_theme_test.dart +++ b/test/theme/popup_button_theme_test.dart @@ -51,14 +51,11 @@ void main() { .map((node) => node.toString()) .toList(); - expect( - description, - [ - 'highlightColor: MacosColor(0xff8e8e93)', - 'backgroundColor: MacosColor(0xff0433ff)', - 'popupColor: Color(0x19000000)', - ], - ); + expect(description, [ + 'highlightColor: MacosColor(alpha: 1.0000, red: 0.5569, green: 0.5569, blue: 0.5765, colorSpace: ColorSpace.sRGB)', + 'backgroundColor: MacosColor(alpha: 1.0000, red: 0.0157, green: 0.2000, blue: 1.0000, colorSpace: ColorSpace.sRGB)', + 'popupColor: Color(alpha: 0.1000, red: 0.0000, green: 0.0000, blue: 0.0000, colorSpace: ColorSpace.sRGB)', + ]); }); testWidgets('Default values in widget tree', (tester) async { @@ -80,11 +77,12 @@ void main() { }, items: ['One', 'Two', 'Three', 'Four'] .map>((String value) { - return MacosPopupMenuItem( - value: value, - child: Text(value), - ); - }).toList(), + return MacosPopupMenuItem( + value: value, + child: Text(value), + ); + }) + .toList(), ); }, ), @@ -96,7 +94,10 @@ void main() { final theme = MacosPopupButtonTheme.of(capturedContext); expect(theme.backgroundColor, const Color(0xffffffff)); - expect(theme.highlightColor, const MacosColor(0xbe0981ff)); + expect( + theme.highlightColor, + const MacosColor.fromRGBO(9, 129, 255, 0.749), + ); 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 a082b42e..27b05bb6 100644 --- a/test/theme/pulldown_button_theme_test.dart +++ b/test/theme/pulldown_button_theme_test.dart @@ -50,15 +50,12 @@ void main() { .map((node) => node.toString()) .toList(); - expect( - description, - [ - 'highlightColor: MacosColor(0xff8e8e93)', - 'backgroundColor: MacosColor(0xff0433ff)', - 'pulldownColor: Color(0x19000000)', - 'iconColor: MacosColor(0xff00f900)', - ], - ); + expect(description, [ + 'highlightColor: MacosColor(alpha: 1.0000, red: 0.5569, green: 0.5569, blue: 0.5765, colorSpace: ColorSpace.sRGB)', + 'backgroundColor: MacosColor(alpha: 1.0000, red: 0.0157, green: 0.2000, blue: 1.0000, colorSpace: ColorSpace.sRGB)', + 'pulldownColor: Color(alpha: 0.1000, red: 0.0000, green: 0.0000, blue: 0.0000, colorSpace: ColorSpace.sRGB)', + 'iconColor: MacosColor(alpha: 1.0000, red: 0.0000, green: 0.9765, blue: 0.0000, colorSpace: ColorSpace.sRGB)', + ]); }); testWidgets('Default values in widget tree', (tester) async { @@ -97,7 +94,10 @@ void main() { final theme = MacosPulldownButtonTheme.of(capturedContext); expect(theme.backgroundColor, const Color(0xffffffff)); - expect(theme.highlightColor, const MacosColor(0xbe0981ff)); + expect( + theme.highlightColor, + const MacosColor.fromRGBO(9, 129, 255, 0.749), + ); expect(theme.pulldownColor, const Color(0xfff2f2f7)); }); }); diff --git a/test/theme/scrollbar_theme_test.dart b/test/theme/scrollbar_theme_test.dart index 39e3c156..6b7132a9 100644 --- a/test/theme/scrollbar_theme_test.dart +++ b/test/theme/scrollbar_theme_test.dart @@ -45,10 +45,7 @@ void main() { .map((node) => node.toString()) .toList(); - expect( - description, - [], - ); + expect(description, []); }); } diff --git a/test/theme/search_field_theme_test.dart b/test/theme/search_field_theme_test.dart index 39aa577f..bb7294b2 100644 --- a/test/theme/search_field_theme_test.dart +++ b/test/theme/search_field_theme_test.dart @@ -48,13 +48,10 @@ void main() { .map((node) => node.toString()) .toList(); - expect( - description, - [ - 'highlightColor: Color(0xff007aff)', - 'resultsBackgroundColor: Color(0xfff2f2f7)', - ], - ); + expect(description, [ + 'highlightColor: Color(alpha: 1.0000, red: 0.0000, green: 0.4784, blue: 1.0000, colorSpace: ColorSpace.sRGB)', + 'resultsBackgroundColor: Color(alpha: 1.0000, red: 0.9490, green: 0.9490, blue: 0.9686, colorSpace: ColorSpace.sRGB)', + ]); }); testWidgets('Default values in widget tree', (tester) async { @@ -68,9 +65,7 @@ void main() { ContentArea( builder: (context, _) { capturedContext = context; - return const Center( - child: MacosSearchField(), - ); + return const Center(child: MacosSearchField()); }, ), ], @@ -80,7 +75,10 @@ void main() { ); final theme = MacosSearchFieldTheme.of(capturedContext); - expect(theme.highlightColor, const MacosColor(0xbe0981ff)); + expect( + theme.highlightColor, + const MacosColor.fromRGBO(9, 129, 255, 0.749), + ); expect(theme.resultsBackgroundColor, const Color(0xfff2f2f7)); }); }); diff --git a/test/theme/tooltip_theme_test.dart b/test/theme/tooltip_theme_test.dart index cb4bcb79..c56ebb02 100644 --- a/test/theme/tooltip_theme_test.dart +++ b/test/theme/tooltip_theme_test.dart @@ -44,40 +44,29 @@ void main() { .map((node) => node.toString()) .toList(); - expect( - description, - [ - 'height: null', - 'verticalOffset: null', - 'padding: null', - 'margin: null', - 'decoration: null', - 'waitDuration: null', - 'showDuration: null', - 'textStyle: null', - ], - ); + expect(description, [ + 'height: null', + 'verticalOffset: null', + 'padding: null', + 'margin: null', + 'decoration: null', + 'waitDuration: null', + 'showDuration: null', + 'textStyle: null', + ]); }); } const _tooltipThemeData = MacosTooltipThemeData( - decoration: BoxDecoration( - color: Colors.red, - ), + decoration: BoxDecoration(color: Colors.red), margin: EdgeInsets.all(6), padding: EdgeInsets.all(6), - textStyle: TextStyle( - color: Colors.black, - ), + textStyle: TextStyle(color: Colors.black), ); const _tooltipThemeDataDark = MacosTooltipThemeData( - decoration: BoxDecoration( - color: Colors.blue, - ), + decoration: BoxDecoration(color: Colors.blue), margin: EdgeInsets.all(8), padding: EdgeInsets.all(8), - textStyle: TextStyle( - color: Colors.white, - ), + textStyle: TextStyle(color: Colors.white), );