diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index af69bfd4..bb71af66 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -7,9 +7,7 @@
## Pre-launch Checklist
-- [ ] I have run `dartfmt` on all changed files
- [ ] I have incremented the package version as appropriate and updated `CHANGELOG.md` with my changes
- [ ] I have added/updated relevant documentation
- [ ] I have run "optimize/organize imports" on all changed files
-- [ ] I have addressed all analyzer warnings as best I could
-
\ No newline at end of file
+- [ ] I have addressed all analyzer warnings as best I could
\ No newline at end of file
diff --git a/.github/workflows/flutter_analysis.yml b/.github/workflows/flutter_analysis.yml
index 29e896de..0187a10d 100644
--- a/.github/workflows/flutter_analysis.yml
+++ b/.github/workflows/flutter_analysis.yml
@@ -10,13 +10,27 @@ jobs:
- name: Install Flutter
uses: subosito/flutter-action@v2
with:
- channel: stable
+ channel: master
- name: Install dependencies
run: flutter pub get
+ - uses: actions/checkout@v3
+ - name: Set up git
+ run: |
+ git config user.name "GitHub Actions Bot"
+ git config user.email "<>"
+
- name: Format code
- run: dart format --set-exit-if-changed .
+ run: |
+ dart format .
+ if [ $? -eq 1 ]; then
+ git add .
+ git commit -m "chore: formatting corrections"
+ git push
+ echo "Code has been formatted and changes have been committed and pushed."
+ fi
+ echo "All code is properly formatted!"
- name: Analyze code
run: flutter analyze --fatal-infos .
diff --git a/.github/workflows/pana_analysis.yml b/.github/workflows/pana_analysis.yml
index a32d6cb3..9f90d17e 100644
--- a/.github/workflows/pana_analysis.yml
+++ b/.github/workflows/pana_analysis.yml
@@ -4,6 +4,7 @@ on: [pull_request, workflow_dispatch]
jobs:
package-analysis:
runs-on: ubuntu-latest
+ if: github.base_ref != 'customer_testing'
steps:
- uses: actions/checkout@v3
diff --git a/.gitignore b/.gitignore
index 70efb322..fcfa202c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,7 +15,7 @@
*.iws
.idea/
-.vscode/launch.json
+.vscode
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 994154c1..15c38001 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,13 @@
+## [1.11.1]
+* Fixed an issue where the `MacosSearchField` would not perform an action when an item was selected.
+
+## [1.11.0]
+* 🚨 Breaking Changes 🚨
+* `ResizablePane` can now be vertically resized
+ * `ResizablePane.startWidth` has been changed to `ResizablePane.startSize`
+ * `ResizablePane.minWidth` has been changed to `ResizablePane.minSize`
+ * `ResizablePane.maxWidth` has been changed to `ResizablePane.maxSize`
+
## [1.10.0]
🚨 Breaking Changes 🚨
* `MacosScrollbar` has been completely overhauled and now resembles the native macOS scrollbar in appearance and
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7b6b77d0..bed82a0e 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -18,16 +18,12 @@ This repository uses [conventional commits](https://www.conventionalcommits.org/
As mentioned above, all pull requests should target `dev`.
#### Pre-launch script
-Before opening your pull request, run the `pr_prelaunch_tasks.sh` script to ensure that your changes meet the
-following requirements:
+Before opening your pull request, please ensure that the following
+following requirements are met:
* All code is properly formatted
* There are no Dart analysis warnings
* All tests pass
-If the format step of the script results in changes, the script will make those change, commit them, and prompt you to push the commit.
-
-If the `dart fix` step results in changes, the script will make those changes, commit them, and prompt you to push the commit.
-
Pull requests should **always** be merged via GitHub and not via command-line.
### Versioning
diff --git a/README.md b/README.md
index 663d9d65..1a1a1451 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,10 @@ Guides, codelabs, and other documentation can be found at https://macosui.dev
-## 🚨 Usage notes
+## 🚨 Usage notes
+### 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
pub.dev shows that `macos_ui` only supports macOS. This is because `macos_ui` calls some native code, and therefore
@@ -50,6 +53,7 @@ should avoid allowing your application window to be resized below the height of
- [Layout](#layout)
- [MacosWindow](#macoswindow)
+ - [Sidebar](#sidebar)
- [MacosScaffold](#macosscaffold)
- [Modern Window Look](#modern-window-look)
- [ToolBar](#toolbar)
@@ -148,6 +152,56 @@ your `MacosScaffold` in a `Builder` widget in order for this to work properly.
+## Sidebar
+A sidebar enables app navigation and provides quick access to top-level collections of content in your app.
+
+Sidebars may be placed at the left or right of your app. To place a sidebar on the left, use the `MacosWindow.sidebar` property. To place a sidebar on the right, use the `MacosWindow.endSidebar` property.
+
+
+
+Example usage:
+
+```dart
+int pageIndex = 0;
+
+...
+
+MacosWindow(
+ sidebar: Sidebar(
+ minWidth: 200,
+ builder: (context, scrollController) {
+ return SidebarItems(
+ currentIndex: pageIndex,
+ scrollController: scrollController,
+ itemSize: SidebarItemSize.large,
+ onChanged: (i) {
+ setState(() => pageIndex = i);
+ },
+ items: const [
+ SidebarItem(
+ label: Text('Page One'),
+ ),
+ SidebarItem(
+ label: Text('Page Two'),
+ ),
+ ],
+ );
+ },
+ ),
+ endSidebar: Sidebar(
+ startWidth: 200,
+ minWidth: 200,
+ maxWidth: 300,
+ shownByDefault: false,
+ builder: (context, _) {
+ return const Center(
+ child: Text('End Sidebar'),
+ );
+ },
+ ),
+),
+```
+
## MacosScaffold
The `MacosScaffold` is what you might call a "page".
@@ -355,7 +409,7 @@ CustomToolbarItem(
## MacosListTile
-A widget that aims to approximate the [ListTile] widget found in
+A widget that aims to approximate the [`ListTile`](https://api.flutter.dev/flutter/material/ListTile-class.html) widget found in
Flutter's material library.
![MacosListTile](https://imgur.com/pQB99M2.png)
@@ -862,10 +916,10 @@ You can set `discrete` to `true` to make it a discrete capacity indicator.
A slider is a control that lets people select a value from a continuous or discrete range of values by moving the slider thumb.
- Continuous | Discrete |
-|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| ![Continuous Slider Example](https://i.imgur.com/dc4YjoX.png) | ![Discrete Slider Example](https://i.imgur.com/KckOTUf.png) |
-| A horizontal slider where any value continuous value between a min and max can be selected | A horizontal slider where only discrete values between a min and max can be selected. Tick marks are often displayed to provide context. |
+ | Continuous | Discrete |
+ | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
+ | ![Continuous Slider Example](https://i.imgur.com/dc4YjoX.png) | ![Discrete Slider Example](https://i.imgur.com/KckOTUf.png) |
+ | A horizontal slider where any value continuous value between a min and max can be selected | A horizontal slider where only discrete values between a min and max can be selected. Tick marks are often displayed to provide context. |
Here's an example of how to create an interactive continuous slider:
diff --git a/example/.gitignore b/example/.gitignore
index 8b52fde8..4e8c3b2b 100644
--- a/example/.gitignore
+++ b/example/.gitignore
@@ -47,3 +47,4 @@ app.*.map.json
/android/app/release
/windows/
+linux/
diff --git a/example/lib/pages/buttons_page.dart b/example/lib/pages/buttons_page.dart
index dafc5ea2..6533484b 100644
--- a/example/lib/pages/buttons_page.dart
+++ b/example/lib/pages/buttons_page.dart
@@ -60,8 +60,8 @@ class _ButtonsPageState extends State {
),
children: [
ResizablePane(
- minWidth: 180,
- startWidth: 200,
+ minSize: 180,
+ startSize: 200,
windowBreakpoint: 700,
resizableSide: ResizableSide.right,
builder: (_, __) {
@@ -72,366 +72,394 @@ class _ButtonsPageState extends State {
),
ContentArea(
builder: (context, scrollController) {
- return SingleChildScrollView(
- controller: scrollController,
- padding: const EdgeInsets.all(20),
- child: Column(
- children: [
- const Text('MacosBackButton'),
- const SizedBox(height: 8),
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- MacosBackButton(
- onPressed: () => debugPrint('click'),
- fillColor: Colors.transparent,
- ),
- const SizedBox(width: 16.0),
- MacosBackButton(
- onPressed: () => debugPrint('click'),
- ),
- ],
- ),
- const SizedBox(height: 20),
- const Text('MacosDisclosureButton'),
- const SizedBox(height: 8),
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- MacosDisclosureButton(
- isPressed: isDisclosureButtonPressed,
- onPressed: () {
- debugPrint('click');
- setState(() {
- isDisclosureButtonPressed =
- !isDisclosureButtonPressed;
- });
- }),
- ],
- ),
- const SizedBox(height: 20),
- const Text('MacosIconButton'),
- const SizedBox(height: 8),
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- MacosIconButton(
- icon: const MacosIcon(
- CupertinoIcons.star_fill,
+ return Column(
+ children: [
+ Flexible(
+ fit: FlexFit.loose,
+ child: SingleChildScrollView(
+ controller: scrollController,
+ padding: const EdgeInsets.all(20),
+ child: Column(
+ children: [
+ const Text('MacosBackButton'),
+ const SizedBox(height: 8),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ MacosBackButton(
+ onPressed: () => debugPrint('click'),
+ fillColor: Colors.transparent,
+ ),
+ const SizedBox(width: 16.0),
+ MacosBackButton(
+ onPressed: () => debugPrint('click'),
+ ),
+ ],
),
- shape: BoxShape.rectangle,
- borderRadius: BorderRadius.circular(7),
- onPressed: () {},
- ),
- const SizedBox(width: 8),
- const MacosIconButton(
- icon: MacosIcon(
- CupertinoIcons.plus_app,
+ const SizedBox(height: 20),
+ const Text('MacosDisclosureButton'),
+ const SizedBox(height: 8),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ MacosDisclosureButton(
+ isPressed: isDisclosureButtonPressed,
+ onPressed: () {
+ debugPrint('click');
+ setState(() {
+ isDisclosureButtonPressed =
+ !isDisclosureButtonPressed;
+ });
+ }),
+ ],
),
- shape: BoxShape.circle,
- //onPressed: () {},
- ),
- const SizedBox(width: 8),
- MacosIconButton(
- icon: const MacosIcon(
- CupertinoIcons.minus_square,
+ const SizedBox(height: 20),
+ const Text('MacosIconButton'),
+ const SizedBox(height: 8),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ MacosIconButton(
+ 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,
+ ),
+ shape: BoxShape.circle,
+ //onPressed: () {},
+ ),
+ const SizedBox(width: 8),
+ MacosIconButton(
+ icon: const MacosIcon(
+ CupertinoIcons.minus_square,
+ ),
+ backgroundColor: Colors.transparent,
+ onPressed: () {},
+ ),
+ ],
),
- backgroundColor: Colors.transparent,
- onPressed: () {},
- ),
- ],
- ),
- const SizedBox(height: 20),
- const Text('PushButton'),
- const SizedBox(height: 8),
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- PushButton(
- buttonSize: ButtonSize.large,
- child: const Text('Large'),
- onPressed: () {
- MacosWindowScope.of(context).toggleSidebar();
- },
- ),
- const SizedBox(width: 20),
- PushButton(
- buttonSize: ButtonSize.small,
- child: const Text('Small'),
- onPressed: () {
- Navigator.of(context).push(
- MaterialPageRoute(
- builder: (_) {
- return MacosScaffold(
- toolBar: const ToolBar(
- title: Text('New page'),
- ),
- children: [
- ContentArea(
- builder: (context, _) {
- return Center(
- child: PushButton(
- buttonSize: ButtonSize.large,
- child: const Text('Go Back'),
- onPressed: () {
- Navigator.of(context).maybePop();
+ const SizedBox(height: 20),
+ const Text('PushButton'),
+ const SizedBox(height: 8),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ PushButton(
+ buttonSize: ButtonSize.large,
+ child: const Text('Large'),
+ onPressed: () {
+ MacosWindowScope.of(context).toggleSidebar();
+ },
+ ),
+ const SizedBox(width: 20),
+ PushButton(
+ buttonSize: ButtonSize.small,
+ child: const Text('Small'),
+ onPressed: () {
+ Navigator.of(context).push(
+ MaterialPageRoute(
+ builder: (_) {
+ return MacosScaffold(
+ toolBar: const ToolBar(
+ title: Text('New page'),
+ ),
+ children: [
+ ContentArea(
+ builder: (context, _) {
+ return Center(
+ child: PushButton(
+ buttonSize: ButtonSize.large,
+ child: const Text('Go Back'),
+ onPressed: () {
+ Navigator.of(context)
+ .maybePop();
+ },
+ ),
+ );
},
),
- );
- },
- ),
- ResizablePane(
- minWidth: 180,
- startWidth: 200,
- windowBreakpoint: 700,
- resizableSide: ResizableSide.left,
- builder: (_, __) {
- return const Center(
- child: Text('Resizable Pane'),
- );
- },
- ),
- ],
+ ResizablePane(
+ minSize: 180,
+ startSize: 200,
+ windowBreakpoint: 700,
+ resizableSide: ResizableSide.left,
+ builder: (_, __) {
+ return const Center(
+ child: Text('Resizable Pane'),
+ );
+ },
+ ),
+ ],
+ );
+ },
+ ),
);
},
),
- );
- },
- ),
- const SizedBox(width: 20),
- PushButton(
- buttonSize: ButtonSize.large,
- isSecondary: true,
- child: const Text('Secondary'),
- onPressed: () {
- MacosWindowScope.of(context).toggleSidebar();
- },
- ),
- ],
- ),
- const SizedBox(height: 20),
- const Text('MacosSwitch'),
- const SizedBox(height: 8),
- MacosSwitch(
- value: switchValue,
- onChanged: (value) {
- setState(() => switchValue = value);
- },
- ),
- const SizedBox(height: 20),
- const Text('MacosPulldownButton'),
- const SizedBox(height: 8),
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- MacosPulldownButton(
- title: "PDF",
- items: [
- MacosPulldownMenuItem(
- title: const Text('Open in Preview'),
- onTap: () => debugPrint("Opening in preview..."),
- ),
- MacosPulldownMenuItem(
- title: const Text('Save as PDF...'),
- onTap: () => debugPrint("Saving as PDF..."),
- ),
- MacosPulldownMenuItem(
- enabled: false,
- title: const Text('Save as Postscript'),
- onTap: () => debugPrint("Saving as Postscript..."),
- ),
- const MacosPulldownMenuDivider(),
- MacosPulldownMenuItem(
- enabled: false,
- title: const Text('Save to iCloud Drive'),
- onTap: () => debugPrint("Saving to iCloud..."),
- ),
- MacosPulldownMenuItem(
- enabled: false,
- title: const Text('Save to Web Receipts'),
- onTap: () =>
- debugPrint("Saving to Web Receipts..."),
- ),
- MacosPulldownMenuItem(
- title: const Text('Send in Mail...'),
- onTap: () => debugPrint("Sending via Mail..."),
- ),
- const MacosPulldownMenuDivider(),
- MacosPulldownMenuItem(
- title: const Text('Edit Menu...'),
- onTap: () => debugPrint("Editing menu..."),
- ),
- ],
- ),
- const SizedBox(width: 20),
- const MacosPulldownButton(
- title: "PDF",
- disabledTitle: "Disabled",
- items: [],
- ),
- ],
- ),
- const SizedBox(height: 8),
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- MacosPulldownButton(
- icon: CupertinoIcons.ellipsis_circle,
- items: [
- MacosPulldownMenuItem(
- title: const Text('New Folder'),
- onTap: () => debugPrint("Creating new folder..."),
- ),
- MacosPulldownMenuItem(
- title: const Text('Open'),
- onTap: () => debugPrint("Opening..."),
- ),
- MacosPulldownMenuItem(
- title: const Text('Open with...'),
- onTap: () => debugPrint("Opening with..."),
- ),
- MacosPulldownMenuItem(
- title: const Text('Import from iPhone...'),
- onTap: () => debugPrint("Importing..."),
- ),
- const MacosPulldownMenuDivider(),
- MacosPulldownMenuItem(
- enabled: false,
- title: const Text('Remove'),
- onTap: () => debugPrint("Deleting..."),
- ),
- MacosPulldownMenuItem(
- title: const Text('Move to Bin'),
- onTap: () => debugPrint("Moving to Bin..."),
- ),
- const MacosPulldownMenuDivider(),
- MacosPulldownMenuItem(
- title: const Text('Tags...'),
- onTap: () => debugPrint("Tags..."),
- ),
- ],
- ),
- const SizedBox(width: 20),
- const MacosPulldownButton(
- icon: CupertinoIcons.square_grid_3x2,
- items: [],
- ),
- ],
- ),
- const SizedBox(height: 20),
- const Text('MacosPopupButton'),
- const SizedBox(height: 8),
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- MacosPopupButton(
- value: popupValue,
- onChanged: (String? newValue) {
- setState(() => popupValue = newValue!);
- },
- items: ['One', 'Two', 'Three', 'Four']
- .map>((String value) {
- return MacosPopupMenuItem(
- value: value,
- child: Text(value),
- );
- }).toList(),
- ),
- const SizedBox(width: 20),
- MacosPopupButton(
- disabledHint: const Text("Disabled"),
- onChanged: null,
- items: null,
- ),
- ],
- ),
- const SizedBox(height: 20),
- MacosPopupButton(
- value: languagePopupValue,
- onChanged: (String? newValue) {
- setState(() => languagePopupValue = newValue!);
- },
- items: languages
- .map>((String value) {
- return MacosPopupMenuItem(
- value: value,
- child: Text(value),
- );
- }).toList(),
- ),
- const SizedBox(height: 20),
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- const Text('System Theme'),
- const SizedBox(width: 8),
- MacosRadioButton(
- groupValue: context.watch().mode,
- value: ThemeMode.system,
- onChanged: (value) {
- context.read().mode = value!;
- },
- ),
- ],
- ),
- const SizedBox(height: 8),
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- const Text('Light Theme'),
- const SizedBox(width: 24),
- MacosRadioButton(
- groupValue: context.watch().mode,
- value: ThemeMode.light,
- onChanged: (value) {
- context.read().mode = value!;
- },
- ),
- ],
- ),
- const SizedBox(height: 8),
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- const Text('Dark Theme'),
- const SizedBox(width: 26),
- MacosRadioButton(
- groupValue: context.watch().mode,
- value: ThemeMode.dark,
- onChanged: (value) {
- context.read().mode = value!;
- },
- ),
- ],
- ),
- const SizedBox(height: 20),
- const Text('MacosSegmentedControl'),
- const SizedBox(height: 8),
- MacosSegmentedControl(
- controller: _tabController,
- tabs: [
- MacosTab(
- label: 'Tab 1',
- active: _tabController.index == 0,
- ),
- MacosTab(
- label: 'Tab 2',
- active: _tabController.index == 1,
- ),
- MacosTab(
- label: 'Tab 3',
- active: _tabController.index == 2,
- ),
- ],
+ const SizedBox(width: 20),
+ PushButton(
+ buttonSize: ButtonSize.large,
+ isSecondary: true,
+ child: const Text('Secondary'),
+ onPressed: () {
+ MacosWindowScope.of(context).toggleSidebar();
+ },
+ ),
+ ],
+ ),
+ const SizedBox(height: 20),
+ const Text('MacosSwitch'),
+ const SizedBox(height: 8),
+ MacosSwitch(
+ value: switchValue,
+ onChanged: (value) {
+ setState(() => switchValue = value);
+ },
+ ),
+ const SizedBox(height: 20),
+ const Text('MacosPulldownButton'),
+ const SizedBox(height: 8),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ MacosPulldownButton(
+ title: "PDF",
+ items: [
+ MacosPulldownMenuItem(
+ title: const Text('Open in Preview'),
+ onTap: () =>
+ debugPrint("Opening in preview..."),
+ ),
+ MacosPulldownMenuItem(
+ title: const Text('Save as PDF...'),
+ onTap: () => debugPrint("Saving as PDF..."),
+ ),
+ MacosPulldownMenuItem(
+ enabled: false,
+ title: const Text('Save as Postscript'),
+ onTap: () =>
+ debugPrint("Saving as Postscript..."),
+ ),
+ const MacosPulldownMenuDivider(),
+ MacosPulldownMenuItem(
+ enabled: false,
+ title: const Text('Save to iCloud Drive'),
+ onTap: () =>
+ debugPrint("Saving to iCloud..."),
+ ),
+ MacosPulldownMenuItem(
+ enabled: false,
+ title: const Text('Save to Web Receipts'),
+ onTap: () =>
+ debugPrint("Saving to Web Receipts..."),
+ ),
+ MacosPulldownMenuItem(
+ title: const Text('Send in Mail...'),
+ onTap: () =>
+ debugPrint("Sending via Mail..."),
+ ),
+ const MacosPulldownMenuDivider(),
+ MacosPulldownMenuItem(
+ title: const Text('Edit Menu...'),
+ onTap: () => debugPrint("Editing menu..."),
+ ),
+ ],
+ ),
+ const SizedBox(width: 20),
+ const MacosPulldownButton(
+ title: "PDF",
+ disabledTitle: "Disabled",
+ items: [],
+ ),
+ ],
+ ),
+ const SizedBox(height: 8),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ MacosPulldownButton(
+ icon: CupertinoIcons.ellipsis_circle,
+ items: [
+ MacosPulldownMenuItem(
+ title: const Text('New Folder'),
+ onTap: () =>
+ debugPrint("Creating new folder..."),
+ ),
+ MacosPulldownMenuItem(
+ title: const Text('Open'),
+ onTap: () => debugPrint("Opening..."),
+ ),
+ MacosPulldownMenuItem(
+ title: const Text('Open with...'),
+ onTap: () => debugPrint("Opening with..."),
+ ),
+ MacosPulldownMenuItem(
+ title: const Text('Import from iPhone...'),
+ onTap: () => debugPrint("Importing..."),
+ ),
+ const MacosPulldownMenuDivider(),
+ MacosPulldownMenuItem(
+ enabled: false,
+ title: const Text('Remove'),
+ onTap: () => debugPrint("Deleting..."),
+ ),
+ MacosPulldownMenuItem(
+ title: const Text('Move to Bin'),
+ onTap: () => debugPrint("Moving to Bin..."),
+ ),
+ const MacosPulldownMenuDivider(),
+ MacosPulldownMenuItem(
+ title: const Text('Tags...'),
+ onTap: () => debugPrint("Tags..."),
+ ),
+ ],
+ ),
+ const SizedBox(width: 20),
+ const MacosPulldownButton(
+ icon: CupertinoIcons.square_grid_3x2,
+ items: [],
+ ),
+ ],
+ ),
+ const SizedBox(height: 20),
+ const Text('MacosPopupButton'),
+ const SizedBox(height: 8),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ MacosPopupButton(
+ value: popupValue,
+ onChanged: (String? newValue) {
+ setState(() => popupValue = newValue!);
+ },
+ items: [
+ 'One',
+ 'Two',
+ 'Three',
+ 'Four'
+ ].map>((String value) {
+ return MacosPopupMenuItem(
+ value: value,
+ child: Text(value),
+ );
+ }).toList(),
+ ),
+ const SizedBox(width: 20),
+ MacosPopupButton(
+ disabledHint: const Text("Disabled"),
+ onChanged: null,
+ items: null,
+ ),
+ ],
+ ),
+ const SizedBox(height: 20),
+ MacosPopupButton(
+ value: languagePopupValue,
+ onChanged: (String? newValue) {
+ setState(() => languagePopupValue = newValue!);
+ },
+ items: languages
+ .map>((String value) {
+ return MacosPopupMenuItem(
+ value: value,
+ child: Text(value),
+ );
+ }).toList(),
+ ),
+ const SizedBox(height: 20),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ const Text('System Theme'),
+ const SizedBox(width: 8),
+ MacosRadioButton(
+ groupValue: context.watch().mode,
+ value: ThemeMode.system,
+ onChanged: (value) {
+ context.read().mode = value!;
+ },
+ ),
+ ],
+ ),
+ const SizedBox(height: 8),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ const Text('Light Theme'),
+ const SizedBox(width: 24),
+ MacosRadioButton(
+ groupValue: context.watch().mode,
+ value: ThemeMode.light,
+ onChanged: (value) {
+ context.read().mode = value!;
+ },
+ ),
+ ],
+ ),
+ const SizedBox(height: 8),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ const Text('Dark Theme'),
+ const SizedBox(width: 26),
+ MacosRadioButton(
+ groupValue: context.watch().mode,
+ value: ThemeMode.dark,
+ onChanged: (value) {
+ context.read().mode = value!;
+ },
+ ),
+ ],
+ ),
+ const SizedBox(height: 20),
+ const Text('MacosSegmentedControl'),
+ const SizedBox(height: 8),
+ MacosSegmentedControl(
+ controller: _tabController,
+ tabs: [
+ MacosTab(
+ label: 'Tab 1',
+ active: _tabController.index == 0,
+ ),
+ MacosTab(
+ label: 'Tab 2',
+ active: _tabController.index == 1,
+ ),
+ MacosTab(
+ label: 'Tab 3',
+ active: _tabController.index == 2,
+ ),
+ ],
+ ),
+ ],
+ ),
),
- ],
- ),
+ ),
+ ResizablePane(
+ minSize: 50,
+ startSize: 200,
+ //windowBreakpoint: 600,
+ builder: (_, __) {
+ return const Center(
+ child: Text('Resizable Pane'),
+ );
+ },
+ resizableSide: ResizableSide.top,
+ )
+ ],
);
},
),
ResizablePane(
- minWidth: 180,
- startWidth: 200,
+ minSize: 180,
+ startSize: 200,
windowBreakpoint: 800,
resizableSide: ResizableSide.left,
builder: (_, __) {
diff --git a/example/lib/pages/fields_page.dart b/example/lib/pages/fields_page.dart
index c80ad815..c63e9f09 100644
--- a/example/lib/pages/fields_page.dart
+++ b/example/lib/pages/fields_page.dart
@@ -126,8 +126,8 @@ class _FieldsPageState extends State {
},
),
ResizablePane(
- minWidth: 180,
- startWidth: 200,
+ minSize: 180,
+ startSize: 200,
windowBreakpoint: 800,
resizableSide: ResizableSide.left,
builder: (_, __) {
diff --git a/example/lib/pages/indicators_page.dart b/example/lib/pages/indicators_page.dart
index 5daeaaf9..1dd4caf5 100644
--- a/example/lib/pages/indicators_page.dart
+++ b/example/lib/pages/indicators_page.dart
@@ -40,7 +40,7 @@ class _IndicatorsPageState extends State {
children: [
CapacityIndicator(
value: capacitorValue,
- onChanged: (v) => setState(() => sliderValue = v),
+ onChanged: (v) => setState(() => capacitorValue = v),
splits: 20,
discrete: true,
),
diff --git a/example/lib/pages/selectors_page.dart b/example/lib/pages/selectors_page.dart
index e44a1936..8256a33e 100644
--- a/example/lib/pages/selectors_page.dart
+++ b/example/lib/pages/selectors_page.dart
@@ -30,6 +30,7 @@ class _SelectorsPageState extends State {
ContentArea(
builder: (context, scrollController) {
return SingleChildScrollView(
+ controller: scrollController,
padding: const EdgeInsets.all(20),
child: Column(
children: [
diff --git a/example/lib/pages/tabview_page.dart b/example/lib/pages/tabview_page.dart
index 786b11b0..64d4d8ff 100644
--- a/example/lib/pages/tabview_page.dart
+++ b/example/lib/pages/tabview_page.dart
@@ -22,7 +22,7 @@ class _TabViewPageState extends State {
),
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
return Padding(
padding: const EdgeInsets.all(24.0),
child: MacosTabView(
diff --git a/example/lib/pages/toolbar_page.dart b/example/lib/pages/toolbar_page.dart
index af01f229..7492869b 100644
--- a/example/lib/pages/toolbar_page.dart
+++ b/example/lib/pages/toolbar_page.dart
@@ -158,11 +158,11 @@ class _ToolbarPageState extends State {
children: [
ContentArea(
builder: (context, scrollController) {
- return SingleChildScrollView(
- padding: const EdgeInsets.all(30),
+ return const SingleChildScrollView(
+ padding: EdgeInsets.all(30),
child: Center(
child: Column(
- children: const [
+ children: [
Text(
"The toolbar appears below the title bar of the macOS app or integrates with it.",
textAlign: TextAlign.center,
diff --git a/example/pubspec.lock b/example/pubspec.lock
index f6155c18..9d37f274 100644
--- a/example/pubspec.lock
+++ b/example/pubspec.lock
@@ -97,7 +97,7 @@ packages:
path: ".."
relative: true
source: path
- version: "1.10.0"
+ version: "1.11.1"
matcher:
dependency: transitive
description:
diff --git a/lib/src/fields/search_field.dart b/lib/src/fields/search_field.dart
index d7eddb63..2064ef9a 100644
--- a/lib/src/fields/search_field.dart
+++ b/lib/src/fields/search_field.dart
@@ -326,39 +326,39 @@ class _MacosSearchFieldState extends State> {
}
height += _kResultsOverlayMargin;
- return 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,
- ),
- );
- },
+ 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),
+ );
+ },
+ ),
),
),
);
diff --git a/lib/src/layout/resizable_pane.dart b/lib/src/layout/resizable_pane.dart
index c71ff8c2..68ccfbed 100644
--- a/lib/src/layout/resizable_pane.dart
+++ b/lib/src/layout/resizable_pane.dart
@@ -15,16 +15,19 @@ enum ResizableSide {
/// The right side of the [ResizablePane].
right,
+
+ /// The top side of the [ResizablePane].
+ top,
}
/// {@template resizablePane}
-/// A widget that can be resized horizontally.
+/// A widget that can be resized horizontally or vertically.
///
-/// The [builder], [minWidth] and [resizableSide] can not be null.
-/// The [maxWidth] and the [windowBreakpoint] default to `500.00`.
+/// The [builder], [minSize] and [resizableSide] can not be null.
+/// The [maxSize] and the [windowBreakpoint] default to `500.00`.
/// [isResizable] defaults to `true`.
///
-/// The [startWidth] is the initial width.
+/// The [startSize] is the initial width or height depending on the orientation of the pane.
/// {@endtemplate}
class ResizablePane extends StatefulWidget {
/// {@macro resizablePane}
@@ -32,19 +35,19 @@ class ResizablePane extends StatefulWidget {
super.key,
required this.builder,
this.decoration,
- this.maxWidth = 500.0,
- required this.minWidth,
+ this.maxSize = 500.0,
+ required this.minSize,
this.isResizable = true,
required this.resizableSide,
this.windowBreakpoint,
- required this.startWidth,
+ required this.startSize,
}) : assert(
- maxWidth >= minWidth,
- 'minWidth should not be more than maxWidth.',
+ maxSize >= minSize,
+ 'minSize should not be more than maxSize.',
),
assert(
- (startWidth >= minWidth) && (startWidth <= maxWidth),
- 'startWidth must not be less than minWidth or more than maxWidth',
+ (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
@@ -61,19 +64,34 @@ class ResizablePane extends StatefulWidget {
/// resizable side of this widget.
final bool isResizable;
- /// Specifies the maximum width that this [ResizablePane] can have.
+ /// Specifies the maximum width or height that this [ResizablePane] can have
+ /// according to its orientation.
+ ///
+ /// The orientation is horizontal if the [resizableSide] is
+ /// [ResizableSide.left] or [ResizableSide.right] and vertical if the
+ /// [resizableSide] is [ResizableSide.top]).
///
- /// The value can be null and defaults to `500.0`.
- final double maxWidth;
+ /// If this value is null, it defaults to `500.0`.
+ final double maxSize;
- /// Specifies the minimum width that this [ResizablePane] can have.
- final double minWidth;
+ /// Specifies the minimum width of height that this [ResizablePane] can have
+ /// according to its orientation.
+ ///
+ /// The orientation is horizontal if the [resizableSide] is
+ /// [ResizableSide.left] or [ResizableSide.right] and vertical if the
+ /// [resizableSide] is [ResizableSide.top].
+ final double minSize;
- /// Specifies the width that this [ResizablePane] first starts width.
+ /// Specifies the width or height that this [ResizablePane] first starts with
+ /// according to its orientation.
+ ///
+ /// The orientation is horizontal if the [resizableSide] is
+ /// [ResizableSide.left] or [ResizableSide.right] and vertical if the
+ /// [resizableSide] is [ResizableSide.top]).
///
- /// The [startWidth] should not be more than the [maxWidth] or
- /// less than the [minWidth].
- final double startWidth;
+ /// The [startSize] should not be more than the [maxSize] or
+ /// less than the [minSize].
+ final double startSize;
/// Indicates the draggable side of the [ResizablePane] for resizing
final ResizableSide resizableSide;
@@ -86,21 +104,26 @@ class ResizablePane extends StatefulWidget {
}
class _ResizablePaneState extends State {
- SystemMouseCursor _cursor = SystemMouseCursors.resizeColumn;
+ late SystemMouseCursor _cursor;
final _scrollController = ScrollController();
- late double _width;
- late double _dragStartWidth;
+ late double _size;
+ late double _dragStartSize;
late double _dragStartPosition;
Color get _dividerColor => MacosTheme.of(context).dividerColor;
bool get _resizeOnRight => widget.resizableSide == ResizableSide.right;
+ bool get _resizeOnTop => widget.resizableSide == ResizableSide.top;
+
BoxDecoration get _decoration {
final borderSide = BorderSide(color: _dividerColor);
final right = Border(right: borderSide);
final left = Border(left: borderSide);
- return BoxDecoration(border: _resizeOnRight ? right : left).copyWith(
+ final top = Border(top: borderSide);
+ return BoxDecoration(
+ border: _resizeOnTop ? top : (_resizeOnRight ? right : left),
+ ).copyWith(
color: widget.decoration?.color,
border: widget.decoration?.border,
borderRadius: widget.decoration?.borderRadius,
@@ -112,51 +135,99 @@ class _ResizablePaneState extends State {
);
}
+ BoxConstraints get _boxConstraint {
+ if (_resizeOnTop) {
+ return BoxConstraints(
+ maxHeight: widget.maxSize,
+ minHeight: widget.minSize,
+ ).normalize();
+ }
+ return BoxConstraints(
+ maxWidth: widget.maxSize,
+ minWidth: widget.minSize,
+ ).normalize();
+ }
+
Widget get _resizeArea {
- return GestureDetector(
- behavior: HitTestBehavior.opaque,
- child: MouseRegion(
- cursor: _cursor,
- child: const SizedBox(width: 5),
- ),
- onHorizontalDragStart: (details) {
- _dragStartWidth = _width;
- _dragStartPosition = details.globalPosition.dx;
- },
- onHorizontalDragUpdate: (details) {
- setState(() {
- final newWidth = _resizeOnRight
- ? _dragStartWidth -
- (_dragStartPosition - details.globalPosition.dx)
- : _dragStartWidth +
- (_dragStartPosition - details.globalPosition.dx);
- _width = math.max(
- widget.minWidth,
- math.min(
- widget.maxWidth,
- newWidth,
+ return _resizeOnTop
+ ? GestureDetector(
+ behavior: HitTestBehavior.opaque,
+ child: MouseRegion(
+ cursor: _cursor,
+ child: const SizedBox(width: 5),
),
+ onVerticalDragStart: (details) {
+ _dragStartSize = _size;
+ _dragStartPosition = details.globalPosition.dy;
+ },
+ onVerticalDragUpdate: (details) {
+ setState(() {
+ final newHeight = _dragStartSize +
+ (_dragStartPosition - details.globalPosition.dy);
+ _size = math.max(
+ widget.minSize,
+ math.min(
+ widget.maxSize,
+ newHeight,
+ ),
+ );
+ if (_size == widget.minSize) {
+ _cursor = SystemMouseCursors.resizeUp;
+ } else if (_size == widget.maxSize) {
+ _cursor = SystemMouseCursors.resizeDown;
+ } else {
+ _cursor = SystemMouseCursors.resizeRow;
+ }
+ });
+ },
+ )
+ : GestureDetector(
+ behavior: HitTestBehavior.opaque,
+ child: MouseRegion(
+ cursor: _cursor,
+ child: const SizedBox(width: 5),
+ ),
+ onHorizontalDragStart: (details) {
+ _dragStartSize = _size;
+ _dragStartPosition = details.globalPosition.dx;
+ },
+ onHorizontalDragUpdate: (details) {
+ setState(() {
+ final newWidth = _resizeOnRight
+ ? _dragStartSize -
+ (_dragStartPosition - details.globalPosition.dx)
+ : _dragStartSize +
+ (_dragStartPosition - details.globalPosition.dx);
+ _size = math.max(
+ widget.minSize,
+ math.min(
+ widget.maxSize,
+ newWidth,
+ ),
+ );
+ if (_size == widget.minSize) {
+ _cursor = _resizeOnRight
+ ? SystemMouseCursors.resizeRight
+ : SystemMouseCursors.resizeLeft;
+ } else if (_size == widget.maxSize) {
+ _cursor = _resizeOnRight
+ ? SystemMouseCursors.resizeLeft
+ : SystemMouseCursors.resizeRight;
+ } else {
+ _cursor = SystemMouseCursors.resizeColumn;
+ }
+ });
+ },
);
- if (_width == widget.minWidth) {
- _cursor = _resizeOnRight
- ? SystemMouseCursors.resizeRight
- : SystemMouseCursors.resizeLeft;
- } else if (_width == widget.maxWidth) {
- _cursor = _resizeOnRight
- ? SystemMouseCursors.resizeLeft
- : SystemMouseCursors.resizeRight;
- } else {
- _cursor = SystemMouseCursors.resizeColumn;
- }
- });
- },
- );
}
@override
void initState() {
super.initState();
- _width = widget.startWidth;
+ _cursor = _resizeOnTop
+ ? SystemMouseCursors.resizeRow
+ : SystemMouseCursors.resizeColumn;
+ _size = widget.startSize;
_scrollController.addListener(() => setState(() {}));
}
@@ -164,12 +235,12 @@ class _ResizablePaneState extends State {
void didUpdateWidget(covariant ResizablePane oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.windowBreakpoint != widget.windowBreakpoint ||
- oldWidget.minWidth != widget.minWidth ||
- oldWidget.maxWidth != widget.maxWidth ||
+ oldWidget.minSize != widget.minSize ||
+ oldWidget.maxSize != widget.maxSize ||
oldWidget.resizableSide != widget.resizableSide) {
setState(() {
- if (widget.minWidth > _width) _width = widget.minWidth;
- if (widget.maxWidth < _width) _width = widget.maxWidth;
+ if (widget.minSize > _size) _size = widget.minSize;
+ if (widget.maxSize < _size) _size = widget.maxSize;
});
}
}
@@ -186,19 +257,23 @@ class _ResizablePaneState extends State {
final maxHeight = media.size.height;
final maxWidth = media.size.width;
- if (widget.windowBreakpoint != null &&
- maxWidth <= widget.windowBreakpoint!) {
- return const SizedBox.shrink();
+ if (_resizeOnTop) {
+ if (widget.windowBreakpoint != null &&
+ maxHeight <= widget.windowBreakpoint!) {
+ return const SizedBox.shrink();
+ }
+ } else {
+ if (widget.windowBreakpoint != null &&
+ maxWidth <= widget.windowBreakpoint!) {
+ return const SizedBox.shrink();
+ }
}
return Container(
- width: _width,
- height: maxHeight,
+ width: _resizeOnTop ? maxWidth : _size,
+ height: _resizeOnTop ? _size : maxHeight,
decoration: _decoration,
- constraints: BoxConstraints(
- maxWidth: widget.maxWidth,
- minWidth: widget.minWidth,
- ).normalize(),
+ constraints: _boxConstraint,
child: Stack(
children: [
SafeArea(
@@ -209,7 +284,7 @@ class _ResizablePaneState extends State {
child: widget.builder(context, _scrollController),
),
),
- if (widget.isResizable && !_resizeOnRight)
+ if (widget.isResizable && !_resizeOnRight && !_resizeOnTop)
Positioned(
left: 0,
width: 5,
@@ -223,6 +298,13 @@ class _ResizablePaneState extends State {
height: maxHeight,
child: _resizeArea,
),
+ if (widget.isResizable && _resizeOnTop)
+ Positioned(
+ top: 0,
+ width: maxWidth,
+ height: 5,
+ child: _resizeArea,
+ ),
],
),
);
diff --git a/lib/src/layout/toolbar/toolbar.dart b/lib/src/layout/toolbar/toolbar.dart
index 01a3c12d..294a24a6 100644
--- a/lib/src/layout/toolbar/toolbar.dart
+++ b/lib/src/layout/toolbar/toolbar.dart
@@ -89,15 +89,17 @@ class ToolBar extends StatefulWidget {
/// Typically the [leading] widget is a [MacosIcon] or a [MacosIconButton].
final Widget? leading;
- /// Controls whether we should try to imply the leading widget if null.
+ /// Controls whether the toolbar should try to imply if the [leading] widget
+ /// is null.
///
- /// If `true` and [leading] is null, automatically try to deduce what the leading
- /// widget should be. If `false` and [leading] is null, leading space is given to [title].
- /// If leading widget is not null, this parameter has no effect.
+ /// If `true` and [leading] are null, the toolbar will automatically try to
+ /// deduce what the leading widget should be. If `false` and [leading] is
+ /// null, leading space is given to [title]. If the [leading] widget is not
+ /// null, this parameter has no effect.
final bool automaticallyImplyLeading;
- /// A list of [ToolbarItem] widgets to display in a row after the [title] widget,
- /// as the toolbar actions.
+ /// A list of [ToolbarItem] widgets to display in a row after the [title]
+ /// widget, as the toolbar actions.
///
/// Toolbar items include [ToolBarIconButton], [ToolBarPulldownButton],
/// [ToolBarSpacer], and [CustomToolbarItem] widgets.
@@ -108,14 +110,14 @@ class ToolBar extends StatefulWidget {
/// at the right edge of the toolbar.
final List? actions;
- /// Whether the title should be centered.
+ /// Whether the [title] should be centered.
final bool centerTitle;
/// The color of the divider below the toolbar.
///
- /// Defaults to MacosTheme.of(context).dividerColor.
+ /// Defaults to `MacosTheme.of(context).dividerColor`.
///
- /// Set it to MacosColors.transparent to remove.
+ /// Set this to `MacosColors.transparent` to remove.
final Color? dividerColor;
@override
diff --git a/pr_prelaunch_tasks.sh b/pr_prelaunch_tasks.sh
deleted file mode 100644
index b7d2ff83..00000000
--- a/pr_prelaunch_tasks.sh
+++ /dev/null
@@ -1,39 +0,0 @@
-dart format --set-exit-if-changed .
-if [ $? -eq 1 ]; then
- dart format lib
- git add .
- git commit -m "chore: run flutter format ."
- echo "push changes? [y/n]"
- read -r pushResponse
- if [ "$pushResponse" = "y" ]; then
- git push origin
- fi
-fi
-echo "Run dart fix --dry-run? [y/n]"
-read -r dryRunResponse
-if [ "$dryRunResponse" = "y" ]; then
- dart fix --dry-run
-fi
-echo "Run dart fix --apply? [y/n]"
-read -r applyResponse
-if [ "$applyResponse" = "y" ]; then
- dart fix --apply
- if [ -z "$(git status --porcelain)" ]; then
- echo "No changes to commit"
- else
- git add .
- git commit -m "chore: run dart fix --apply"
- echo "push changes? [y/n]"
- read -r pushResponse
- if [ "$pushResponse" = "y" ]; then
- git push origin
- fi
- fi
-fi
-echo "Run tests? [y/n]"
-read -r testResponse
-if [ "$testResponse" = "y" ]; then
- flutter test
-else
- exit 0
-fi
\ No newline at end of file
diff --git a/publish_tasks.sh b/publish_tasks.sh
deleted file mode 100644
index a6aa33e1..00000000
--- a/publish_tasks.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-# MAINTAINER ONLY SCRIPT. DO NOT RUN THIS SCRIPT UNLESS YOU ARE THE MAINTAINER.
-pana --no-warning
-echo "Are you ready to dry-run publish macos_ui? [y/n]"
-read -r dryRunResponse
-if [ "$dryRunResponse" = "y" ]; then
- flutter pub publish --dry-run
-else
- exit 0
-fi
-echo "Are you ready to publish macos_ui to pub.dev? [y/n]"
-read -r publishResponse
-if [ "$publishResponse" = "y" ]; then
- flutter pub publish
-else
- exit 0
-fi
\ No newline at end of file
diff --git a/pubspec.yaml b/pubspec.yaml
index 7b6b263b..d1760775 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
name: macos_ui
description: Flutter widgets and themes implementing the current macOS design language.
-version: 1.10.0
+version: 1.11.1
homepage: "https://macosui.dev"
repository: "https://github.com/GroovinChip/macos_ui"
diff --git a/test/buttons/checkbox_test.dart b/test/buttons/checkbox_test.dart
index 9ba9c1a5..09881007 100644
--- a/test/buttons/checkbox_test.dart
+++ b/test/buttons/checkbox_test.dart
@@ -12,7 +12,7 @@ void main() {
child: MacosScaffold(
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
return StatefulBuilder(
builder: (context, setState) {
return MacosCheckbox(
diff --git a/test/buttons/help_button_test.dart b/test/buttons/help_button_test.dart
index 6124e5c0..2f11f430 100644
--- a/test/buttons/help_button_test.dart
+++ b/test/buttons/help_button_test.dart
@@ -24,7 +24,7 @@ void main() {
child: MacosScaffold(
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
return HelpButton(
onPressed: mockOnPressedFunction.handler,
);
diff --git a/test/buttons/icon_button_test.dart b/test/buttons/icon_button_test.dart
index a4c1e543..057f6a3b 100644
--- a/test/buttons/icon_button_test.dart
+++ b/test/buttons/icon_button_test.dart
@@ -19,7 +19,7 @@ void main() {
child: MacosScaffold(
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
return MacosIconButton(
icon: const Icon(CupertinoIcons.add),
onPressed: mockOnPressedFunction.handler,
diff --git a/test/buttons/popup_button_test.dart b/test/buttons/popup_button_test.dart
index d685d3da..704501ef 100644
--- a/test/buttons/popup_button_test.dart
+++ b/test/buttons/popup_button_test.dart
@@ -17,7 +17,7 @@ void main() {
child: MacosScaffold(
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
return StatefulBuilder(
builder: (context, setState) {
return MacosPopupButton(
diff --git a/test/buttons/pulldown_button_test.dart b/test/buttons/pulldown_button_test.dart
index aa42cc83..e22a355e 100644
--- a/test/buttons/pulldown_button_test.dart
+++ b/test/buttons/pulldown_button_test.dart
@@ -22,7 +22,7 @@ void main() {
child: MacosScaffold(
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
return Center(
child: MacosPulldownButton(
title: "test",
diff --git a/test/buttons/push_button_test.dart b/test/buttons/push_button_test.dart
index 99fe95ae..96dc571e 100644
--- a/test/buttons/push_button_test.dart
+++ b/test/buttons/push_button_test.dart
@@ -25,7 +25,7 @@ void main() {
child: MacosScaffold(
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
return PushButton(
buttonSize: ButtonSize.small,
onPressed: mockOnPressedFunction.handler,
diff --git a/test/buttons/radio_button_test.dart b/test/buttons/radio_button_test.dart
index cb51f3b3..d561b643 100644
--- a/test/buttons/radio_button_test.dart
+++ b/test/buttons/radio_button_test.dart
@@ -20,7 +20,7 @@ void main() {
child: MacosScaffold(
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
return Center(
child: MacosRadioButton(
value: TestOptions.first,
diff --git a/test/buttons/segmented_control_test.dart b/test/buttons/segmented_control_test.dart
index 1ccf4a74..62d19796 100644
--- a/test/buttons/segmented_control_test.dart
+++ b/test/buttons/segmented_control_test.dart
@@ -14,7 +14,7 @@ void main() {
child: MacosScaffold(
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
return Center(
child: MacosSegmentedControl(
controller: controller,
diff --git a/test/buttons/switch_test.dart b/test/buttons/switch_test.dart
index 75c3e863..642f0f11 100644
--- a/test/buttons/switch_test.dart
+++ b/test/buttons/switch_test.dart
@@ -12,7 +12,7 @@ void main() {
child: MacosScaffold(
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
return Center(
child: MacosSwitch(
value: selected,
diff --git a/test/fields/search_field_test.dart b/test/fields/search_field_test.dart
index a6f1a750..4fdbc863 100644
--- a/test/fields/search_field_test.dart
+++ b/test/fields/search_field_test.dart
@@ -29,10 +29,11 @@ void main() {
child: MacosScaffold(
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
return Center(
child: SizedBox(
width: 300.0,
+ height: 500.0,
child: MacosSearchField(
results:
kOptions.map((e) => SearchResultItem(e)).toList(),
@@ -64,6 +65,15 @@ void main() {
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.tap(find.text('elephant'));
+ await tester.pump();
+
+ 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 d83ce27b..71b12568 100644
--- a/test/fields/text_field_test.dart
+++ b/test/fields/text_field_test.dart
@@ -12,7 +12,7 @@ void main() {
child: MacosScaffold(
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
return Center(
child: MacosTextField(
controller: controller,
diff --git a/test/layout/macos_list_tile_test.dart b/test/layout/macos_list_tile_test.dart
index 6f86b952..e019a007 100644
--- a/test/layout/macos_list_tile_test.dart
+++ b/test/layout/macos_list_tile_test.dart
@@ -23,7 +23,7 @@ void main() {
child: MacosScaffold(
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
return MacosListTile(
title: const Text('List Tile'),
onClick: mockOnPressedFunction.handler,
diff --git a/test/layout/resizeable_pane_test.dart b/test/layout/resizeable_pane_test.dart
index bae5ac4d..86638a6a 100644
--- a/test/layout/resizeable_pane_test.dart
+++ b/test/layout/resizeable_pane_test.dart
@@ -7,150 +7,226 @@ void main() {
group('ResizablePane', () {
for (var side in matrix) {
- group(side == ResizableSide.left ? "left" : "right", () {
- const double maxWidth = 300;
- const double minWidth = 100;
- const double startWidth = 200;
-
- final resizablePane = ResizablePane(
- builder: (context, scrollController) => const Text('Hello there'),
- minWidth: minWidth,
- startWidth: startWidth,
- maxWidth: maxWidth,
- resizableSide: side,
- );
-
- final view = MacosApp(
- home: MacosWindow(
- child: MacosScaffold(
- children: [
- resizablePane,
- ContentArea(
- builder: (context, scrollController) {
- return const Text('Hello there');
- },
- ),
- ],
- ),
- ),
- );
-
- final resizablePaneFinder = find.byWidget(resizablePane);
- final dragFinder = find.descendant(
- of: resizablePaneFinder,
- matching: find.byType(GestureDetector),
- );
-
- final directionModifier = side == ResizableSide.right ? 1 : -1;
- final double safeDelta = 50.0 * directionModifier;
- final double overflowDelta = 500.0 * directionModifier;
-
- testWidgets('initial width equals startWidth', (tester) async {
- await tester.pumpWidget(view);
-
- var resizablePaneRenderObject =
- tester.renderObject(resizablePaneFinder);
- expect(resizablePaneRenderObject.size.width, startWidth);
- });
-
- testWidgets('dragging wider works', (tester) async {
- await tester.pumpWidget(view);
-
- await tester.drag(
- dragFinder,
- Offset(safeDelta, 0),
+ bool verticallyResizable = side == ResizableSide.top;
+
+ group(
+ side == ResizableSide.top
+ ? 'top'
+ : (side == ResizableSide.left ? 'left' : 'right'),
+ () {
+ const double maxSize = 300;
+ const double minSize = 100;
+ const double startSize = 200;
+
+ final resizablePane = ResizablePane(
+ builder: (context, scrollController) => const Text('Hello there'),
+ minSize: minSize,
+ startSize: startSize,
+ maxSize: maxSize,
+ resizableSide: side,
);
- await tester.pump();
- var resizablePaneRenderObject =
- tester.renderObject(resizablePaneFinder);
- expect(
- resizablePaneRenderObject.size.width,
- startWidth + safeDelta * directionModifier,
+ final view = side == ResizableSide.top
+ ? MacosApp(
+ home: MacosWindow(
+ child: MacosScaffold(
+ children: [
+ ContentArea(
+ builder: (context, scrollController) {
+ return Column(
+ children: [
+ const Flexible(
+ fit: FlexFit.loose,
+ child: Center(
+ child: Text('Hello there'),
+ ),
+ ),
+ resizablePane,
+ ],
+ );
+ },
+ ),
+ ],
+ ),
+ ),
+ )
+ : MacosApp(
+ home: MacosWindow(
+ child: MacosScaffold(
+ children: [
+ resizablePane,
+ ContentArea(
+ builder: (context, scrollController) {
+ return const Text('Hello there');
+ },
+ ),
+ ],
+ ),
+ ),
+ );
+
+ final resizablePaneFinder = find.byWidget(resizablePane);
+ final dragFinder = find.descendant(
+ of: resizablePaneFinder,
+ matching: find.byType(GestureDetector),
);
- });
- testWidgets('dragging wider respects maxWidth', (tester) async {
- await tester.pumpWidget(view);
+ // No need to check if the resizable side is top because directionModifier
+ // would take -1 if it is the case
+ final directionModifier = side == ResizableSide.right ? 1 : -1;
+ final double safeDelta = 50.0 * directionModifier;
+ final double overflowDelta = 500.0 * directionModifier;
- await tester.drag(
- dragFinder,
- Offset(overflowDelta, 0),
- );
- await tester.pump();
+ testWidgets('initial size equals startSize', (tester) async {
+ await tester.pumpWidget(view);
+
+ var resizablePaneRenderObject =
+ tester.renderObject(resizablePaneFinder);
+ var initialSize = verticallyResizable
+ ? resizablePaneRenderObject.size.height
+ : resizablePaneRenderObject.size.width;
- var resizablePaneRenderObject =
- tester.renderObject(resizablePaneFinder);
- expect(resizablePaneRenderObject.size.width, maxWidth);
- });
+ expect(initialSize, startSize);
+ });
- testWidgets(
- 'drag events past maxWidth have no effect',
- (tester) async {
+ testWidgets('dragging wider works $side', (tester) async {
await tester.pumpWidget(view);
- final dragStartLocation = tester.getCenter(dragFinder);
- final drag = await tester.startGesture(dragStartLocation);
- await drag.moveBy(Offset(overflowDelta, 0));
- await drag.moveBy(Offset(-10.0 * directionModifier, 0));
- await drag.up();
+ await tester.drag(
+ dragFinder,
+ verticallyResizable ? Offset(0, safeDelta) : Offset(safeDelta, 0),
+ );
await tester.pump();
var resizablePaneRenderObject =
tester.renderObject(resizablePaneFinder);
- expect(resizablePaneRenderObject.size.width, maxWidth);
- },
- );
-
- testWidgets('dragging narrower works', (tester) async {
- await tester.pumpWidget(view);
+ expect(
+ verticallyResizable
+ ? resizablePaneRenderObject.size.height
+ : resizablePaneRenderObject.size.width,
+ startSize + safeDelta * directionModifier,
+ );
+ });
+
+ testWidgets('dragging wider respects maxSize', (tester) async {
+ await tester.pumpWidget(view);
- await tester.drag(
- dragFinder,
- Offset(-safeDelta, 0),
- );
- await tester.pump();
+ await tester.drag(
+ dragFinder,
+ verticallyResizable
+ ? Offset(0, overflowDelta)
+ : Offset(overflowDelta, 0),
+ );
+ await tester.pump();
- var resizablePaneRenderObject =
- tester.renderObject(resizablePaneFinder);
- expect(
- resizablePaneRenderObject.size.width,
- startWidth - safeDelta * directionModifier,
+ 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);
+
+ 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 respects minWidth', (tester) async {
- await tester.pumpWidget(view);
- await tester.drag(
- dragFinder,
- Offset(-overflowDelta, 0),
- );
- await tester.pump();
+ testWidgets('dragging narrower works', (tester) async {
+ await tester.pumpWidget(view);
- var resizablePaneRenderObject =
- tester.renderObject(resizablePaneFinder);
- expect(resizablePaneRenderObject.size.width, minWidth);
- });
+ await tester.drag(
+ dragFinder,
+ verticallyResizable
+ ? Offset(0, -safeDelta)
+ : Offset(-safeDelta, 0),
+ );
+ await tester.pump();
- testWidgets(
- 'drag events past minWidth have no effect',
- (tester) async {
+ var resizablePaneRenderObject =
+ tester.renderObject(resizablePaneFinder);
+ var currentSize = verticallyResizable
+ ? resizablePaneRenderObject.size.height
+ : resizablePaneRenderObject.size.width;
+ expect(
+ currentSize,
+ startSize - safeDelta * directionModifier,
+ );
+ });
+
+ testWidgets('dragging narrower respects minSize', (tester) async {
await tester.pumpWidget(view);
- final dragStartLocation = tester.getCenter(dragFinder);
- final drag = await tester.startGesture(dragStartLocation);
- await drag.moveBy(Offset(-overflowDelta, 0));
- await drag.moveBy(Offset(10.0 * directionModifier, 0));
- await drag.up();
+ await tester.drag(
+ dragFinder,
+ verticallyResizable
+ ? Offset(0, -overflowDelta)
+ : Offset(-overflowDelta, 0),
+ );
await tester.pump();
var resizablePaneRenderObject =
tester.renderObject(resizablePaneFinder);
- expect(resizablePaneRenderObject.size.width, minWidth);
- },
- );
- });
+ 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);
+
+ 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/tab_view_test.dart b/test/layout/tab_view_test.dart
index 3673f4d1..2fb09c07 100644
--- a/test/layout/tab_view_test.dart
+++ b/test/layout/tab_view_test.dart
@@ -14,7 +14,7 @@ void main() {
child: MacosScaffold(
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
return Padding(
padding: const EdgeInsets.all(24.0),
child: MacosTabView(
diff --git a/test/selectors/date_picker_test.dart b/test/selectors/date_picker_test.dart
index e6d36763..f0c5afbc 100644
--- a/test/selectors/date_picker_test.dart
+++ b/test/selectors/date_picker_test.dart
@@ -15,7 +15,7 @@ void main() {
child: MacosScaffold(
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
return Center(
child: MacosDatePicker(
onDateChanged: (date) {},
@@ -262,7 +262,7 @@ void main() {
child: MacosScaffold(
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
return Center(
child: MacosDatePicker(
onDateChanged: (date) {
diff --git a/test/theme/help_button_theme_test.dart b/test/theme/help_button_theme_test.dart
index cd93ac74..702a85ed 100644
--- a/test/theme/help_button_theme_test.dart
+++ b/test/theme/help_button_theme_test.dart
@@ -59,7 +59,7 @@ void main() {
child: MacosScaffold(
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
capturedContext = context;
return const HelpButton();
},
diff --git a/test/theme/icon_button_theme_test.dart b/test/theme/icon_button_theme_test.dart
index 92832505..af7a40e6 100644
--- a/test/theme/icon_button_theme_test.dart
+++ b/test/theme/icon_button_theme_test.dart
@@ -66,7 +66,7 @@ void main() {
child: MacosScaffold(
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
capturedContext = context;
return MacosIconButton(
icon: const Icon(CupertinoIcons.add),
diff --git a/test/theme/icon_theme_test.dart b/test/theme/icon_theme_test.dart
index 23182817..8e98f80a 100644
--- a/test/theme/icon_theme_test.dart
+++ b/test/theme/icon_theme_test.dart
@@ -66,7 +66,7 @@ void main() {
child: MacosScaffold(
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
capturedContext = context;
return const MacosIcon(
CupertinoIcons.add,
diff --git a/test/theme/popup_button_theme_test.dart b/test/theme/popup_button_theme_test.dart
index 710f2f49..daa039de 100644
--- a/test/theme/popup_button_theme_test.dart
+++ b/test/theme/popup_button_theme_test.dart
@@ -70,7 +70,7 @@ void main() {
child: MacosScaffold(
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
capturedContext = context;
return MacosPopupButton(
value: popupValue,
diff --git a/test/theme/pulldown_button_theme_test.dart b/test/theme/pulldown_button_theme_test.dart
index 44264874..373ac0c4 100644
--- a/test/theme/pulldown_button_theme_test.dart
+++ b/test/theme/pulldown_button_theme_test.dart
@@ -69,7 +69,7 @@ void main() {
child: MacosScaffold(
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
capturedContext = context;
return const Center(
child: MacosPulldownButton(
diff --git a/test/theme/push_button_theme_test.dart b/test/theme/push_button_theme_test.dart
index 8ced6d85..5bcc4ef1 100644
--- a/test/theme/push_button_theme_test.dart
+++ b/test/theme/push_button_theme_test.dart
@@ -61,7 +61,7 @@ void main() {
child: MacosScaffold(
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
capturedContext = context;
return const PushButton(
buttonSize: ButtonSize.small,
diff --git a/test/theme/search_field_theme_test.dart b/test/theme/search_field_theme_test.dart
index 866f83cc..da838f37 100644
--- a/test/theme/search_field_theme_test.dart
+++ b/test/theme/search_field_theme_test.dart
@@ -65,7 +65,7 @@ void main() {
child: MacosScaffold(
children: [
ContentArea(
- builder: (context, scrollController) {
+ builder: (context, _) {
capturedContext = context;
return const Center(
child: MacosSearchField(),