fix(admin): enable touch interaction on TV slider controls

This commit is contained in:
dwindown
2026-04-02 05:52:05 +07:00
parent c8d33f0ca0
commit 4a4fea6c38

View File

@@ -3238,6 +3238,18 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
'Offset Hijriah ${_hijriOffsetDays >= 0 ? '+' : ''}$_hijriOffsetDays hari tersimpan', 'Offset Hijriah ${_hijriOffsetDays >= 0 ? '+' : ''}$_hijriOffsetDays hari tersimpan',
); );
}, },
onProgressChanged: (nextProgress) {
final mapped = (minOffset + ((maxOffset - minOffset) * nextProgress)).round();
final clamped = mapped.clamp(minOffset, maxOffset).toInt();
if (clamped == _hijriOffsetDays) return;
setState(() {
_hijriOffsetDays = clamped;
});
_queueJadwalAutoSave(
message:
'Offset Hijriah ${_hijriOffsetDays >= 0 ? '+' : ''}$_hijriOffsetDays hari tersimpan',
);
},
); );
} }
@@ -3361,6 +3373,8 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
}) { }) {
final value = _parseCtrlInt(controller, fallback); final value = _parseCtrlInt(controller, fallback);
final valueLabel = suffix.isEmpty ? '$value' : '$value $suffix'; final valueLabel = suffix.isEmpty ? '$value' : '$value $suffix';
final denominator = max - min;
final progress = denominator <= 0 ? 0.0 : ((value - min) / denominator);
return _scrollAware( return _scrollAware(
controller: _scrollControllerForTab(_selectedTab), controller: _scrollControllerForTab(_selectedTab),
@@ -3369,7 +3383,7 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
focusNode: focusNode, focusNode: focusNode,
label: label, label: label,
valueLabel: valueLabel, valueLabel: valueLabel,
progress: ((value - min) / (max - min)).clamp(0.0, 1.0), progress: progress.clamp(0.0, 1.0),
helperText: 'Tekan OK untuk mulai ubah. Saat aktif, gunakan ← → untuk menyesuaikan nilai.', helperText: 'Tekan OK untuk mulai ubah. Saat aktif, gunakan ← → untuk menyesuaikan nilai.',
onMoveLeft: onMoveLeft, onMoveLeft: onMoveLeft,
onMoveUp: onMoveUp, onMoveUp: onMoveUp,
@@ -3394,6 +3408,19 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
); );
onValueChanged?.call(); onValueChanged?.call();
}, },
onProgressChanged: denominator <= 0
? null
: (nextProgress) {
final mapped = (min + ((max - min) * nextProgress))
.round()
.clamp(min, max)
.toInt();
if (mapped == _parseCtrlInt(controller, fallback)) return;
setState(() {
controller.text = mapped.toString();
});
onValueChanged?.call();
},
), ),
); );
} }
@@ -3410,6 +3437,7 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
VoidCallback? onMoveDown, VoidCallback? onMoveDown,
required VoidCallback onIncrement, required VoidCallback onIncrement,
required VoidCallback onDecrement, required VoidCallback onDecrement,
ValueChanged<double>? onProgressChanged,
}) { }) {
return _TvAdjustTile( return _TvAdjustTile(
scale: s, scale: s,
@@ -3423,6 +3451,7 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
onMoveDown: onMoveDown, onMoveDown: onMoveDown,
onIncrement: onIncrement, onIncrement: onIncrement,
onDecrement: onDecrement, onDecrement: onDecrement,
onProgressChanged: onProgressChanged,
); );
} }
@@ -3524,6 +3553,11 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
onMoveDown: onMoveDown, onMoveDown: onMoveDown,
onIncrement: () => onChanged((value + step).clamp(0.5, 2.0)), onIncrement: () => onChanged((value + step).clamp(0.5, 2.0)),
onDecrement: () => onChanged((value - step).clamp(0.5, 2.0)), onDecrement: () => onChanged((value - step).clamp(0.5, 2.0)),
onProgressChanged: (nextProgress) {
final mapped = (0.5 + (1.5 * nextProgress)).clamp(0.5, 2.0);
final snapped = (((mapped / step).round() * step).clamp(0.5, 2.0)).toDouble();
onChanged(snapped);
},
); );
} }
@@ -4185,6 +4219,7 @@ class _TvAdjustTile extends StatefulWidget {
final VoidCallback? onMoveDown; final VoidCallback? onMoveDown;
final VoidCallback onIncrement; final VoidCallback onIncrement;
final VoidCallback onDecrement; final VoidCallback onDecrement;
final ValueChanged<double>? onProgressChanged;
const _TvAdjustTile({ const _TvAdjustTile({
required this.scale, required this.scale,
@@ -4198,6 +4233,7 @@ class _TvAdjustTile extends StatefulWidget {
this.onMoveDown, this.onMoveDown,
required this.onIncrement, required this.onIncrement,
required this.onDecrement, required this.onDecrement,
this.onProgressChanged,
}); });
@override @override
@@ -4243,6 +4279,12 @@ class _TvAdjustTileState extends State<_TvAdjustTile> {
FocusNode get _focusNode => widget.focusNode ?? _fallbackFocusNode; FocusNode get _focusNode => widget.focusNode ?? _fallbackFocusNode;
void _updateFromTouchPosition(double x, double width) {
if (widget.onProgressChanged == null || width <= 0) return;
final normalized = (x / width).clamp(0.0, 1.0);
widget.onProgressChanged!(normalized);
}
@override @override
void dispose() { void dispose() {
if (widget.focusNode == null) { if (widget.focusNode == null) {
@@ -4385,7 +4427,12 @@ class _TvAdjustTileState extends State<_TvAdjustTile> {
SizedBox(height: 14 * s), SizedBox(height: 14 * s),
Row( Row(
children: [ children: [
Container( GestureDetector(
onTap: () {
_focusNode.requestFocus();
widget.onDecrement();
},
child: Container(
width: 36 * s, width: 36 * s,
height: 36 * s, height: 36 * s,
alignment: Alignment.center, alignment: Alignment.center,
@@ -4409,8 +4456,36 @@ class _TvAdjustTileState extends State<_TvAdjustTile> {
), ),
), ),
), ),
),
SizedBox(width: 12 * s), SizedBox(width: 12 * s),
Expanded( Expanded(
child: LayoutBuilder(
builder: (context, constraints) {
final barWidth = constraints.maxWidth;
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTapDown: (details) {
_focusNode.requestFocus();
_updateFromTouchPosition(details.localPosition.dx, barWidth);
},
onHorizontalDragStart: widget.onProgressChanged == null
? null
: (_) {
_focusNode.requestFocus();
setState(() => _isEditing = true);
},
onHorizontalDragUpdate: widget.onProgressChanged == null
? null
: (details) => _updateFromTouchPosition(
details.localPosition.dx,
barWidth,
),
onHorizontalDragEnd: widget.onProgressChanged == null
? null
: (_) => setState(() => _isEditing = false),
onHorizontalDragCancel: widget.onProgressChanged == null
? null
: () => setState(() => _isEditing = false),
child: Container( child: Container(
height: 6 * s, height: 6 * s,
decoration: BoxDecoration( decoration: BoxDecoration(
@@ -4428,9 +4503,17 @@ class _TvAdjustTileState extends State<_TvAdjustTile> {
), ),
), ),
), ),
);
},
),
), ),
SizedBox(width: 12 * s), SizedBox(width: 12 * s),
Container( GestureDetector(
onTap: () {
_focusNode.requestFocus();
widget.onIncrement();
},
child: Container(
width: 36 * s, width: 36 * s,
height: 36 * s, height: 36 * s,
alignment: Alignment.center, alignment: Alignment.center,
@@ -4454,6 +4537,7 @@ class _TvAdjustTileState extends State<_TvAdjustTile> {
), ),
), ),
), ),
),
], ],
), ),
SizedBox(height: 10 * s), SizedBox(height: 10 * s),