Cleaned up preview app

Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
2026-09-02 00:30:05 +02:00
parent 91c70fc4af
commit 2caad7ad5a
+63 -74
View File
@@ -1,9 +1,9 @@
import "dart:async"; import "dart:async";
import "dart:io"; import "dart:io";
import "dart:typed_data";
import "package:custom_cursor/custom_cursor.dart"; import "package:custom_cursor/custom_cursor.dart";
import "package:desktop_drop/desktop_drop.dart"; import "package:desktop_drop/desktop_drop.dart";
import "package:flutter/foundation.dart";
import "package:flutter/material.dart"; import "package:flutter/material.dart";
import "package:flutter/services.dart" show rootBundle; import "package:flutter/services.dart" show rootBundle;
@@ -41,7 +41,6 @@ class CursorGridScreen extends StatefulWidget {
class _CursorGridScreenState extends State<CursorGridScreen> { class _CursorGridScreenState extends State<CursorGridScreen> {
static const _defaultAssets = <String>["normal", "move", "resize"]; static const _defaultAssets = <String>["normal", "move", "resize"];
static const _sizePresets = <int>[24, 30, 32, 36, 48, 64, 128];
Map<String, CursorAsset> _cursors = {}; Map<String, CursorAsset> _cursors = {};
final Map<String, Uint8List> _rawFiles = {}; final Map<String, Uint8List> _rawFiles = {};
@@ -53,7 +52,6 @@ class _CursorGridScreenState extends State<CursorGridScreen> {
bool _respectOsScale = true; bool _respectOsScale = true;
bool _rtl = false; bool _rtl = false;
double _systemScale = 1.0; double _systemScale = 1.0;
String _customSize = "";
DecodeOptions get _options { DecodeOptions get _options {
return DecodeOptions( return DecodeOptions(
@@ -174,21 +172,13 @@ class _CursorGridScreenState extends State<CursorGridScreen> {
setState(() { setState(() {
_cursors = {}; _cursors = {};
_loading = true; _loading = true;
_targetSize = 32;
}); });
await _loadDefaults(); await _loadDefaults();
} }
void _setPreset(int? size) { void _setPreset(int? size) {
_targetSize = size?.toDouble(); _targetSize = size?.toDouble();
if (size != null) _customSize = "";
unawaited(_redecode());
}
void _applyCustomSize(String text) {
final parsed = double.tryParse(text);
if (parsed != null && parsed > 0) {
_targetSize = parsed;
}
unawaited(_redecode()); unawaited(_redecode());
} }
@@ -219,13 +209,11 @@ class _CursorGridScreenState extends State<CursorGridScreen> {
children: [ children: [
_ScaleControls( _ScaleControls(
preset: _targetSize, preset: _targetSize,
customSize: _customSize,
respectOsScale: _respectOsScale, respectOsScale: _respectOsScale,
osScale: _systemScale, osScale: _systemScale,
rtl: _rtl, rtl: _rtl,
onPreset: (size) => setState(() => _setPreset(size)), onPreset: (size) => setState(() => _setPreset(size)),
onCustomChanged: (text) => setState(() => _customSize = text),
onCustomSubmitted: _applyCustomSize,
onToggleOsScale: (value) => onToggleOsScale: (value) =>
setState(() => _toggleOsScale(value)), setState(() => _toggleOsScale(value)),
onToggleRtl: (value) => setState(() => _rtl = value), onToggleRtl: (value) => setState(() => _rtl = value),
@@ -262,25 +250,19 @@ class _CursorGridScreenState extends State<CursorGridScreen> {
class _ScaleControls extends StatelessWidget { class _ScaleControls extends StatelessWidget {
const _ScaleControls({ const _ScaleControls({
required this.preset, required this.preset,
required this.customSize,
required this.respectOsScale, required this.respectOsScale,
required this.osScale, required this.osScale,
required this.rtl, required this.rtl,
required this.onPreset, required this.onPreset,
required this.onCustomChanged,
required this.onCustomSubmitted,
required this.onToggleOsScale, required this.onToggleOsScale,
required this.onToggleRtl, required this.onToggleRtl,
}); });
final double? preset; final double? preset;
final String customSize;
final bool respectOsScale; final bool respectOsScale;
final double osScale; final double osScale;
final bool rtl; final bool rtl;
final ValueChanged<int?> onPreset; final ValueChanged<int?> onPreset;
final ValueChanged<String> onCustomChanged;
final ValueChanged<String> onCustomSubmitted;
final ValueChanged<bool> onToggleOsScale; final ValueChanged<bool> onToggleOsScale;
final ValueChanged<bool> onToggleRtl; final ValueChanged<bool> onToggleRtl;
@@ -294,52 +276,51 @@ class _ScaleControls extends StatelessWidget {
crossAxisAlignment: WrapCrossAlignment.center, crossAxisAlignment: WrapCrossAlignment.center,
children: [ children: [
Text("Size:", style: Theme.of(context).textTheme.titleSmall), Text("Size:", style: Theme.of(context).textTheme.titleSmall),
for (final size in _CursorGridScreenState._sizePresets) Slider.adaptive(
ChoiceChip( min: 16,
label: Text("$size"), max: 128,
selected: preset == size, value: preset ?? 32,
onSelected: (_) => onPreset(size), divisions: 8,
), showValueIndicator: ShowValueIndicator.alwaysVisible,
SizedBox( onChanged: (value) {
width: 72, onPreset(value.toInt());
child: TextField( },
decoration: const InputDecoration( ),
labelText: "Custom", Row(
isDense: true, spacing: 8,
children: [
Directionality(
textDirection: TextDirection.ltr,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text("Dir:", style: Theme.of(context).textTheme.titleSmall),
const SizedBox(width: 8),
ChoiceChip(
label: const Text("LTR"),
selected: !rtl,
onSelected: (_) => onToggleRtl(false),
),
const SizedBox(width: 4),
ChoiceChip(
label: const Text("RTL"),
selected: rtl,
onSelected: (_) => onToggleRtl(true),
),
],
),
), ),
keyboardType: TextInputType.number, Expanded(
onChanged: onCustomChanged, child: SwitchListTile.adaptive(
onSubmitted: onCustomSubmitted, contentPadding: EdgeInsets.zero,
), title: Text(
), "Respect OS pointer size (${osScale.toStringAsFixed(2)}x)",
Directionality( ),
textDirection: TextDirection.ltr, value: respectOsScale,
child: Row( onChanged: onToggleOsScale,
mainAxisSize: MainAxisSize.min,
children: [
Text("Dir:", style: Theme.of(context).textTheme.titleSmall),
const SizedBox(width: 8),
ChoiceChip(
label: const Text("LTR"),
selected: !rtl,
onSelected: (_) => onToggleRtl(false),
), ),
const SizedBox(width: 4), ),
ChoiceChip( ],
label: const Text("RTL"),
selected: rtl,
onSelected: (_) => onToggleRtl(true),
),
],
),
),
SwitchListTile(
contentPadding: EdgeInsets.zero,
title: Text(
"Respect OS pointer size (${osScale.toStringAsFixed(2)}x)",
),
value: respectOsScale,
onChanged: onToggleOsScale,
), ),
], ],
), ),
@@ -361,12 +342,16 @@ class _DropRegion extends StatelessWidget {
final ValueChanged<DropEventDetails> onDragExited; final ValueChanged<DropEventDetails> onDragExited;
final ValueChanged<DropDoneDetails> onDragDone; final ValueChanged<DropDoneDetails> onDragDone;
bool get useDropTarget =>
kIsWeb || Platform.isWindows || Platform.isLinux || Platform.isMacOS;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
return Padding( return Padding(
padding: const EdgeInsets.fromLTRB(24, 24, 24, 0), padding: const EdgeInsets.fromLTRB(24, 24, 24, 0),
child: DropTarget( child: DropTarget(
enable: useDropTarget,
onDragEntered: onDragEntered, onDragEntered: onDragEntered,
onDragExited: onDragExited, onDragExited: onDragExited,
onDragDone: onDragDone, onDragDone: onDragDone,
@@ -387,9 +372,11 @@ class _DropRegion extends StatelessWidget {
), ),
), ),
child: Text( child: Text(
dragging useDropTarget
? "Release to load cursors" ? dragging
: "Drop cursor/image files here (cur, ani, PNG, GIF, SVG...)", ? "Release to load cursors"
: "Drop cursor/image files here (cur, ani, PNG, GIF, SVG...)"
: "Tap to load cursor/image files (cur, ani, PNG, GIF, SVG...)",
style: theme.textTheme.titleMedium, style: theme.textTheme.titleMedium,
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
@@ -467,10 +454,10 @@ class _CursorCardState extends State<CursorCard> {
), ),
), ),
child: Column( child: Column(
spacing: 12,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
AssetPreview(asset: widget.asset), Flexible(child: AssetPreview(asset: widget.asset)),
const SizedBox(height: 12),
Text(widget.name, style: theme.textTheme.titleMedium), Text(widget.name, style: theme.textTheme.titleMedium),
], ],
), ),
@@ -558,12 +545,14 @@ class _CursorPreview extends StatelessWidget {
final rtl = effectiveDirection(context) == TextDirection.rtl; final rtl = effectiveDirection(context) == TextDirection.rtl;
final width = cursor.image.width.toDouble(); final width = cursor.image.width.toDouble();
final height = cursor.image.height.toDouble(); final height = cursor.image.height.toDouble();
return SizedBox( return Center(
width: width,
height: height,
child: Transform.scale( child: Transform.scale(
scaleX: rtl ? -1 : 1, scaleX: rtl ? -1 : 1,
child: RawImage(image: cursor.image, width: width, height: height), child: RawImage(
image: cursor.image,
width: width,
height: height,
),
), ),
); );
} }