feat(tv-ui): add slideshow pattern mode and improve admin readability

This commit is contained in:
dwindown
2026-04-06 09:23:42 +07:00
parent 185c55a143
commit 414450125d
6 changed files with 312 additions and 34 deletions

View File

@@ -49,6 +49,10 @@ class _HomeViewState extends ConsumerState<HomeView> {
bool _isAutoRefreshRunning = false;
int _touchUnlockTapCount = 0;
LogicalKeyboardKey _normalizedComboKey(LogicalKeyboardKey key) {
return key == LogicalKeyboardKey.enter ? LogicalKeyboardKey.select : key;
}
@override
void initState() {
super.initState();
@@ -162,6 +166,13 @@ class _HomeViewState extends ConsumerState<HomeView> {
_recentKeys.removeAt(0);
}
final manualAction = _matchManualRotateSequence();
if (manualAction != null) {
_dispatchManualBackgroundRotate(manualAction);
_resetCombo();
return KeyEventResult.handled;
}
if (_matchesUnlockSequence()) {
_resetCombo();
WidgetsBinding.instance.addPostFrameCallback((_) async {
@@ -192,14 +203,50 @@ class _HomeViewState extends ConsumerState<HomeView> {
if (_recentKeys.length != _adminUnlockSequence.length) return false;
for (var i = 0; i < _adminUnlockSequence.length; i++) {
final current = _recentKeys[i] == LogicalKeyboardKey.enter
? LogicalKeyboardKey.select
: _recentKeys[i];
final current = _normalizedComboKey(_recentKeys[i]);
if (current != _adminUnlockSequence[i]) return false;
}
return true;
}
BackgroundRotateAction? _matchManualRotateSequence() {
if (_recentKeys.length < 3) return null;
final tail = _recentKeys.sublist(_recentKeys.length - 3).map(_normalizedComboKey).toList();
if (tail[0] == LogicalKeyboardKey.arrowRight &&
tail[1] == LogicalKeyboardKey.arrowRight &&
tail[2] == LogicalKeyboardKey.select) {
return BackgroundRotateAction.next;
}
if (tail[0] == LogicalKeyboardKey.arrowLeft &&
tail[1] == LogicalKeyboardKey.arrowLeft &&
tail[2] == LogicalKeyboardKey.select) {
return BackgroundRotateAction.previous;
}
if (tail[0] == LogicalKeyboardKey.arrowDown &&
tail[1] == LogicalKeyboardKey.arrowDown &&
tail[2] == LogicalKeyboardKey.select) {
return BackgroundRotateAction.random;
}
return null;
}
void _dispatchManualBackgroundRotate(BackgroundRotateAction action) {
final screenData = ref.read(screenStateProvider);
final isMainScreen = ref.read(isMainScreenProvider);
if (!isMainScreen ||
!(screenData.state == ScreenState.normal ||
screenData.state == ScreenState.menujuAdzan)) {
return;
}
final notifier = ref.read(backgroundRotateCommandProvider.notifier);
final current = notifier.state;
notifier.state = BackgroundRotateCommand(
nonce: current.nonce + 1,
action: action,
);
}
void _resetCombo() {
_comboResetTimer?.cancel();
_recentKeys.clear();
@@ -262,6 +309,7 @@ class _HomeViewState extends ConsumerState<HomeView> {
final screenData = ref.watch(screenStateProvider);
final isMainScreen = ref.watch(isMainScreenProvider);
final rotationIndex = ref.watch(rotationIndexProvider);
// Determine which screen to display
Widget screen;
@@ -273,7 +321,7 @@ class _HomeViewState extends ConsumerState<HomeView> {
} else {
screen = isMainScreen
? const MainScreen(key: ValueKey('main'))
: const SlideshowScreen(key: ValueKey('slideshow'));
: SlideshowScreen(key: ValueKey('slideshow-$rotationIndex'));
}
break;
case ScreenState.kembaliNormal: