improve gesture ui and matching
This commit is contained in:
+34
-20
@@ -32,7 +32,9 @@ Future<GestureAction?> showGestureActionPicker(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
useSafeArea: true,
|
||||
showDragHandle: true,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
|
||||
),
|
||||
builder: (context) => _GestureActionPicker(selected: selected),
|
||||
);
|
||||
}
|
||||
@@ -52,27 +54,39 @@ class _GestureActionPicker extends StatelessWidget {
|
||||
byCategory.putIfAbsent(action.category, () => []).add(action);
|
||||
}
|
||||
|
||||
// Cap the sheet height so the long action list scrolls inside a sheet that
|
||||
// never covers the whole screen.
|
||||
final maxHeight = MediaQuery.sizeOf(context).height * 0.8;
|
||||
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints(maxHeight: maxHeight),
|
||||
child: SafeArea(
|
||||
top: false,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
// A draggable sheet (matching the main browser menu) so the whole surface —
|
||||
// not just a small handle — can be swiped down to dismiss.
|
||||
return DraggableScrollableSheet(
|
||||
initialChildSize: 0.7,
|
||||
minChildSize: 0.4,
|
||||
maxChildSize: 0.95,
|
||||
expand: false,
|
||||
builder: (context, scrollController) {
|
||||
return Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 0, 24, 8),
|
||||
child: Text(
|
||||
'Choose action',
|
||||
style: theme.textTheme.titleLarge,
|
||||
// Drag handle.
|
||||
Container(
|
||||
margin: const EdgeInsets.only(top: 12, bottom: 8),
|
||||
height: 4,
|
||||
width: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: colorScheme.onSurfaceVariant.withValues(alpha: 0.4),
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 0, 24, 8),
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
'Choose action',
|
||||
style: theme.textTheme.titleLarge,
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
controller: scrollController,
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
children: [
|
||||
for (final category in GestureActionCategory.values)
|
||||
@@ -104,8 +118,8 @@ class _GestureActionPicker extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -243,7 +243,10 @@ class _GestureBindingEditor extends HookWidget {
|
||||
).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
)
|
||||
: GestureStrokeView(stroke: stroke),
|
||||
: GestureStrokeView(
|
||||
stroke: stroke,
|
||||
showQualifiers: false,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
|
||||
@@ -18,7 +18,9 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
||||
import 'package:weblibre/features/gestures/data/models/gesture_stroke.dart';
|
||||
import 'package:weblibre/presentation/widgets/inline_count_badge.dart';
|
||||
|
||||
extension GestureArrowIcon on GestureArrow {
|
||||
IconData get icon => switch (this) {
|
||||
@@ -30,17 +32,27 @@ extension GestureArrowIcon on GestureArrow {
|
||||
}
|
||||
|
||||
/// Compact visual rendering of a [GestureStroke]: the direction arrows in
|
||||
/// sequence, prefixed by start-position and finger-count qualifiers when set.
|
||||
/// sequence, prefixed by start-position and finger-count qualifiers.
|
||||
///
|
||||
/// All glyphs share a single foreground [color] so the view blends with
|
||||
/// whatever surface it sits on; it defaults to the primary color, but callers
|
||||
/// rendering on a contrasting surface (e.g. the live overlay) should pass the
|
||||
/// matching `on…` color.
|
||||
///
|
||||
/// Set [showQualifiers] to false to render only the direction arrows, omitting
|
||||
/// the start-position and finger qualifiers (e.g. the live pattern preview in
|
||||
/// the binding editor, where those are configured separately).
|
||||
class GestureStrokeView extends StatelessWidget {
|
||||
final GestureStroke stroke;
|
||||
final Color? color;
|
||||
final bool showQualifiers;
|
||||
|
||||
const GestureStrokeView({required this.stroke, this.color, super.key});
|
||||
const GestureStrokeView({
|
||||
required this.stroke,
|
||||
this.color,
|
||||
this.showQualifiers = true,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -50,7 +62,7 @@ class GestureStrokeView extends StatelessWidget {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (stroke.startPosition != GestureStartPosition.anywhere)
|
||||
if (showQualifiers) ...[
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 6),
|
||||
child: Icon(
|
||||
@@ -59,14 +71,16 @@ class GestureStrokeView extends StatelessWidget {
|
||||
color: foreground,
|
||||
),
|
||||
),
|
||||
if (stroke.fingers >= 2)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 4),
|
||||
child: Text(
|
||||
'${stroke.fingers}×',
|
||||
style: theme.textTheme.labelLarge?.copyWith(color: foreground),
|
||||
padding: const EdgeInsets.only(right: 6),
|
||||
child: InlineCountBadge(
|
||||
count: stroke.fingers,
|
||||
backgroundColor: foreground,
|
||||
foregroundColor: theme.colorScheme.surface,
|
||||
icon: MdiIcons.buttonPointer,
|
||||
),
|
||||
),
|
||||
],
|
||||
for (final arrow in stroke.arrows)
|
||||
Icon(arrow.icon, size: 18, color: foreground),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user