From 2ac3de54c5813b05b929090a5d4e6c2ddf779cfe Mon Sep 17 00:00:00 2001 From: Bruno D'Luka <45696119+bdlukaa@users.noreply.github.com> Date: Sun, 9 May 2021 19:48:01 -0300 Subject: [PATCH 1/4] Implemente mouse cursors --- lib/src/buttons/checkbox.dart | 92 +++++++++++++++-------------- lib/src/buttons/help_button.dart | 96 +++++++++++++++--------------- lib/src/buttons/push_button.dart | 70 +++++++++++----------- lib/src/buttons/radio_button.dart | 98 ++++++++++++++++--------------- lib/src/fields/text_field.dart | 43 +++++++------- 5 files changed, 209 insertions(+), 190 deletions(-) diff --git a/lib/src/buttons/checkbox.dart b/lib/src/buttons/checkbox.dart index f4e6c907..089732d4 100644 --- a/lib/src/buttons/checkbox.dart +++ b/lib/src/buttons/checkbox.dart @@ -1,4 +1,5 @@ import 'package:flutter/foundation.dart'; +import 'package:flutter/rendering.dart'; import 'package:macos_ui/src/library.dart'; import 'package:macos_ui/macos_ui.dart'; @@ -82,54 +83,57 @@ class Checkbox extends StatelessWidget { Widget build(BuildContext context) { assert(debugCheckHasMacosTheme(context)); bool isLight = context.macosTheme.brightness != Brightness.dark; - return GestureDetector( - onTap: () { - if (value == null || value == false) { - onChanged?.call(true); - } else { - onChanged?.call(false); - } - }, - child: Semantics( - // value == true because [value] can be null - checked: value == true, - label: semanticLabel, - child: Container( - height: size, - width: size, - alignment: Alignment.center, - decoration: isDisabled || value == null || value == true - ? BoxDecoration( - color: DynamicColorX.macosResolve( - isDisabled - ? disabledColor - : activeColor ?? - context.macosTheme.primaryColor ?? - CupertinoColors.activeBlue, - context, - ), - borderRadius: BorderRadius.circular(4.0), - ) - : BoxDecoration( - color: isLight ? null : CupertinoColors.tertiaryLabel, - border: Border.all( - style: isLight ? BorderStyle.solid : BorderStyle.none, - width: 0.5, + return MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + onTap: () { + if (value == null || value == false) { + onChanged?.call(true); + } else { + onChanged?.call(false); + } + }, + child: Semantics( + // value == true because [value] can be null + checked: value == true, + label: semanticLabel, + child: Container( + height: size, + width: size, + alignment: Alignment.center, + decoration: isDisabled || value == null || value == true + ? BoxDecoration( color: DynamicColorX.macosResolve( - offBorderColor, + isDisabled + ? disabledColor + : activeColor ?? + context.macosTheme.primaryColor ?? + CupertinoColors.activeBlue, context, ), + borderRadius: BorderRadius.circular(4.0), + ) + : BoxDecoration( + color: isLight ? null : CupertinoColors.tertiaryLabel, + border: Border.all( + style: isLight ? BorderStyle.solid : BorderStyle.none, + width: 0.5, + color: DynamicColorX.macosResolve( + offBorderColor, + context, + ), + ), + borderRadius: BorderRadius.circular(4.0), ), - borderRadius: BorderRadius.circular(4.0), - ), - child: Icon( - isDisabled || value == false - ? null - : isMixed - ? CupertinoIcons.minus - : CupertinoIcons.check_mark, - color: CupertinoColors.white, - size: (size - 3).clamp(0, size), + child: Icon( + isDisabled || value == false + ? null + : isMixed + ? CupertinoIcons.minus + : CupertinoIcons.check_mark, + color: CupertinoColors.white, + size: (size - 3).clamp(0, size), + ), ), ), ), diff --git a/lib/src/buttons/help_button.dart b/lib/src/buttons/help_button.dart index 7aeb2f85..d86ff014 100644 --- a/lib/src/buttons/help_button.dart +++ b/lib/src/buttons/help_button.dart @@ -1,4 +1,5 @@ import 'package:flutter/foundation.dart'; +import 'package:flutter/rendering.dart'; import 'package:macos_ui/src/library.dart'; import 'package:macos_ui/macos_ui.dart'; @@ -170,52 +171,55 @@ class _HelpButtonState extends State ? Color.fromRGBO(255, 255, 255, 0.25) : Color.fromRGBO(0, 0, 0, 0.25); - return GestureDetector( - behavior: HitTestBehavior.opaque, - onTapDown: enabled ? _handleTapDown : null, - onTapUp: enabled ? _handleTapUp : null, - onTapCancel: enabled ? _handleTapCancel : null, - onTap: widget.onPressed, - child: Semantics( - label: widget.semanticLabel, - button: true, - child: ConstrainedBox( - constraints: BoxConstraints( - minWidth: 20, - minHeight: 20, - ), - child: FadeTransition( - opacity: _opacityAnimation, - child: DecoratedBox( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: !enabled - ? DynamicColorX.macosResolve(disabledColor!, context) - : backgroundColor, - boxShadow: [ - BoxShadow( - color: Color.fromRGBO(0, 0, 0, 0.1), - offset: Offset(-0.1, -0.1), - ), - BoxShadow( - color: Color.fromRGBO(0, 0, 0, 0.1), - offset: Offset(0.1, 0.1), - ), - BoxShadow( - color: CupertinoColors.tertiarySystemFill, - offset: Offset(0, 0), - ), - ], - ), - child: Padding( - padding: EdgeInsets.all(8), - child: Align( - alignment: widget.alignment, - widthFactor: 1.0, - heightFactor: 1.0, - child: Icon( - CupertinoIcons.question, - color: foregroundColor, + return MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTapDown: enabled ? _handleTapDown : null, + onTapUp: enabled ? _handleTapUp : null, + onTapCancel: enabled ? _handleTapCancel : null, + onTap: widget.onPressed, + child: Semantics( + label: widget.semanticLabel, + button: true, + child: ConstrainedBox( + constraints: BoxConstraints( + minWidth: 20, + minHeight: 20, + ), + child: FadeTransition( + opacity: _opacityAnimation, + child: DecoratedBox( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: !enabled + ? DynamicColorX.macosResolve(disabledColor!, context) + : backgroundColor, + boxShadow: [ + BoxShadow( + color: Color.fromRGBO(0, 0, 0, 0.1), + offset: Offset(-0.1, -0.1), + ), + BoxShadow( + color: Color.fromRGBO(0, 0, 0, 0.1), + offset: Offset(0.1, 0.1), + ), + BoxShadow( + color: CupertinoColors.tertiarySystemFill, + offset: Offset(0, 0), + ), + ], + ), + child: Padding( + padding: EdgeInsets.all(8), + child: Align( + alignment: widget.alignment, + widthFactor: 1.0, + heightFactor: 1.0, + child: Icon( + CupertinoIcons.question, + color: foregroundColor, + ), ), ), ), diff --git a/lib/src/buttons/push_button.dart b/lib/src/buttons/push_button.dart index cadd627e..01583bec 100644 --- a/lib/src/buttons/push_button.dart +++ b/lib/src/buttons/push_button.dart @@ -1,4 +1,5 @@ import 'package:flutter/foundation.dart'; +import 'package:flutter/rendering.dart'; import 'package:macos_ui/src/library.dart'; import 'package:macos_ui/macos_ui.dart'; @@ -232,39 +233,42 @@ class _PushButtonState extends State final TextStyle textStyle = theme.typography!.headline!.copyWith(color: foregroundColor); - return GestureDetector( - behavior: HitTestBehavior.opaque, - onTapDown: enabled ? _handleTapDown : null, - onTapUp: enabled ? _handleTapUp : null, - onTapCancel: enabled ? _handleTapCancel : null, - onTap: widget.onPressed, - child: Semantics( - button: true, - label: widget.semanticLabel, - child: ConstrainedBox( - constraints: BoxConstraints( - minWidth: 49, - minHeight: 20, - ), - child: FadeTransition( - opacity: _opacityAnimation, - child: DecoratedBox( - decoration: BoxDecoration( - borderRadius: borderRadius, - color: !enabled - ? DynamicColorX.macosResolve(disabledColor, context) - : backgroundColor, - ), - child: Padding( - padding: buttonPadding!, - child: Align( - alignment: widget.alignment, - widthFactor: 1.0, - heightFactor: 1.0, - // TODO(groovin): show proper text color in light theme - child: DefaultTextStyle( - style: textStyle, - child: widget.child, + return MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTapDown: enabled ? _handleTapDown : null, + onTapUp: enabled ? _handleTapUp : null, + onTapCancel: enabled ? _handleTapCancel : null, + onTap: widget.onPressed, + child: Semantics( + button: true, + label: widget.semanticLabel, + child: ConstrainedBox( + constraints: BoxConstraints( + minWidth: 49, + minHeight: 20, + ), + child: FadeTransition( + opacity: _opacityAnimation, + child: DecoratedBox( + decoration: BoxDecoration( + borderRadius: borderRadius, + color: !enabled + ? DynamicColorX.macosResolve(disabledColor, context) + : backgroundColor, + ), + child: Padding( + padding: buttonPadding!, + child: Align( + alignment: widget.alignment, + widthFactor: 1.0, + heightFactor: 1.0, + // TODO(groovin): show proper text color in light theme + child: DefaultTextStyle( + style: textStyle, + child: widget.child, + ), ), ), ), diff --git a/lib/src/buttons/radio_button.dart b/lib/src/buttons/radio_button.dart index aab04c43..d90dc90f 100644 --- a/lib/src/buttons/radio_button.dart +++ b/lib/src/buttons/radio_button.dart @@ -1,4 +1,5 @@ import 'package:flutter/foundation.dart'; +import 'package:flutter/rendering.dart'; import 'package:macos_ui/src/library.dart'; import 'package:macos_ui/macos_ui.dart'; @@ -80,57 +81,60 @@ class RadioButton extends StatelessWidget { Widget build(BuildContext context) { assert(debugCheckHasMacosTheme(context)); final isLight = context.macosTheme.brightness != Brightness.dark; - return GestureDetector( - onTap: () => onChanged?.call(!value), - child: Semantics( - checked: value, - label: semanticLabel, - child: Container( - height: size, - width: size, - decoration: BoxDecoration( - border: Border.all( - style: isDisabled ? BorderStyle.none : BorderStyle.solid, - width: value ? size / 4.0 : 1, - color: DynamicColorX.macosResolve( - value - ? onColor ?? - context.macosTheme.primaryColor ?? - CupertinoColors.activeBlue - : offColor, - context, - ), - ), - shape: BoxShape.circle, - ), - // The inner color is inside another container because it sometimes - // overlap the border when used together + return MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + onTap: () => onChanged?.call(!value), + child: Semantics( + checked: value, + label: semanticLabel, child: Container( + height: size, + width: size, decoration: BoxDecoration( - shape: BoxShape.circle, - color: DynamicColorX.macosResolve( - innerColor ?? - (isDisabled - ? CupertinoColors.quaternarySystemFill - : value || isLight - ? CupertinoColors.white - : CupertinoColors.tertiarySystemFill), - context, - ), - boxShadow: [ - BoxShadow( - color: Color.fromRGBO(0, 0, 0, 0.05), - offset: Offset(-0.05, -0.05), + border: Border.all( + style: isDisabled ? BorderStyle.none : BorderStyle.solid, + width: value ? size / 4.0 : 1, + color: DynamicColorX.macosResolve( + value + ? onColor ?? + context.macosTheme.primaryColor ?? + CupertinoColors.activeBlue + : offColor, + context, ), - BoxShadow( - color: Color.fromRGBO(0, 0, 0, 0.05), - offset: Offset(0.05, 0.05), - ), - BoxShadow( - color: CupertinoColors.tertiarySystemFill, - offset: Offset(0, 0), + ), + shape: BoxShape.circle, + ), + // The inner color is inside another container because it sometimes + // overlap the border when used together + child: Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: DynamicColorX.macosResolve( + innerColor ?? + (isDisabled + ? CupertinoColors.quaternarySystemFill + : value || isLight + ? CupertinoColors.white + : CupertinoColors.tertiarySystemFill), + context, ), - ], + boxShadow: [ + BoxShadow( + color: Color.fromRGBO(0, 0, 0, 0.05), + offset: Offset(-0.05, -0.05), + ), + BoxShadow( + color: Color.fromRGBO(0, 0, 0, 0.05), + offset: Offset(0.05, 0.05), + ), + BoxShadow( + color: CupertinoColors.tertiarySystemFill, + offset: Offset(0, 0), + ), + ], + ), ), ), ), diff --git a/lib/src/fields/text_field.dart b/lib/src/fields/text_field.dart index 51ec1134..10fd9e06 100644 --- a/lib/src/fields/text_field.dart +++ b/lib/src/fields/text_field.dart @@ -1121,26 +1121,29 @@ class _TextFieldState extends State widget.suffix! // Otherwise, try to show a clear button if its visibility mode matches. else if (_showClearButton(text)) - GestureDetector( - key: _clearGlobalKey, - onTap: widget.enabled ?? true - ? () { - // Special handle onChanged for ClearButton - // Also call onChanged when the clear button is tapped. - final bool textChanged = - _effectiveController.text.isNotEmpty; - _effectiveController.clear(); - if (widget.onChanged != null && textChanged) - widget.onChanged!(_effectiveController.text); - } - : null, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 6.0), - child: Icon( - CupertinoIcons.clear_thick_circled, - size: 18.0, - color: - DynamicColorX.macosResolve(_kClearButtonColor, context), + MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + key: _clearGlobalKey, + onTap: widget.enabled ?? true + ? () { + // Special handle onChanged for ClearButton + // Also call onChanged when the clear button is tapped. + final bool textChanged = + _effectiveController.text.isNotEmpty; + _effectiveController.clear(); + if (widget.onChanged != null && textChanged) + widget.onChanged!(_effectiveController.text); + } + : null, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 6.0), + child: Icon( + CupertinoIcons.clear_thick_circled, + size: 18.0, + color: + DynamicColorX.macosResolve(_kClearButtonColor, context), + ), ), ), ), From 120efca8fb96f17afb2c2ff3706e3bd937f9159b Mon Sep 17 00:00:00 2001 From: Bruno D'Luka <45696119+bdlukaa@users.noreply.github.com> Date: Sun, 9 May 2021 19:57:35 -0300 Subject: [PATCH 2/4] Removed mouse cursor from checkbox and radio button --- lib/src/buttons/checkbox.dart | 91 ++++++++++++++--------------- lib/src/buttons/radio_button.dart | 97 +++++++++++++++---------------- 2 files changed, 91 insertions(+), 97 deletions(-) diff --git a/lib/src/buttons/checkbox.dart b/lib/src/buttons/checkbox.dart index 089732d4..0e01094e 100644 --- a/lib/src/buttons/checkbox.dart +++ b/lib/src/buttons/checkbox.dart @@ -83,57 +83,54 @@ class Checkbox extends StatelessWidget { Widget build(BuildContext context) { assert(debugCheckHasMacosTheme(context)); bool isLight = context.macosTheme.brightness != Brightness.dark; - return MouseRegion( - cursor: SystemMouseCursors.click, - child: GestureDetector( - onTap: () { - if (value == null || value == false) { - onChanged?.call(true); - } else { - onChanged?.call(false); - } - }, - child: Semantics( - // value == true because [value] can be null - checked: value == true, - label: semanticLabel, - child: Container( - height: size, - width: size, - alignment: Alignment.center, - decoration: isDisabled || value == null || value == true - ? BoxDecoration( + return GestureDetector( + onTap: () { + if (value == null || value == false) { + onChanged?.call(true); + } else { + onChanged?.call(false); + } + }, + child: Semantics( + // value == true because [value] can be null + checked: value == true, + label: semanticLabel, + child: Container( + height: size, + width: size, + alignment: Alignment.center, + decoration: isDisabled || value == null || value == true + ? BoxDecoration( + color: DynamicColorX.macosResolve( + isDisabled + ? disabledColor + : activeColor ?? + context.macosTheme.primaryColor ?? + CupertinoColors.activeBlue, + context, + ), + borderRadius: BorderRadius.circular(4.0), + ) + : BoxDecoration( + color: isLight ? null : CupertinoColors.tertiaryLabel, + border: Border.all( + style: isLight ? BorderStyle.solid : BorderStyle.none, + width: 0.5, color: DynamicColorX.macosResolve( - isDisabled - ? disabledColor - : activeColor ?? - context.macosTheme.primaryColor ?? - CupertinoColors.activeBlue, + offBorderColor, context, ), - borderRadius: BorderRadius.circular(4.0), - ) - : BoxDecoration( - color: isLight ? null : CupertinoColors.tertiaryLabel, - border: Border.all( - style: isLight ? BorderStyle.solid : BorderStyle.none, - width: 0.5, - color: DynamicColorX.macosResolve( - offBorderColor, - context, - ), - ), - borderRadius: BorderRadius.circular(4.0), ), - child: Icon( - isDisabled || value == false - ? null - : isMixed - ? CupertinoIcons.minus - : CupertinoIcons.check_mark, - color: CupertinoColors.white, - size: (size - 3).clamp(0, size), - ), + borderRadius: BorderRadius.circular(4.0), + ), + child: Icon( + isDisabled || value == false + ? null + : isMixed + ? CupertinoIcons.minus + : CupertinoIcons.check_mark, + color: CupertinoColors.white, + size: (size - 3).clamp(0, size), ), ), ), diff --git a/lib/src/buttons/radio_button.dart b/lib/src/buttons/radio_button.dart index d90dc90f..71cd35ac 100644 --- a/lib/src/buttons/radio_button.dart +++ b/lib/src/buttons/radio_button.dart @@ -81,60 +81,57 @@ class RadioButton extends StatelessWidget { Widget build(BuildContext context) { assert(debugCheckHasMacosTheme(context)); final isLight = context.macosTheme.brightness != Brightness.dark; - return MouseRegion( - cursor: SystemMouseCursors.click, - child: GestureDetector( - onTap: () => onChanged?.call(!value), - child: Semantics( - checked: value, - label: semanticLabel, + return GestureDetector( + onTap: () => onChanged?.call(!value), + child: Semantics( + checked: value, + label: semanticLabel, + child: Container( + height: size, + width: size, + decoration: BoxDecoration( + border: Border.all( + style: isDisabled ? BorderStyle.none : BorderStyle.solid, + width: value ? size / 4.0 : 1, + color: DynamicColorX.macosResolve( + value + ? onColor ?? + context.macosTheme.primaryColor ?? + CupertinoColors.activeBlue + : offColor, + context, + ), + ), + shape: BoxShape.circle, + ), + // The inner color is inside another container because it sometimes + // overlap the border when used together child: Container( - height: size, - width: size, decoration: BoxDecoration( - border: Border.all( - style: isDisabled ? BorderStyle.none : BorderStyle.solid, - width: value ? size / 4.0 : 1, - color: DynamicColorX.macosResolve( - value - ? onColor ?? - context.macosTheme.primaryColor ?? - CupertinoColors.activeBlue - : offColor, - context, - ), - ), shape: BoxShape.circle, - ), - // The inner color is inside another container because it sometimes - // overlap the border when used together - child: Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: DynamicColorX.macosResolve( - innerColor ?? - (isDisabled - ? CupertinoColors.quaternarySystemFill - : value || isLight - ? CupertinoColors.white - : CupertinoColors.tertiarySystemFill), - context, - ), - boxShadow: [ - BoxShadow( - color: Color.fromRGBO(0, 0, 0, 0.05), - offset: Offset(-0.05, -0.05), - ), - BoxShadow( - color: Color.fromRGBO(0, 0, 0, 0.05), - offset: Offset(0.05, 0.05), - ), - BoxShadow( - color: CupertinoColors.tertiarySystemFill, - offset: Offset(0, 0), - ), - ], + color: DynamicColorX.macosResolve( + innerColor ?? + (isDisabled + ? CupertinoColors.quaternarySystemFill + : value || isLight + ? CupertinoColors.white + : CupertinoColors.tertiarySystemFill), + context, ), + boxShadow: [ + BoxShadow( + color: Color.fromRGBO(0, 0, 0, 0.05), + offset: Offset(-0.05, -0.05), + ), + BoxShadow( + color: Color.fromRGBO(0, 0, 0, 0.05), + offset: Offset(0.05, 0.05), + ), + BoxShadow( + color: CupertinoColors.tertiarySystemFill, + offset: Offset(0, 0), + ), + ], ), ), ), From c2cd4a7ea84fa6ef33846e6f422deea0399b08e2 Mon Sep 17 00:00:00 2001 From: Bruno D'Luka <45696119+bdlukaa@users.noreply.github.com> Date: Sun, 9 May 2021 20:20:03 -0300 Subject: [PATCH 3/4] Implemented mouse cursor for text field --- lib/src/fields/text_field.dart | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/src/fields/text_field.dart b/lib/src/fields/text_field.dart index 10fd9e06..9b1dea2e 100644 --- a/lib/src/fields/text_field.dart +++ b/lib/src/fields/text_field.dart @@ -1349,7 +1349,7 @@ class _TextFieldState extends State ), ); - final Widget child = Semantics( + Widget child = Semantics( enabled: enabled, onTap: !enabled || widget.readOnly ? null @@ -1389,6 +1389,11 @@ class _TextFieldState extends State ), ); + child = MouseRegion( + cursor: SystemMouseCursors.text, + child: child, + ); + if (kIsWeb) { return Shortcuts( shortcuts: scrollShortcutOverrides, From 6f1060118f6d4077ed03d88d23c633753b3bd82f Mon Sep 17 00:00:00 2001 From: Bruno D'Luka <45696119+bdlukaa@users.noreply.github.com> Date: Sun, 9 May 2021 21:20:04 -0300 Subject: [PATCH 4/4] Bump version --- CHANGELOG.md | 3 +++ example/pubspec.lock | 2 +- pubspec.yaml | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35ac6e8f..697a1246 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [0.0.12] +* Add mouse cursors to help button, push button and `TextField` + ## [0.0.11] * Implement `TextField` diff --git a/example/pubspec.lock b/example/pubspec.lock index 6925f62e..df2fecfe 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -73,7 +73,7 @@ packages: path: ".." relative: true source: path - version: "0.0.11" + version: "0.0.12" matcher: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 2b61bbab..147f51c2 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: 0.0.11 +version: 0.0.12 homepage: 'https://github.com/GroovinChip/macos_ui' environment: