fix(tv-focus): stabilize tampilan navigation and reveal + bump 1.0.8+9
This commit is contained in:
@@ -527,6 +527,14 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
|
||||
}
|
||||
|
||||
Future<void> _showCitySearchDialog(double s) async {
|
||||
bool isActivateKey(LogicalKeyboardKey key) {
|
||||
return key == LogicalKeyboardKey.enter ||
|
||||
key == LogicalKeyboardKey.select ||
|
||||
key == LogicalKeyboardKey.numpadEnter ||
|
||||
key == LogicalKeyboardKey.space ||
|
||||
key == LogicalKeyboardKey.gameButtonA;
|
||||
}
|
||||
|
||||
final queryCtrl = TextEditingController();
|
||||
final queryFocusNode = FocusNode(debugLabel: 'city_query');
|
||||
final searchFocusNode = FocusNode(debugLabel: 'city_search');
|
||||
@@ -639,6 +647,9 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
|
||||
label: 'Kata Kunci Kota / Kabupaten',
|
||||
controller: queryCtrl,
|
||||
focusNode: queryFocusNode,
|
||||
onMoveDown: () {
|
||||
searchFocusNode.requestFocus();
|
||||
},
|
||||
onEditComplete: () {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (ctx.mounted) {
|
||||
@@ -667,8 +678,7 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
|
||||
}
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
if (key == LogicalKeyboardKey.enter ||
|
||||
key == LogicalKeyboardKey.select) {
|
||||
if (isActivateKey(key)) {
|
||||
runSearch();
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
@@ -804,10 +814,7 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
|
||||
return KeyEventResult.ignored;
|
||||
}
|
||||
final key = event.logicalKey;
|
||||
if (key ==
|
||||
LogicalKeyboardKey.enter ||
|
||||
key ==
|
||||
LogicalKeyboardKey.select) {
|
||||
if (isActivateKey(key)) {
|
||||
selectCity(city);
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
@@ -1185,41 +1192,37 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
|
||||
void _focusIdentityRow(int index) {
|
||||
if (_selectedTab != 0) return;
|
||||
if (index < 0 || index >= _identityFocusNodes.length) return;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted) {
|
||||
_identityFocusNodes[index].requestFocus();
|
||||
}
|
||||
});
|
||||
_requestFocusAndReveal(
|
||||
_identityFocusNodes[index],
|
||||
_identityScrollController,
|
||||
);
|
||||
}
|
||||
|
||||
void _focusJumatRow(int index) {
|
||||
if (_selectedTab != 4) return;
|
||||
if (index < 0 || index >= _jumatFocusNodes.length) return;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted) {
|
||||
_jumatFocusNodes[index].requestFocus();
|
||||
}
|
||||
});
|
||||
_requestFocusAndReveal(
|
||||
_jumatFocusNodes[index],
|
||||
_jumatScrollController,
|
||||
);
|
||||
}
|
||||
|
||||
void _focusSimulasiRow(int index) {
|
||||
if (_selectedTab != 5) return;
|
||||
if (index < 0 || index >= _simulasiFocusNodes.length) return;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted) {
|
||||
_simulasiFocusNodes[index].requestFocus();
|
||||
}
|
||||
});
|
||||
_requestFocusAndReveal(
|
||||
_simulasiFocusNodes[index],
|
||||
_simulasiScrollController,
|
||||
);
|
||||
}
|
||||
|
||||
void _focusTentangRow(int index) {
|
||||
if (_selectedTab != 6) return;
|
||||
if (index < 0 || index >= _tentangRowCount()) return;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted) {
|
||||
_tentangFocusNodes[index].requestFocus();
|
||||
}
|
||||
});
|
||||
_requestFocusAndReveal(
|
||||
_tentangFocusNodes[index],
|
||||
_tentangScrollController,
|
||||
);
|
||||
}
|
||||
|
||||
int _tentangRowCount() {
|
||||
@@ -1229,11 +1232,10 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
|
||||
void _focusJadwalRow(int index) {
|
||||
if (_selectedTab != 1) return;
|
||||
if (index < 0 || index >= _jadwalFocusNodes.length) return;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted) {
|
||||
_jadwalFocusNodes[index].requestFocus();
|
||||
}
|
||||
});
|
||||
_requestFocusAndReveal(
|
||||
_jadwalFocusNodes[index],
|
||||
_jadwalScrollController,
|
||||
);
|
||||
}
|
||||
|
||||
FocusNode _tampilanFocusNode(int index) {
|
||||
@@ -1276,11 +1278,10 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
|
||||
if (_selectedTab != 2) return;
|
||||
final max = _tampilanRowCount();
|
||||
if (index < 0 || index >= max) return;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted) {
|
||||
_tampilanFocusNode(index).requestFocus();
|
||||
}
|
||||
});
|
||||
_requestFocusAndReveal(
|
||||
_tampilanFocusNode(index),
|
||||
_tampilanScrollController,
|
||||
);
|
||||
}
|
||||
|
||||
int _pengumumanRowCount() {
|
||||
@@ -1298,10 +1299,30 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
|
||||
if (_selectedTab != 3) return;
|
||||
final max = _pengumumanRowCount();
|
||||
if (index < 0 || index >= max) return;
|
||||
_requestFocusAndReveal(
|
||||
_pengumumanFocusNode(index),
|
||||
_pengumumanScrollController,
|
||||
);
|
||||
}
|
||||
|
||||
void _requestFocusAndReveal(
|
||||
FocusNode node,
|
||||
ScrollController controller,
|
||||
) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted) {
|
||||
_pengumumanFocusNode(index).requestFocus();
|
||||
}
|
||||
if (!mounted) return;
|
||||
node.requestFocus();
|
||||
WidgetsBinding.instance.addPostFrameCallback((__) {
|
||||
if (!mounted || !controller.hasClients) return;
|
||||
final focusContext = node.context;
|
||||
if (focusContext == null || !focusContext.mounted) return;
|
||||
Scrollable.ensureVisible(
|
||||
focusContext,
|
||||
duration: const Duration(milliseconds: 220),
|
||||
curve: Curves.easeOutCubic,
|
||||
alignment: 0.18,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1977,8 +1998,14 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
|
||||
label: 'Gunakan Foto Unsplash API',
|
||||
value: _useUnsplash,
|
||||
onChanged: (val) {
|
||||
final previous = _useUnsplash;
|
||||
setState(() => _useUnsplash = val);
|
||||
_queueTampilanAutoSave();
|
||||
if (!previous && val) {
|
||||
_focusTampilanRow(useUnsplashRow + 1);
|
||||
} else if (previous && !val) {
|
||||
_focusTampilanRow(useUnsplashRow);
|
||||
}
|
||||
},
|
||||
trueLabel: 'Aktif',
|
||||
falseLabel: 'Nonaktif',
|
||||
@@ -2363,36 +2390,39 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12 * s),
|
||||
_TvEditableTextTile(
|
||||
scale: s,
|
||||
label: 'Isi Text Slide',
|
||||
focusNode: _pengumumanFocusNode(
|
||||
textSlideTextRows[idx],
|
||||
_scrollAware(
|
||||
controller: _pengumumanScrollController,
|
||||
child: _TvEditableTextTile(
|
||||
scale: s,
|
||||
label: 'Isi Text Slide',
|
||||
focusNode: _pengumumanFocusNode(
|
||||
textSlideTextRows[idx],
|
||||
),
|
||||
controller: textCtrl,
|
||||
maxLines: 3,
|
||||
onMoveLeft: () => _focusNavTab(_selectedTab),
|
||||
onMoveUp: () => _focusPengumumanRow(
|
||||
idx == 0
|
||||
? announcementDurationRow
|
||||
: textSlideDeleteRows[idx - 1],
|
||||
),
|
||||
onMoveDown: () => _focusPengumumanRow(
|
||||
textSlideDeleteRows[idx],
|
||||
),
|
||||
onChanged: (val) {
|
||||
_textSlides[idx] = val;
|
||||
_queuePengumumanAutoSave(
|
||||
message:
|
||||
'Text slide tengah otomatis tersimpan',
|
||||
);
|
||||
},
|
||||
onEditComplete: () {
|
||||
_queuePengumumanAutoSave(
|
||||
message:
|
||||
'Text slide tengah otomatis tersimpan',
|
||||
);
|
||||
},
|
||||
),
|
||||
controller: textCtrl,
|
||||
maxLines: 3,
|
||||
onMoveLeft: () => _focusNavTab(_selectedTab),
|
||||
onMoveUp: () => _focusPengumumanRow(
|
||||
idx == 0
|
||||
? announcementDurationRow
|
||||
: textSlideDeleteRows[idx - 1],
|
||||
),
|
||||
onMoveDown: () => _focusPengumumanRow(
|
||||
textSlideDeleteRows[idx],
|
||||
),
|
||||
onChanged: (val) {
|
||||
_textSlides[idx] = val;
|
||||
_queuePengumumanAutoSave(
|
||||
message:
|
||||
'Text slide tengah otomatis tersimpan',
|
||||
);
|
||||
},
|
||||
onEditComplete: () {
|
||||
_queuePengumumanAutoSave(
|
||||
message:
|
||||
'Text slide tengah otomatis tersimpan',
|
||||
);
|
||||
},
|
||||
),
|
||||
SizedBox(height: 10 * s),
|
||||
_buildPengumumanActionButton(
|
||||
@@ -2579,57 +2609,26 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12 * s),
|
||||
_TvEditableTextTile(
|
||||
scale: s,
|
||||
label: 'Teks Berjalan',
|
||||
focusNode: _pengumumanFocusNode(
|
||||
runningTextTextRows[idx],
|
||||
),
|
||||
controller: textCtrl,
|
||||
onMoveLeft: () => _focusNavTab(_selectedTab),
|
||||
onMoveUp: () => _focusPengumumanRow(
|
||||
idx == 0
|
||||
? marqueeModeRow
|
||||
: runningTextDeleteRows[idx - 1],
|
||||
),
|
||||
onMoveDown: () => _focusPengumumanRow(
|
||||
runningTextDurationRows[idx],
|
||||
),
|
||||
onChanged: (val) {
|
||||
_runningTexts[idx] = val;
|
||||
_queuePengumumanAutoSave(
|
||||
message:
|
||||
'Teks berjalan otomatis tersimpan',
|
||||
);
|
||||
},
|
||||
onEditComplete: () {
|
||||
_queuePengumumanAutoSave(
|
||||
message:
|
||||
'Teks berjalan otomatis tersimpan',
|
||||
);
|
||||
},
|
||||
),
|
||||
SizedBox(height: 12 * s),
|
||||
SizedBox(
|
||||
width: 180 * s,
|
||||
_scrollAware(
|
||||
controller: _pengumumanScrollController,
|
||||
child: _TvEditableTextTile(
|
||||
scale: s,
|
||||
label: 'Durasi (detik)',
|
||||
label: 'Teks Berjalan',
|
||||
focusNode: _pengumumanFocusNode(
|
||||
runningTextDurationRows[idx],
|
||||
),
|
||||
controller: durCtrl,
|
||||
keyboardType: TextInputType.number,
|
||||
onMoveLeft: () => _focusNavTab(_selectedTab),
|
||||
onMoveUp: () => _focusPengumumanRow(
|
||||
runningTextTextRows[idx],
|
||||
),
|
||||
controller: textCtrl,
|
||||
onMoveLeft: () => _focusNavTab(_selectedTab),
|
||||
onMoveUp: () => _focusPengumumanRow(
|
||||
idx == 0
|
||||
? marqueeModeRow
|
||||
: runningTextDeleteRows[idx - 1],
|
||||
),
|
||||
onMoveDown: () => _focusPengumumanRow(
|
||||
runningTextDeleteRows[idx],
|
||||
runningTextDurationRows[idx],
|
||||
),
|
||||
onChanged: (val) {
|
||||
_runningTextDurations[idx] =
|
||||
int.tryParse(val) ?? 12;
|
||||
_runningTexts[idx] = val;
|
||||
_queuePengumumanAutoSave(
|
||||
message:
|
||||
'Teks berjalan otomatis tersimpan',
|
||||
@@ -2643,6 +2642,43 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
|
||||
},
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12 * s),
|
||||
SizedBox(
|
||||
width: 180 * s,
|
||||
child: _scrollAware(
|
||||
controller: _pengumumanScrollController,
|
||||
child: _TvEditableTextTile(
|
||||
scale: s,
|
||||
label: 'Durasi (detik)',
|
||||
focusNode: _pengumumanFocusNode(
|
||||
runningTextDurationRows[idx],
|
||||
),
|
||||
controller: durCtrl,
|
||||
keyboardType: TextInputType.number,
|
||||
onMoveLeft: () => _focusNavTab(_selectedTab),
|
||||
onMoveUp: () => _focusPengumumanRow(
|
||||
runningTextTextRows[idx],
|
||||
),
|
||||
onMoveDown: () => _focusPengumumanRow(
|
||||
runningTextDeleteRows[idx],
|
||||
),
|
||||
onChanged: (val) {
|
||||
_runningTextDurations[idx] =
|
||||
int.tryParse(val) ?? 12;
|
||||
_queuePengumumanAutoSave(
|
||||
message:
|
||||
'Teks berjalan otomatis tersimpan',
|
||||
);
|
||||
},
|
||||
onEditComplete: () {
|
||||
_queuePengumumanAutoSave(
|
||||
message:
|
||||
'Teks berjalan otomatis tersimpan',
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10 * s),
|
||||
_buildPengumumanActionButton(
|
||||
rowIndex: runningTextDeleteRows[idx],
|
||||
@@ -2881,16 +2917,25 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
|
||||
}
|
||||
final key = event.logicalKey;
|
||||
if (key == LogicalKeyboardKey.arrowLeft) {
|
||||
onMoveLeft?.call();
|
||||
return KeyEventResult.handled;
|
||||
if (onMoveLeft != null) {
|
||||
onMoveLeft();
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
return KeyEventResult.ignored;
|
||||
}
|
||||
if (key == LogicalKeyboardKey.arrowUp) {
|
||||
onMoveUp?.call();
|
||||
return KeyEventResult.handled;
|
||||
if (onMoveUp != null) {
|
||||
onMoveUp();
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
return KeyEventResult.ignored;
|
||||
}
|
||||
if (key == LogicalKeyboardKey.arrowDown) {
|
||||
onMoveDown?.call();
|
||||
return KeyEventResult.handled;
|
||||
if (onMoveDown != null) {
|
||||
onMoveDown();
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
return KeyEventResult.ignored;
|
||||
}
|
||||
if (key == LogicalKeyboardKey.arrowRight) {
|
||||
return KeyEventResult.handled;
|
||||
@@ -4046,52 +4091,50 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
|
||||
final denominator = max - min;
|
||||
final progress = denominator <= 0 ? 0.0 : ((value - min) / denominator);
|
||||
|
||||
return _scrollAware(
|
||||
controller: _scrollControllerForTab(_selectedTab),
|
||||
child: _buildTvAdjustTile(
|
||||
s: s,
|
||||
focusNode: focusNode,
|
||||
label: label,
|
||||
valueLabel: valueLabel,
|
||||
progress: progress.clamp(0.0, 1.0),
|
||||
helperText: 'Tekan OK untuk mulai ubah. Saat aktif, gunakan ← → untuk menyesuaikan nilai.',
|
||||
onMoveLeft: onMoveLeft,
|
||||
onMoveUp: onMoveUp,
|
||||
onMoveDown: onMoveDown,
|
||||
onIncrement: () {
|
||||
_bumpCtrlInt(
|
||||
controller,
|
||||
delta: 1,
|
||||
min: min,
|
||||
max: max,
|
||||
fallback: fallback,
|
||||
);
|
||||
onValueChanged?.call();
|
||||
},
|
||||
onDecrement: () {
|
||||
_bumpCtrlInt(
|
||||
controller,
|
||||
delta: -1,
|
||||
min: min,
|
||||
max: max,
|
||||
fallback: fallback,
|
||||
);
|
||||
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();
|
||||
},
|
||||
),
|
||||
return _buildTvAdjustTile(
|
||||
s: s,
|
||||
focusNode: focusNode,
|
||||
label: label,
|
||||
valueLabel: valueLabel,
|
||||
progress: progress.clamp(0.0, 1.0),
|
||||
helperText:
|
||||
'Tekan OK untuk mulai ubah. Saat aktif, gunakan ← → untuk menyesuaikan nilai.',
|
||||
onMoveLeft: onMoveLeft,
|
||||
onMoveUp: onMoveUp,
|
||||
onMoveDown: onMoveDown,
|
||||
onIncrement: () {
|
||||
_bumpCtrlInt(
|
||||
controller,
|
||||
delta: 1,
|
||||
min: min,
|
||||
max: max,
|
||||
fallback: fallback,
|
||||
);
|
||||
onValueChanged?.call();
|
||||
},
|
||||
onDecrement: () {
|
||||
_bumpCtrlInt(
|
||||
controller,
|
||||
delta: -1,
|
||||
min: min,
|
||||
max: max,
|
||||
fallback: fallback,
|
||||
);
|
||||
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();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4109,19 +4152,22 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
|
||||
required VoidCallback onDecrement,
|
||||
ValueChanged<double>? onProgressChanged,
|
||||
}) {
|
||||
return _TvAdjustTile(
|
||||
scale: s,
|
||||
focusNode: focusNode,
|
||||
label: label,
|
||||
valueLabel: valueLabel,
|
||||
progress: progress,
|
||||
helperText: helperText,
|
||||
onMoveLeft: onMoveLeft,
|
||||
onMoveUp: onMoveUp,
|
||||
onMoveDown: onMoveDown,
|
||||
onIncrement: onIncrement,
|
||||
onDecrement: onDecrement,
|
||||
onProgressChanged: onProgressChanged,
|
||||
return _scrollAware(
|
||||
controller: _scrollControllerForTab(_selectedTab),
|
||||
child: _TvAdjustTile(
|
||||
scale: s,
|
||||
focusNode: focusNode,
|
||||
label: label,
|
||||
valueLabel: valueLabel,
|
||||
progress: progress,
|
||||
helperText: helperText,
|
||||
onMoveLeft: onMoveLeft,
|
||||
onMoveUp: onMoveUp,
|
||||
onMoveDown: onMoveDown,
|
||||
onIncrement: onIncrement,
|
||||
onDecrement: onDecrement,
|
||||
onProgressChanged: onProgressChanged,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4972,29 +5018,60 @@ class _TvAdjustTileState extends State<_TvAdjustTile> {
|
||||
}
|
||||
|
||||
final key = event.logicalKey;
|
||||
if (key == LogicalKeyboardKey.select || key == LogicalKeyboardKey.enter) {
|
||||
final isActivateKey = key == LogicalKeyboardKey.select ||
|
||||
key == LogicalKeyboardKey.enter ||
|
||||
key == LogicalKeyboardKey.numpadEnter ||
|
||||
key == LogicalKeyboardKey.space ||
|
||||
key == LogicalKeyboardKey.gameButtonA;
|
||||
|
||||
if (isActivateKey) {
|
||||
setState(() => _isEditing = !_isEditing);
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
|
||||
if (!_isEditing && key == LogicalKeyboardKey.arrowUp) {
|
||||
widget.onMoveUp?.call();
|
||||
return KeyEventResult.handled;
|
||||
if (widget.onMoveUp != null) {
|
||||
widget.onMoveUp!.call();
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
return KeyEventResult.ignored;
|
||||
}
|
||||
if (!_isEditing && key == LogicalKeyboardKey.arrowDown) {
|
||||
widget.onMoveDown?.call();
|
||||
return KeyEventResult.handled;
|
||||
if (widget.onMoveDown != null) {
|
||||
widget.onMoveDown!.call();
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
return KeyEventResult.ignored;
|
||||
}
|
||||
if (!_isEditing && key == LogicalKeyboardKey.arrowLeft) {
|
||||
widget.onMoveLeft?.call();
|
||||
return KeyEventResult.handled;
|
||||
if (widget.onMoveLeft != null) {
|
||||
widget.onMoveLeft!.call();
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
return KeyEventResult.ignored;
|
||||
}
|
||||
if (!_isEditing && key == LogicalKeyboardKey.arrowRight) {
|
||||
return KeyEventResult.handled;
|
||||
return KeyEventResult.ignored;
|
||||
}
|
||||
|
||||
if (!_isEditing) return KeyEventResult.ignored;
|
||||
|
||||
if (key == LogicalKeyboardKey.arrowUp) {
|
||||
setState(() => _isEditing = false);
|
||||
if (widget.onMoveUp != null) {
|
||||
widget.onMoveUp!.call();
|
||||
}
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
|
||||
if (key == LogicalKeyboardKey.arrowDown) {
|
||||
setState(() => _isEditing = false);
|
||||
if (widget.onMoveDown != null) {
|
||||
widget.onMoveDown!.call();
|
||||
}
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
|
||||
if (key == LogicalKeyboardKey.arrowLeft) {
|
||||
widget.onDecrement();
|
||||
return KeyEventResult.handled;
|
||||
@@ -5300,26 +5377,39 @@ class _TvEditableTextTileState extends State<_TvEditableTextTile> {
|
||||
}
|
||||
|
||||
final key = event.logicalKey;
|
||||
final isActivateKey = key == LogicalKeyboardKey.enter ||
|
||||
key == LogicalKeyboardKey.select ||
|
||||
key == LogicalKeyboardKey.numpadEnter ||
|
||||
key == LogicalKeyboardKey.space ||
|
||||
key == LogicalKeyboardKey.gameButtonA;
|
||||
if (!_isEditing &&
|
||||
(key == LogicalKeyboardKey.enter ||
|
||||
key == LogicalKeyboardKey.select)) {
|
||||
isActivateKey) {
|
||||
_startEditing();
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
|
||||
if (!_isEditing && key == LogicalKeyboardKey.arrowLeft) {
|
||||
widget.onMoveLeft?.call();
|
||||
return KeyEventResult.handled;
|
||||
if (widget.onMoveLeft != null) {
|
||||
widget.onMoveLeft!.call();
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
return KeyEventResult.ignored;
|
||||
}
|
||||
|
||||
if (!_isEditing && key == LogicalKeyboardKey.arrowUp) {
|
||||
widget.onMoveUp?.call();
|
||||
return KeyEventResult.handled;
|
||||
if (widget.onMoveUp != null) {
|
||||
widget.onMoveUp!.call();
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
return KeyEventResult.ignored;
|
||||
}
|
||||
|
||||
if (!_isEditing && key == LogicalKeyboardKey.arrowDown) {
|
||||
widget.onMoveDown?.call();
|
||||
return KeyEventResult.handled;
|
||||
if (widget.onMoveDown != null) {
|
||||
widget.onMoveDown!.call();
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
return KeyEventResult.ignored;
|
||||
}
|
||||
|
||||
if (_isEditing && key == LogicalKeyboardKey.escape) {
|
||||
@@ -5329,8 +5419,7 @@ class _TvEditableTextTileState extends State<_TvEditableTextTile> {
|
||||
|
||||
if (_isEditing &&
|
||||
widget.maxLines == 1 &&
|
||||
(key == LogicalKeyboardKey.enter ||
|
||||
key == LogicalKeyboardKey.select)) {
|
||||
isActivateKey) {
|
||||
_finishEditing();
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user