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',
);
},
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 valueLabel = suffix.isEmpty ? '$value' : '$value $suffix';
final denominator = max - min;
final progress = denominator <= 0 ? 0.0 : ((value - min) / denominator);
return _scrollAware(
controller: _scrollControllerForTab(_selectedTab),
@@ -3369,7 +3383,7 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
focusNode: focusNode,
label: label,
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.',
onMoveLeft: onMoveLeft,
onMoveUp: onMoveUp,
@@ -3394,6 +3408,19 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
);
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,
required VoidCallback onIncrement,
required VoidCallback onDecrement,
ValueChanged<double>? onProgressChanged,
}) {
return _TvAdjustTile(
scale: s,
@@ -3423,6 +3451,7 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
onMoveDown: onMoveDown,
onIncrement: onIncrement,
onDecrement: onDecrement,
onProgressChanged: onProgressChanged,
);
}
@@ -3524,6 +3553,11 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
onMoveDown: onMoveDown,
onIncrement: () => 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 onIncrement;
final VoidCallback onDecrement;
final ValueChanged<double>? onProgressChanged;
const _TvAdjustTile({
required this.scale,
@@ -4198,6 +4233,7 @@ class _TvAdjustTile extends StatefulWidget {
this.onMoveDown,
required this.onIncrement,
required this.onDecrement,
this.onProgressChanged,
});
@override
@@ -4243,6 +4279,12 @@ class _TvAdjustTileState extends State<_TvAdjustTile> {
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
void dispose() {
if (widget.focusNode == null) {
@@ -4385,7 +4427,12 @@ class _TvAdjustTileState extends State<_TvAdjustTile> {
SizedBox(height: 14 * s),
Row(
children: [
Container(
GestureDetector(
onTap: () {
_focusNode.requestFocus();
widget.onDecrement();
},
child: Container(
width: 36 * s,
height: 36 * s,
alignment: Alignment.center,
@@ -4409,8 +4456,36 @@ class _TvAdjustTileState extends State<_TvAdjustTile> {
),
),
),
),
SizedBox(width: 12 * s),
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(
height: 6 * s,
decoration: BoxDecoration(
@@ -4428,9 +4503,17 @@ class _TvAdjustTileState extends State<_TvAdjustTile> {
),
),
),
);
},
),
),
SizedBox(width: 12 * s),
Container(
GestureDetector(
onTap: () {
_focusNode.requestFocus();
widget.onIncrement();
},
child: Container(
width: 36 * s,
height: 36 * s,
alignment: Alignment.center,
@@ -4454,6 +4537,7 @@ class _TvAdjustTileState extends State<_TvAdjustTile> {
),
),
),
),
],
),
SizedBox(height: 10 * s),