diff --git a/CHANGELOG.md b/CHANGELOG.md index e853ae93..a4ad17c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## [1.3.0] +* Add a `top` property to `Sidebar` +* Tweak the default `primaryColor` value in `MacosThemeData`. + ## [1.2.1+1] * Fix `MacosApp` documentation diff --git a/example/lib/main.dart b/example/lib/main.dart index 8264f019..b2fdac3c 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -51,6 +51,8 @@ class _DemoState extends State { int pageIndex = 0; + late final searchFieldController = TextEditingController(); + final List pages = [ CupertinoTabView( builder: (_) => const ButtonsPage(), @@ -80,6 +82,67 @@ class _DemoState extends State { // title: Text('macOS App Name'), // ), sidebar: Sidebar( + top: MacosSearchField( + placeholder: 'Search', + controller: searchFieldController, + onResultSelected: (result) { + switch (result.searchKey) { + case 'Buttons': + setState(() { + pageIndex = 0; + searchFieldController.clear(); + }); + break; + case 'Indicators': + setState(() { + pageIndex = 1; + searchFieldController.clear(); + }); + break; + case 'Fields': + setState(() { + pageIndex = 2; + searchFieldController.clear(); + }); + break; + case 'Colors': + setState(() { + pageIndex = 3; + searchFieldController.clear(); + }); + break; + case 'Dialogs and Sheets': + setState(() { + pageIndex = 5; + searchFieldController.clear(); + }); + break; + case 'Toolbar': + setState(() { + pageIndex = 6; + searchFieldController.clear(); + }); + break; + case 'Selectors': + setState(() { + pageIndex = 7; + searchFieldController.clear(); + }); + break; + default: + searchFieldController.clear(); + } + }, + results: const [ + SearchResultItem('Buttons'), + SearchResultItem('Indicators'), + SearchResultItem('Fields'), + SearchResultItem('Colors'), + SearchResultItem('Dialogs and Sheets'), + SearchResultItem('Toolbar'), + SearchResultItem('Selectors'), + ], + ), minWidth: 200, builder: (context, controller) { return SidebarItems( @@ -127,13 +190,10 @@ class _DemoState extends State { ], ); }, - bottom: const Padding( - padding: EdgeInsets.all(16.0), - child: MacosListTile( - leading: MacosIcon(CupertinoIcons.profile_circled), - title: Text('Tim Apple'), - subtitle: Text('tim@apple.com'), - ), + bottom: const MacosListTile( + leading: MacosIcon(CupertinoIcons.profile_circled), + title: Text('Tim Apple'), + subtitle: Text('tim@apple.com'), ), ), ); diff --git a/example/macos/Podfile.lock b/example/macos/Podfile.lock index 6cc68f69..bf38dd65 100644 --- a/example/macos/Podfile.lock +++ b/example/macos/Podfile.lock @@ -19,4 +19,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c -COCOAPODS: 1.10.2 +COCOAPODS: 1.11.3 diff --git a/example/pubspec.lock b/example/pubspec.lock index 8e9b0ad3..b2673f81 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -87,7 +87,7 @@ packages: path: ".." relative: true source: path - version: "1.2.1+1" + version: "1.3.0" matcher: dependency: transitive description: diff --git a/lib/macos_ui.dart b/lib/macos_ui.dart index 6c1510f7..8a7c8a4e 100644 --- a/lib/macos_ui.dart +++ b/lib/macos_ui.dart @@ -37,8 +37,9 @@ export 'src/layout/content_area.dart'; export 'src/layout/macos_list_tile.dart'; export 'src/layout/resizable_pane.dart'; export 'src/layout/scaffold.dart'; -export 'src/layout/sidebar.dart'; -export 'src/layout/sidebar_item.dart'; +export 'src/layout/sidebar/sidebar.dart'; +export 'src/layout/sidebar/sidebar_item.dart'; +export 'src/layout/sidebar/sidebar_items.dart'; export 'src/layout/title_bar.dart'; export 'src/layout/toolbar/custom_toolbar_item.dart'; export 'src/layout/toolbar/toolbar.dart'; diff --git a/lib/src/layout/scaffold.dart b/lib/src/layout/scaffold.dart index 50db736f..30617c57 100644 --- a/lib/src/layout/scaffold.dart +++ b/lib/src/layout/scaffold.dart @@ -3,7 +3,7 @@ import 'dart:math' as math; import 'package:flutter/rendering.dart'; import 'package:macos_ui/src/layout/content_area.dart'; import 'package:macos_ui/src/layout/resizable_pane.dart'; -import 'package:macos_ui/src/layout/sidebar.dart'; +import 'package:macos_ui/src/layout/sidebar/sidebar.dart'; import 'package:macos_ui/src/layout/title_bar.dart'; import 'package:macos_ui/src/layout/toolbar/toolbar.dart'; import 'package:macos_ui/src/layout/window.dart'; diff --git a/lib/src/layout/sidebar.dart b/lib/src/layout/sidebar/sidebar.dart similarity index 93% rename from lib/src/layout/sidebar.dart rename to lib/src/layout/sidebar/sidebar.dart index 65469f5a..d9050f2d 100644 --- a/lib/src/layout/sidebar.dart +++ b/lib/src/layout/sidebar/sidebar.dart @@ -20,6 +20,7 @@ class Sidebar { this.startWidth, this.padding = EdgeInsets.zero, this.windowBreakpoint = 556.0, + this.top, this.bottom, this.topOffset = 51.0, }) : dragClosedBuffer = dragClosedBuffer ?? minWidth / 2; @@ -96,7 +97,14 @@ class Sidebar { /// Specifies the width of the window at which this [Sidebar] will be hidden. final double windowBreakpoint; - /// Widget that should be displayed at the Bottom of the Sidebar + /// Widget that should be displayed at the top of the [Sidebar]. + /// + /// Commonly a [MacosSearchField]. + final Widget? top; + + /// Widget that should be displayed at the bottom of the [Sidebar]. + /// + /// Commonly a [MacosListTile]. final Widget? bottom; /// Specifies the top offset of the sidebar. diff --git a/lib/src/layout/sidebar/sidebar_item.dart b/lib/src/layout/sidebar/sidebar_item.dart new file mode 100644 index 00000000..8a98a930 --- /dev/null +++ b/lib/src/layout/sidebar/sidebar_item.dart @@ -0,0 +1,73 @@ +import 'package:flutter/foundation.dart'; +import 'package:macos_ui/macos_ui.dart'; +import 'package:macos_ui/src/library.dart'; + +/// A macOS style navigation-list item intended for use in a [Sidebar] +/// +/// See also: +/// +/// * [Sidebar], a side bar used alongside [MacosScaffold] +/// * [SidebarItems], the widget that displays [SidebarItem]s vertically +class SidebarItem with Diagnosticable { + /// Creates a sidebar item. + const SidebarItem({ + this.leading, + required this.label, + this.selectedColor, + this.unselectedColor, + this.shape, + this.focusNode, + this.semanticLabel, + this.disclosureItems, + }); + + /// The widget before [label]. + /// + /// Typically an [Icon] + final Widget? leading; + + /// Indicates what content this widget represents. + /// + /// Typically a [Text] + final Widget label; + + /// The color to paint this widget as when selected. + /// + /// If null, [MacosThemeData.primaryColor] is used. + final Color? selectedColor; + + /// The color to paint this widget as when unselected. + /// + /// Defaults to transparent. + final Color? unselectedColor; + + /// The [shape] property specifies the outline (border) of the + /// decoration. The shape must not be null. It's used alonside + /// [selectedColor]. + final ShapeBorder? shape; + + /// The focus node used by this item. + final FocusNode? focusNode; + + /// The semantic label used by screen readers. + final String? semanticLabel; + + /// The disclosure items. If null, there will be no disclosure items. + /// + /// If non-null and [leading] is null, a local animated icon is created + final List? disclosureItems; + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(ColorProperty('selectedColor', selectedColor)); + properties.add(ColorProperty('unselectedColor', unselectedColor)); + properties.add(StringProperty('semanticLabel', semanticLabel)); + properties.add(DiagnosticsProperty('shape', shape)); + properties.add(DiagnosticsProperty('focusNode', focusNode)); + properties.add(IterableProperty( + 'disclosure items', + disclosureItems, + )); + } +} diff --git a/lib/src/layout/sidebar_item.dart b/lib/src/layout/sidebar/sidebar_items.dart similarity index 75% rename from lib/src/layout/sidebar_item.dart rename to lib/src/layout/sidebar/sidebar_items.dart index 3088f676..358771ee 100644 --- a/lib/src/layout/sidebar_item.dart +++ b/lib/src/layout/sidebar/sidebar_items.dart @@ -1,4 +1,3 @@ -import 'package:flutter/foundation.dart'; import 'package:macos_ui/macos_ui.dart'; import 'package:macos_ui/src/library.dart'; @@ -7,76 +6,6 @@ const ShapeBorder _defaultShape = RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(7.0)), ); -/// A macOS style navigation-list item intended for use in a [Sidebar] -/// -/// See also: -/// -/// * [Sidebar], a side bar used alongside [MacosScaffold] -/// * [SidebarItems], the widget that displays [SidebarItem]s vertically -class SidebarItem with Diagnosticable { - /// Creates a sidebar item. - const SidebarItem({ - this.leading, - required this.label, - this.selectedColor, - this.unselectedColor, - this.shape, - this.focusNode, - this.semanticLabel, - this.disclosureItems, - }); - - /// The widget before [label]. - /// - /// Typically an [Icon] - final Widget? leading; - - /// Indicates what content this widget represents. - /// - /// Typically a [Text] - final Widget label; - - /// The color to paint this widget as when selected. - /// - /// If null, [MacosThemeData.primaryColor] is used. - final Color? selectedColor; - - /// The color to paint this widget as when unselected. - /// - /// Defaults to transparent. - final Color? unselectedColor; - - /// The [shape] property specifies the outline (border) of the - /// decoration. The shape must not be null. It's used alonside - /// [selectedColor]. - final ShapeBorder? shape; - - /// The focus node used by this item. - final FocusNode? focusNode; - - /// The semantic label used by screen readers. - final String? semanticLabel; - - /// The disclosure items. If null, there will be no disclosure items. - /// - /// If non-null and [leading] is null, a local animated icon is created - final List? disclosureItems; - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(ColorProperty('selectedColor', selectedColor)); - properties.add(ColorProperty('unselectedColor', unselectedColor)); - properties.add(StringProperty('semanticLabel', semanticLabel)); - properties.add(DiagnosticsProperty('shape', shape)); - properties.add(DiagnosticsProperty('focusNode', focusNode)); - properties.add(IterableProperty( - 'disclosure items', - disclosureItems, - )); - } -} - /// A scrollable widget that renders [SidebarItem]s. /// /// See also: @@ -296,26 +225,28 @@ class _SidebarItem extends StatelessWidget { vertical: 7 + theme.visualDensity.horizontal, horizontal: spacing, ), - child: Row(children: [ - if (hasLeading) - Padding( - padding: EdgeInsets.only(right: spacing), - child: MacosIconTheme.merge( - data: MacosIconThemeData( - color: selected - ? MacosColors.white - : CupertinoColors.systemBlue, + child: Row( + children: [ + if (hasLeading) + Padding( + padding: EdgeInsets.only(right: spacing), + child: MacosIconTheme.merge( + data: MacosIconThemeData( + color: selected + ? MacosColors.white + : MacosColors.controlAccentColor, + ), + child: item.leading!, ), - child: item.leading!, ), + DefaultTextStyle( + style: theme.typography.title3.copyWith( + color: selected ? textLuminance(selectedColor) : null, + ), + child: item.label, ), - DefaultTextStyle( - style: theme.typography.title3.copyWith( - color: selected ? textLuminance(selectedColor) : null, - ), - child: item.label, - ), - ]), + ], + ), ), ), ), @@ -392,8 +323,8 @@ class __DisclosureSidebarItemState extends State<_DisclosureSidebarItem> Widget _buildChildren(BuildContext context, Widget? child) { final theme = MacosTheme.of(context); - final double spacing = 10.0 + theme.visualDensity.horizontal; + return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -403,22 +334,24 @@ class __DisclosureSidebarItemState extends State<_DisclosureSidebarItem> child: _SidebarItem( item: SidebarItem( label: widget.item.label, - leading: Row(children: [ - if (widget.item.leading != null) - Padding( - padding: EdgeInsets.only(right: spacing), - child: widget.item.leading!, - ), - RotationTransition( - turns: _iconTurns, - child: Icon( - CupertinoIcons.chevron_right, - color: theme.brightness == Brightness.light - ? MacosColors.black - : MacosColors.white, + leading: Row( + children: [ + if (widget.item.leading != null) + Padding( + padding: EdgeInsets.only(right: spacing), + child: widget.item.leading!, + ), + RotationTransition( + turns: _iconTurns, + child: Icon( + CupertinoIcons.chevron_right, + color: theme.brightness == Brightness.light + ? MacosColors.black + : MacosColors.white, + ), ), - ), - ]), + ], + ), unselectedColor: MacosColors.transparent, focusNode: widget.item.focusNode, semanticLabel: widget.item.semanticLabel, @@ -450,7 +383,7 @@ class __DisclosureSidebarItemState extends State<_DisclosureSidebarItem> child: TickerMode( child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: widget.item.disclosureItems!.map((e) { + children: widget.item.disclosureItems!.map((item) { return Padding( padding: EdgeInsets.only( left: 24.0 + theme.visualDensity.horizontal, @@ -458,11 +391,9 @@ class __DisclosureSidebarItemState extends State<_DisclosureSidebarItem> child: SizedBox( width: double.infinity, child: _SidebarItem( - item: e, - onClick: () { - widget.onChanged?.call(e); - }, - selected: widget.selectedItem == e, + item: item, + onClick: () => widget.onChanged?.call(item), + selected: widget.selectedItem == item, ), ), ); diff --git a/lib/src/layout/window.dart b/lib/src/layout/window.dart index 05d244e8..4404aa48 100644 --- a/lib/src/layout/window.dart +++ b/lib/src/layout/window.dart @@ -6,7 +6,7 @@ import 'package:macos_ui/src/indicators/scrollbar.dart'; import 'package:macos_ui/src/layout/content_area.dart'; import 'package:macos_ui/src/layout/resizable_pane.dart'; import 'package:macos_ui/src/layout/scaffold.dart'; -import 'package:macos_ui/src/layout/sidebar.dart'; +import 'package:macos_ui/src/layout/sidebar/sidebar.dart'; import 'package:macos_ui/src/layout/title_bar.dart'; import 'package:macos_ui/src/library.dart'; import 'package:macos_ui/src/theme/macos_theme.dart'; @@ -159,6 +159,11 @@ class _MacosWindowState extends State { if (_sidebarScrollController.hasClients && _sidebarScrollController.offset > 0.0) Divider(thickness: 1, height: 1, color: dividerColor), + if (widget.sidebar!.top != null) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: widget.sidebar!.top!, + ), Expanded( child: MacosScrollbar( controller: _sidebarScrollController, @@ -170,7 +175,10 @@ class _MacosWindowState extends State { ), ), if (widget.sidebar?.bottom != null) - widget.sidebar!.bottom!, + Padding( + padding: const EdgeInsets.all(16.0), + child: widget.sidebar!.bottom!, + ), ], ), ), diff --git a/lib/src/theme/macos_theme.dart b/lib/src/theme/macos_theme.dart index a728883f..3e3d406a 100644 --- a/lib/src/theme/macos_theme.dart +++ b/lib/src/theme/macos_theme.dart @@ -205,9 +205,7 @@ class MacosThemeData with Diagnosticable { }) { final Brightness _brightness = brightness ?? Brightness.light; final bool isDark = _brightness == Brightness.dark; - primaryColor ??= isDark - ? CupertinoColors.activeBlue.darkColor - : CupertinoColors.activeBlue.color; + primaryColor ??= MacosColors.controlAccentColor; canvasColor ??= isDark ? CupertinoColors.systemBackground.darkElevatedColor : CupertinoColors.systemBackground; diff --git a/pubspec.lock b/pubspec.lock index 291472f9..dd867691 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -35,7 +35,7 @@ packages: name: args url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.3.0" async: dependency: transitive description: @@ -70,7 +70,7 @@ packages: name: cli_util url: "https://pub.dartlang.org" source: hosted - version: "0.3.0" + version: "0.3.5" clock: dependency: transitive description: @@ -91,7 +91,7 @@ packages: name: convert url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" coverage: dependency: transitive description: @@ -105,28 +105,28 @@ packages: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.2" csslib: dependency: transitive description: name: csslib url: "https://pub.dartlang.org" source: hosted - version: "0.17.0" + version: "0.17.1" dart_code_metrics: dependency: "direct dev" description: name: dart_code_metrics url: "https://pub.dartlang.org" source: hosted - version: "4.14.0" + version: "4.15.0" dart_style: dependency: transitive description: name: dart_style url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.2.1" fake_async: dependency: transitive description: @@ -140,7 +140,7 @@ packages: name: file url: "https://pub.dartlang.org" source: hosted - version: "6.1.1" + version: "6.1.2" flutter: dependency: "direct main" description: flutter @@ -171,7 +171,7 @@ packages: name: glob url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.2" html: dependency: transitive description: @@ -185,7 +185,7 @@ packages: name: http_multi_server url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.2.0" http_parser: dependency: transitive description: @@ -206,7 +206,7 @@ packages: name: js url: "https://pub.dartlang.org" source: hosted - version: "0.6.3" + version: "0.6.4" lints: dependency: transitive description: @@ -248,7 +248,7 @@ packages: name: mime url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.2" mocktail: dependency: "direct dev" description: @@ -269,7 +269,7 @@ packages: name: package_config url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.0.2" path: dependency: transitive description: @@ -277,13 +277,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.0" - pedantic: - dependency: transitive - description: - name: pedantic - url: "https://pub.dartlang.org" - source: hosted - version: "1.11.0" petitparser: dependency: transitive description: @@ -304,14 +297,14 @@ packages: name: pub_semver url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.1" shelf: dependency: transitive description: name: shelf url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.0" shelf_packages_handler: dependency: transitive description: @@ -428,28 +421,28 @@ packages: name: vm_service url: "https://pub.dartlang.org" source: hosted - version: "7.3.0" + version: "7.5.0" watcher: dependency: transitive description: name: watcher url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" web_socket_channel: dependency: transitive description: name: web_socket_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.2.0" webkit_inspection_protocol: dependency: transitive description: name: webkit_inspection_protocol url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" xml: dependency: transitive description: @@ -465,5 +458,5 @@ packages: source: hosted version: "3.1.0" sdks: - dart: ">=2.15.0 <3.0.0" + dart: ">=2.16.0 <3.0.0" flutter: ">=1.20.0" diff --git a/pubspec.yaml b/pubspec.yaml index fc01a6e2..9b9d0274 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.2.1+1 +version: 1.3.0 homepage: "https://github.com/GroovinChip/macos_ui" environment: