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

Teaching tip #570

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
20 changes: 14 additions & 6 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -308,19 +308,27 @@ class _MyHomePageState extends State<MyHomePage> with WindowListener {
),
),
PaneItem(
icon: const Icon(FluentIcons.hint_text),
title: const Text('Tooltip'),
icon: const Icon(FluentIcons.pop_expand),
title: const Text('Flyout'),
body: DeferredWidget(
surfaces.loadLibrary,
() => popups.TooltipPage(),
() => popups.Flyout2Screen(),
),
),
PaneItem(
icon: const Icon(FluentIcons.pop_expand),
title: const Text('Flyout'),
icon: const Icon(FluentIcons.field_filled),
title: const Text('Teaching Tip'),
body: DeferredWidget(
surfaces.loadLibrary,
() => popups.Flyout2Screen(),
() => surfaces.TeachingTipPage(),
),
),
PaneItem(
icon: const Icon(FluentIcons.hint_text),
title: const Text('Tooltip'),
body: DeferredWidget(
surfaces.loadLibrary,
() => popups.TooltipPage(),
),
),
PaneItemHeader(header: const Text('Theming')),
Expand Down
1 change: 1 addition & 0 deletions example/lib/routes/surfaces.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ export '../screens/surface/commandbars.dart';
export '../screens/surface/expander.dart';
export '../screens/surface/info_bars.dart';
export '../screens/surface/progress_indicators.dart';
export '../screens/popups/teaching_tip.dart';
export '../screens/surface/tiles.dart';
211 changes: 211 additions & 0 deletions example/lib/screens/popups/teaching_tip.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
import 'package:example/theme.dart';
import 'package:example/widgets/card_highlight.dart';
import 'package:example/widgets/page.dart';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:provider/provider.dart';

class TeachingTipPage extends StatefulWidget {
const TeachingTipPage({Key? key}) : super(key: key);

@override
State<TeachingTipPage> createState() => _TeachingTipPageState();
}

class _TeachingTipPageState extends State<TeachingTipPage> with PageMixin {
final nonTargetedController = FlyoutController();

static const alignments = {
'Bottom left': Alignment.bottomLeft,
'Bottom center': Alignment.bottomCenter,
'Bottom right': Alignment.bottomRight,
'Center': Alignment.center,
'Top left': Alignment.topLeft,
'Top center': Alignment.topCenter,
'Top right': Alignment.topRight,
};
static const placements = {
'Bottom left': FlyoutPlacementMode.bottomLeft,
'Bottom center': FlyoutPlacementMode.bottomCenter,
'Bottom right': FlyoutPlacementMode.bottomRight,
'Center': FlyoutPlacementMode.left,
'Top left': FlyoutPlacementMode.topLeft,
'Top center': FlyoutPlacementMode.topCenter,
'Top right': FlyoutPlacementMode.topRight,
};
late String alignment = 'Bottom center';
final targetedController = FlyoutController();

@override
void dispose() {
nonTargetedController.dispose();
targetedController.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
final theme = FluentTheme.of(context);
final appTheme = context.watch<AppTheme>();

return ScaffoldPage.scrollable(
header: const PageHeader(title: Text('Teaching Tip')),
children: [
description(
content: const Text(
'A teaching tip is a semi-persistent and content-rich flyout '
'that provides contextual information. It is often used for '
'informing, reminding, and teaching users about important and new '
'features that may enhance their experience.',
),
),
subtitle(
content: const Text('Show a non-targeted TeachingTip with buttons'),
),
CardHighlight(
child: Row(children: [
FlyoutTarget(
controller: nonTargetedController,
child: Button(
child: const Text('Show TeachingTip'),
onPressed: () {
showTeachingTip(
flyoutController: nonTargetedController,
nonTargetedAlignment: alignments[alignment],
placementMode: placements[alignment]!,
builder: (context) => TeachingTip(
title: const Text('Change themes without hassle'),
subtitle: const Text(
'It\'s easier to see control samples in both light and dark theme',
),
buttons: [
Button(
child: const Text('Toggle theme now'),
onPressed: () {
if (theme.brightness.isDark) {
appTheme.mode = ThemeMode.light;
} else {
appTheme.mode = ThemeMode.dark;
}
Navigator.of(context).pop();
},
),
Button(
child: const Text('Got it'),
onPressed: Navigator.of(context).pop,
),
],
),
);
},
),
),
const SizedBox(width: 18.0),
SizedBox(
width: 150.0,
child: ComboBox<String>(
placeholder: const Text('Alignment'),
items: List.generate(alignments.length, (index) {
final entry = alignments.entries.elementAt(index);

return ComboBoxItem(
value: entry.key,
child: Text(entry.key.uppercaseFirst()),
);
}),
value: alignment,
onChanged: (a) {
if (a != null) setState(() => alignment = a);
},
),
),
]),
codeSnippet: '''final teachingTip = TeachingTip(
title: Text('Change themes without hassle'),
subtitle: Text(
'It's easier to see control samples in both light and dark theme',
),
buttons: <Widget>[
Button(
child: const Text('Toggle theme now'),
onPressed: () {
// toggle theme here

// then close the popup
Navigator.of(context).pop();
},
),
Button(
child: const Text('Got it'),
onPressed: Navigator.of(context).pop,
),
],
),

showTeachingTip(
context: context,
teachingTip: teachingTip,
);''',
),
// subtitle(
// content: const Text('Show a targeted TeachingTip'),
// ),
// CardHighlight(
// child: Row(
// children: [
// Button(
// child: const Text('Show TeachingTip'),
// onPressed: () {
// targetKey.currentState?.showTeachingTip(builder: (context) {
// return const TeachingTip(
// alignment: Alignment.bottomCenter,
// placementMargin: EdgeInsets.all(20.0),
// title: Text('Change themes without hassle'),
// subtitle: Text(
// 'It\'s easier to see control samples in both light and dark theme',
// ),
// );
// });
// },
// ),
// const Spacer(),
// TeachingTipTarget(
// key: targetKey,
// child: Container(
// height: 100,
// width: 200,
// color: theme.accentColor.defaultBrushFor(theme.brightness),
// ),
// ),
// ],
// ),
// codeSnippet: '''final teachingTip = TeachingTip(
// title: Text('Change themes without hassle'),
// subtitle: Text(
// 'It's easier to see control samples in both light and dark theme',
// ),
// buttons: <Widget>[
// Button(
// child: const Text('Toggle theme now'),
// onPressed: () {
// // toggle theme here

// // then close the popup
// Navigator.of(context).pop();
// },
// ),
// Button(
// child: const Text('Got it'),
// onPressed: Navigator.of(context).pop,
// ),
// ],
// ),

// showTeachingTip(
// context: context,
// teachingTip: teachingTip,
// );''',
// ),
],
);
}
}
1 change: 1 addition & 0 deletions lib/fluent_ui.dart
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export 'src/controls/surfaces/info_bar.dart';
export 'src/controls/surfaces/list_tile.dart';
export 'src/controls/surfaces/progress_indicators.dart';
export 'src/controls/surfaces/snackbar.dart';
export 'src/controls/surfaces/teaching_tip.dart';
export 'src/controls/surfaces/tooltip.dart';
export 'src/controls/utils/divider.dart';
export 'src/controls/utils/hover_button.dart';
Expand Down
6 changes: 4 additions & 2 deletions lib/src/controls/flyouts/flyout.dart
Original file line number Diff line number Diff line change
Expand Up @@ -351,10 +351,12 @@ class _FlyoutPositionDelegate extends SingleChildLayoutDelegate {
double clampHorizontal(double x) {
if (!shouldConstrainToRootBounds) return x;

final max = rootSize.width - flyoutSize.width - margin;

return clampDouble(
x,
margin,
rootSize.width - flyoutSize.width - margin,
clampDouble(margin, double.negativeInfinity, max),
max,
);
}

Expand Down
8 changes: 4 additions & 4 deletions lib/src/controls/surfaces/dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,8 @@ class ContentDialog extends StatelessWidget {
}
}

/// Displays a Material dialog above the current contents of the app, with
/// Material entrance and exit animations, modal barrier color, and modal
/// Displays a Fluent dialog above the current contents of the app, with
/// Fluent entrance and exit animations, modal barrier color, and modal
/// barrier behavior (dialog is dismissible with a tap on the barrier).
///
/// This function takes a `builder` which typically builds a [Dialog] widget.
Expand Down Expand Up @@ -262,7 +262,7 @@ Future<T?> showDialog<T extends Object?>({
/// onto the [Navigator] stack to enable state restoration. See
/// [showDialog] for a state restoration app example.
///
/// This function takes a `builder` which typically builds a [Dialog] widget.
/// This function takes a `builder` which typically builds a [ContentDialog] widget.
/// Content below the dialog is dimmed with a [ModalBarrier]. The widget
/// returned by the `builder` does not share a context with the location that
/// `showDialog` is originally called from. Use a [StatefulBuilder] or a
Expand Down Expand Up @@ -294,7 +294,7 @@ Future<T?> showDialog<T extends Object?>({
/// * [showDialog], which is a way to display a DialogRoute.
/// * [showGeneralDialog], which allows for customization of the dialog popup.
class FluentDialogRoute<T> extends RawDialogRoute<T> {
/// A dialog route with Material entrance and exit animations,
/// A dialog route with Fluent entrance and exit animations,
/// modal barrier color
FluentDialogRoute({
required WidgetBuilder builder,
Expand Down
Loading