Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented Help Button #51

Merged
merged 7 commits into from
May 1, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
## [0.0.8]
## [0.0.9]
harshvsb1105 marked this conversation as resolved.
Show resolved Hide resolved
* Implemented 'HelpButton'
=======
harshvsb1105 marked this conversation as resolved.
Show resolved Hide resolved
* Fixed [#49](https://github.com/GroovinChip/macos_ui/issues/49)

## [0.0.7]
Expand Down
3 changes: 3 additions & 0 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ class _DemoState extends State<Demo> {
value: value,
onChanged: (v) => setState(() => value = v),
),
HelpButton(
onPressed: () {},
),
Padding(
padding: const EdgeInsets.all(8.0),
child: CapacityIndicator(
Expand Down
2 changes: 1 addition & 1 deletion example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ packages:
path: ".."
relative: true
source: path
version: "0.0.8"
version: "0.0.9"
matcher:
dependency: transitive
description:
Expand Down
29 changes: 15 additions & 14 deletions lib/macos_ui.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
library macos_ui;

/// todo: package-level docs
export 'package:flutter/widgets.dart';
export 'package:flutter/cupertino.dart'
show CupertinoColors, CupertinoDynamicColor, CupertinoIcons;
export 'package:flutter/cupertino.dart'
show CupertinoColors, CupertinoDynamicColor, CupertinoIcons;
export 'package:flutter/material.dart'
Expand All @@ -13,35 +13,36 @@ export 'package:flutter/material.dart'
PageTransitionsBuilder,
FlutterLogo,
CircleAvatar;
/// todo: package-level docs
export 'package:flutter/widgets.dart';

export 'package:flutter/cupertino.dart'
show CupertinoColors, CupertinoDynamicColor, CupertinoIcons;

export 'src/buttons/checkbox.dart';
export 'src/buttons/help_button.dart';
export 'src/buttons/help_button_theme.dart';
export 'src/buttons/push_button.dart';
export 'src/buttons/push_button_theme.dart';
export 'src/buttons/radio_button.dart';
export 'src/buttons/switch.dart';
export 'src/buttons/switch.dart';
export 'src/buttons/switch.dart';
export 'src/buttons/switch.dart';
export 'src/buttons/switch.dart';
export 'src/indicators/capacity_indicators.dart';
export 'src/indicators/progress_indicators.dart';
export 'src/indicators/progress_indicators.dart';
export 'src/indicators/progress_indicators.dart';
export 'src/indicators/rating_indicator.dart';
export 'src/indicators/relevance_indicator.dart';
export 'src/layout/scaffold.dart';
export 'src/layout/scaffold.dart';
export 'src/layout/scaffold.dart';
export 'src/layout/scaffold.dart';
export 'src/macos_app.dart';
export 'src/macos_app.dart';
export 'src/styles/colors.dart';
export 'src/styles/macos_theme.dart';
export 'src/styles/macos_theme_data.dart';
export 'src/styles/typography.dart';
export 'src/buttons/radio_button.dart';
export 'src/buttons/checkbox.dart';
export 'src/layout/scaffold.dart';
export 'src/buttons/switch.dart';
export 'src/styles/typography.dart';
export 'src/styles/colors.dart';
export 'src/util.dart';
export 'src/util.dart';
export 'src/indicators/capacity_indicators.dart';
export 'src/indicators/progress_indicators.dart';
export 'src/indicators/rating_indicator.dart';
export 'src/indicators/relevance_indicator.dart';
213 changes: 213 additions & 0 deletions lib/src/buttons/help_button.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
import 'package:flutter/foundation.dart';
import '../../macos_ui.dart';

/// A help button appears within a view and opens app-specific help documentation when clicked.
/// For help documentation creation guidance, see Help. All help buttons are circular,
/// consistently sized buttons that contain a question mark icon. Whenever possible,
/// open a help topic related to the current context. For example,
/// the Rules pane of Mail preferences includes a help button.
/// When clicked, it opens directly to a Rules preferences help topic.
class HelpButton extends StatefulWidget {
///pressedOpacity, if non-null, must be in the range if 0.0 to 1.0
const HelpButton({
harshvsb1105 marked this conversation as resolved.
Show resolved Hide resolved
Key? key,
this.color,
this.disabledColor,
this.onPressed,
this.pressedOpacity = 0.4,
this.alignment = Alignment.center,
this.semanticLabel,
}) : assert(pressedOpacity == null ||
(pressedOpacity >= 0.0 && pressedOpacity <= 1.0)),
super(key: key);

/// The color of the button's background.
final Color? color;

/// The color of the button's background when the button is disabled.
///
/// Ignored if the [HelpButton] doesn't also have a [color].
///
/// Defaults to [CupertinoColors.quaternarySystemFill] when [color] is
/// specified.
final Color? disabledColor;

/// The callback that is called when the button is tapped or otherwise activated.
///
/// If this is set to null, the button will be disabled.
final VoidCallback? onPressed;

/// The opacity that the button will fade to when it is pressed.
/// The button will have an opacity of 1.0 when it is not pressed.
///
/// This defaults to 0.4. If null, opacity will not change on pressed if using
/// your own custom effects is desired.
final double? pressedOpacity;

/// The alignment of the button's [child].
///
/// Typically buttons are sized to be just big enough to contain the child and its
/// [padding]. If the button's size is constrained to a fixed size, for example by
/// enclosing it with a [SizedBox], this property defines how the child is aligned
/// within the available space.
///
/// Always defaults to [Alignment.center].
final AlignmentGeometry alignment;

///Provides a textual description of the button.
final String? semanticLabel;

/// Whether the button is enabled or disabled. Buttons are disabled by default. To
/// enable a button, set its [onPressed] property to a non-null value.
bool get enabled => onPressed != null;

@override
_HelpButtonState createState() => _HelpButtonState();
}

class _HelpButtonState extends State<HelpButton>
with SingleTickerProviderStateMixin {
// Eyeballed values. Feel free to tweak.
static const Duration kFadeOutDuration = Duration(milliseconds: 10);
static const Duration kFadeInDuration = Duration(milliseconds: 100);
final Tween<double> _opacityTween = Tween<double>(begin: 1.0);

late AnimationController _animationController;
late Animation<double> _opacityAnimation;

@override
void initState() {
super.initState();
_animationController = AnimationController(
duration: const Duration(milliseconds: 200),
value: 0.0,
vsync: this,
);
_opacityAnimation = _animationController
.drive(CurveTween(curve: Curves.decelerate))
.drive(_opacityTween);
_setTween();
}

@override
void didUpdateWidget(HelpButton old) {
super.didUpdateWidget(old);
_setTween();
}

void _setTween() {
_opacityTween.end = widget.pressedOpacity ?? 1.0;
}

@override
void dispose() {
_animationController.dispose();
super.dispose();
}

bool _buttonHeldDown = false;

void _handleTapDown(TapDownDetails event) {
if (!_buttonHeldDown) {
_buttonHeldDown = true;
_animate();
}
}

void _handleTapUp(TapUpDetails event) {
if (_buttonHeldDown) {
_buttonHeldDown = false;
_animate();
}
}

void _handleTapCancel() {
if (_buttonHeldDown) {
_buttonHeldDown = false;
_animate();
}
}

void _animate() {
if (_animationController.isAnimating) return;
final bool wasHeldDown = _buttonHeldDown;
final TickerFuture ticker = _buttonHeldDown
? _animationController.animateTo(1.0, duration: kFadeOutDuration)
: _animationController.animateTo(0.0, duration: kFadeInDuration);
ticker.then<void>((void value) {
if (mounted && wasHeldDown != _buttonHeldDown) _animate();
});
}

@override
Widget build(BuildContext context) {
final bool enabled = widget.enabled;
final MacosThemeData theme = MacosTheme.of(context);
final Color? backgroundColor = DynamicColorX.macosResolve(
widget.color ?? theme.helpButtonTheme.color, context);

final Color? disabledColor = DynamicColorX.macosResolve(
widget.disabledColor ?? theme.helpButtonTheme.disabledColor, context);

final Color? foregroundColor = widget.enabled
? iconLuminance(backgroundColor!, theme.brightness!.isDark)
: theme.brightness!.isDark
? 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(
harshvsb1105 marked this conversation as resolved.
Show resolved Hide resolved
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,
),
),
),
),
),
),
),
);
}
}
87 changes: 87 additions & 0 deletions lib/src/buttons/help_button_theme.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import 'package:flutter/foundation.dart';
import 'package:macos_ui/macos_ui.dart';

/// Overrides the default style of its [HelpButton] descendants.
///
/// See also:
///
/// * [HelpButtonThemeData], which is used to configure this theme.
class HelpButtonTheme extends InheritedTheme {
/// Create a [HelpButtonTheme].
///
/// The [data] parameter must not be null.
const HelpButtonTheme({
Key? key,
required this.data,
required Widget child,
}) : super(key: key, child: child);

/// The configuration of this theme.
final HelpButtonThemeData data;

/// The closest instance of this class that encloses the given context.
///
/// If there is no enclosing [HelpButtonTheme] widget, then
/// [MacosThemeData.helpButtonTheme] is used.
///
/// Typical usage is as follows:
///
/// ```dart
/// HelpButtonTheme theme = HelpButtonTheme.of(context);
/// ```
static HelpButtonThemeData of(BuildContext context) {
final HelpButtonTheme? buttonTheme =
context.dependOnInheritedWidgetOfExactType<HelpButtonTheme>();
return buttonTheme?.data ?? MacosTheme.of(context).helpButtonTheme;
}

@override
Widget wrap(BuildContext context, Widget child) {
return HelpButtonTheme(data: data, child: child);
}

@override
bool updateShouldNotify(HelpButtonTheme oldWidget) => data != oldWidget.data;
}

/// A style that overrides the default appearance of
/// [HelpButton]s when it's used with [HelpButtonTheme] or with the
/// overall [MacosTheme]'s [MacosThemeData.helpButtonTheme].
///
/// See also:
///
/// * [HelpButtonTheme], the theme which is configured with this class.
/// * [MacosThemeData.helpButtonTheme], which can be used to override the default
/// style for [HelpButton]s below the overall [MacosTheme].
class HelpButtonThemeData with Diagnosticable {
/// Creates a [HelpButtonThemeData].
///
/// The [style] may be null.
const HelpButtonThemeData({
required this.color,
required this.disabledColor,
});

/// The default background color for [HelpButton]
final Color color;

/// The default disabled color for [HelpButton]
final Color disabledColor;

HelpButtonThemeData copyWith(HelpButtonThemeData? themeData) {
if (themeData == null) {
return this;
}
return HelpButtonThemeData(
color: themeData.color,
disabledColor: themeData.disabledColor,
);
}

@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(ColorProperty('color', color));
properties.add(ColorProperty('disabledColor', disabledColor));
}
}
3 changes: 1 addition & 2 deletions lib/src/buttons/switch.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import 'package:flutter/cupertino.dart' as c;
import 'package:flutter/gestures.dart';
import 'package:macos_ui/macos_ui.dart';

import 'package:flutter/cupertino.dart' as c;

/// A switch is a visual toggle between two mutually exclusive
/// states — on and off. A switch shows that it's on when the
/// accent color is visible and off when the switch appears colorless.
Expand Down
Loading