Add focus outlines to btns, add focus nodes to event markers and editorial text content

This commit is contained in:
Shawn 2023-03-01 14:36:30 -07:00
parent b1084d8542
commit 068d7daf9d
4 changed files with 63 additions and 15 deletions

View File

@ -121,19 +121,35 @@ class AppBtn extends StatelessWidget {
tapTargetSize: MaterialTapTargetSize.shrinkWrap, tapTargetSize: MaterialTapTargetSize.shrinkWrap,
splashFactory: NoSplash.splashFactory, splashFactory: NoSplash.splashFactory,
backgroundColor: ButtonStyleButton.allOrNull<Color>(bgColor ?? defaultColor), backgroundColor: ButtonStyleButton.allOrNull<Color>(bgColor ?? defaultColor),
overlayColor: ButtonStyleButton.allOrNull<Color>(Colors.white.withOpacity(.1)), // disable default press effect overlayColor: ButtonStyleButton.allOrNull<Color>(Colors.transparent), // disable default press effect
shape: ButtonStyleButton.allOrNull<OutlinedBorder>(shape), shape: ButtonStyleButton.allOrNull<OutlinedBorder>(shape),
padding: ButtonStyleButton.allOrNull<EdgeInsetsGeometry>(padding ?? EdgeInsets.all($styles.insets.md)), padding: ButtonStyleButton.allOrNull<EdgeInsetsGeometry>(padding ?? EdgeInsets.all($styles.insets.md)),
enableFeedback: enableFeedback, enableFeedback: enableFeedback,
); );
Widget button = TextButton( Widget button = _CustomFocusBuilder(
onPressed: onPressed, builder: (context, focus) => Stack(
style: style, children: [
child: DefaultTextStyle( TextButton(
style: DefaultTextStyle.of(context).style.copyWith(color: textColor), onPressed: onPressed,
child: content, style: style,
focusNode: focus,
child: DefaultTextStyle(
style: DefaultTextStyle.of(context).style.copyWith(color: textColor),
child: content,
),
),
if (focus.hasFocus)
Positioned.fill(
child: IgnorePointer(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular($styles.corners.md),
border: Border.all(color: $styles.colors.accent1, width: 3))),
),
)
],
), ),
); );
@ -181,3 +197,20 @@ class _ButtonPressEffectState extends State<_ButtonPressEffect> {
); );
} }
} }
class _CustomFocusBuilder extends StatefulWidget {
const _CustomFocusBuilder({Key? key, required this.builder}) : super(key: key);
final Widget Function(BuildContext context, FocusNode focus) builder;
@override
State<_CustomFocusBuilder> createState() => _CustomFocusBuilderState();
}
class _CustomFocusBuilderState extends State<_CustomFocusBuilder> {
late final _focusNode = FocusNode()..addListener(() => setState(() {}));
@override
Widget build(BuildContext context) {
return widget.builder.call(context, _focusNode);
}
}

View File

@ -20,7 +20,7 @@ class _ScrollingContent extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Text buildText(String value) => Text(_fixNewlines(value), style: $styles.text.body); Widget buildText(String value) => Focus(child: Text(_fixNewlines(value), style: $styles.text.body));
Widget buildDropCapText(String value) { Widget buildDropCapText(String value) {
final TextStyle dropStyle = $styles.text.dropCase; final TextStyle dropStyle = $styles.text.dropCase;

View File

@ -3,9 +3,11 @@ part of '../timeline_screen.dart';
/// A vertically aligned stack of dots that represent global events /// A vertically aligned stack of dots that represent global events
/// The event closest to the [selectedYr] param will be visible selected /// The event closest to the [selectedYr] param will be visible selected
class _EventMarkers extends StatefulWidget { class _EventMarkers extends StatefulWidget {
const _EventMarkers(this.selectedYr, {Key? key, required this.onEventChanged}) : super(key: key); const _EventMarkers(this.selectedYr, {Key? key, required this.onEventChanged, required this.onMarkerPressed})
: super(key: key);
final void Function(TimelineEvent? event) onEventChanged; final void Function(TimelineEvent? event) onEventChanged;
final void Function(TimelineEvent event) onMarkerPressed;
final int selectedYr; final int selectedYr;
@override @override
@ -62,8 +64,12 @@ class _EventMarkersState extends State<_EventMarkers> {
/// Create a marker for each event /// Create a marker for each event
List<Widget> markers = timelineLogic.events.map((event) { List<Widget> markers = timelineLogic.events.map((event) {
double offsetY = _calculateOffsetY(event.year); double offsetY = _calculateOffsetY(event.year);
return _EventMarker(offsetY, return _EventMarker(
isSelected: event == selectedEvent, semanticLabel: '${event.year}: ${event.description}'); offsetY,
event: event,
isSelected: event == selectedEvent,
onPressed: widget.onMarkerPressed,
);
}).toList(); }).toList();
/// Stack of fractionally positioned markers /// Stack of fractionally positioned markers
@ -110,11 +116,13 @@ class _EventMarker extends StatelessWidget {
this.offset, { this.offset, {
Key? key, Key? key,
required this.isSelected, required this.isSelected,
required this.semanticLabel, required this.event,
required this.onPressed,
}) : super(key: key); }) : super(key: key);
final double offset; final double offset;
final TimelineEvent event;
final bool isSelected; final bool isSelected;
final String semanticLabel; final void Function(TimelineEvent event) onPressed;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -126,8 +134,9 @@ class _EventMarker extends StatelessWidget {
height: 0, height: 0,
child: OverflowBox( child: OverflowBox(
maxHeight: 30, maxHeight: 30,
child: Semantics( child: AppBtn.basic(
label: semanticLabel, semanticLabel: '${event.year}: ${event.description}',
onPressed: () => onPressed(event),
child: Container( child: Container(
alignment: Alignment.center, alignment: Alignment.center,
height: 30, height: 30,

View File

@ -45,6 +45,11 @@ class _ScalingViewportState extends State<_ScrollingViewport> {
AppHaptics.selectionClick(); AppHaptics.selectionClick();
} }
void _handleMarkerPressed(event) {
final pos = controller.calculateScrollPosFromYear(event.year);
controller.scroller.animateTo(pos, duration: $styles.times.med, curve: Curves.easeOutBack);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( return GestureDetector(
@ -132,6 +137,7 @@ class _ScalingViewportState extends State<_ScrollingViewport> {
builder: (_, __) => _EventMarkers( builder: (_, __) => _EventMarkers(
controller.calculateYearFromScrollPos(), controller.calculateYearFromScrollPos(),
onEventChanged: _handleEventMarkerChanged, onEventChanged: _handleEventMarkerChanged,
onMarkerPressed: _handleMarkerPressed,
), ),
), ),
], ],