fix(admin): enable touch interaction on TV slider controls
This commit is contained in:
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user