Skip to content

Commit

Permalink
Implemented Help Button (#51)
Browse files Browse the repository at this point in the history
* Implemented Help Button

* Implemented Help Button

* Implemented Help Button

* Implemented Help Button

* Implemented Help Button
  • Loading branch information
harshvsb1105 authored May 1, 2021
1 parent b056a35 commit f23cfed
Show file tree
Hide file tree
Showing 10 changed files with 349 additions and 19 deletions.
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]
* Implemented 'HelpButton'
=======
* 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
28 changes: 15 additions & 13 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 @@ -14,34 +14,36 @@ export 'package:flutter/material.dart'
FlutterLogo,
CircleAvatar;

export 'package:flutter/cupertino.dart'
show CupertinoColors, CupertinoDynamicColor, CupertinoIcons;
/// todo: package-level docs
export 'package:flutter/widgets.dart';

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({
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(
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

0 comments on commit f23cfed

Please sign in to comment.