Clean TV navigation traces and update app icons

This commit is contained in:
dwindown
2026-03-31 14:18:09 +07:00
parent 8774735e38
commit 49f130b5ea
33 changed files with 58 additions and 26 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 544 B

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 442 B

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 721 B

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 450 B

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 B

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 B

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 704 B

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 586 B

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 762 B

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -10,6 +10,7 @@ import '../../core/sacred_tokens.dart';
import '../../providers.dart';
import '../../data/services/sync_service.dart';
import '../../data/services/myquran_service.dart';
import '../../data/services/sound_service.dart';
import 'package:file_picker/file_picker.dart';
import 'dart:io';
@@ -120,7 +121,7 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
_simulasiFocusNodes = [
_simulasiEntryFocusNode,
...List.generate(
6,
8,
(index) => FocusNode(debugLabel: 'simulasi_row_${index + 1}'),
),
];
@@ -1005,16 +1006,8 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
setState(() => _selectedTab = index);
}
void _traceNav(String message) {
assert(() {
debugPrint('[TV NAV] $message');
return true;
}());
}
void _focusNavTab(int index) {
if (index < 0 || index >= _navFocusNodes.length) return;
_traceNav('focus nav[$index]');
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
_navFocusNodes[index].requestFocus();
@@ -1025,7 +1018,6 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
void _focusIdentityRow(int index) {
if (_selectedTab != 0) return;
if (index < 0 || index >= _identityFocusNodes.length) return;
_traceNav('focus identitas[$index]');
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
_identityFocusNodes[index].requestFocus();
@@ -1036,7 +1028,6 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
void _focusJumatRow(int index) {
if (_selectedTab != 3) return;
if (index < 0 || index >= _jumatFocusNodes.length) return;
_traceNav('focus jumat[$index]');
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
_jumatFocusNodes[index].requestFocus();
@@ -1047,7 +1038,6 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
void _focusSimulasiRow(int index) {
if (_selectedTab != 4) return;
if (index < 0 || index >= _simulasiFocusNodes.length) return;
_traceNav('focus simulasi[$index]');
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
_simulasiFocusNodes[index].requestFocus();
@@ -1210,7 +1200,6 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
return KeyEventResult.ignored;
}
final key = event.logicalKey;
_traceNav('identitas[$index] key=$key');
if (key == LogicalKeyboardKey.arrowUp) {
_focusIdentityRow(index - 1);
return KeyEventResult.handled;
@@ -1274,7 +1263,6 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
return KeyEventResult.ignored;
}
final key = event.logicalKey;
_traceNav('simulasi[$index] key=$key');
if (key == LogicalKeyboardKey.arrowUp) {
_focusSimulasiRow(index - 1);
return KeyEventResult.handled;
@@ -3393,6 +3381,18 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
rowIndex: 0,
),
SizedBox(height: 16 * s),
_simulasiCard(
s: s,
title: '15 Detik Sebelum Adzan',
icon: HugeIcons.strokeRoundedNotification03,
desc: 'Melompat ke 15 detik sebelum Adzan Dzuhur untuk memeriksa transisi terakhir menuju Adzan.',
onTap: () => _activateSimulation(
() => _simulateEvent('pre_adzan_15'),
),
focusNode: _simulasiFocusNodes[1],
rowIndex: 1,
),
SizedBox(height: 16 * s),
_simulasiCard(
s: s,
title: 'Menuju Adzan',
@@ -3401,8 +3401,8 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
onTap: () => _activateSimulation(
() => _simulateEvent('pre_adzan'),
),
focusNode: _simulasiFocusNodes[1],
rowIndex: 1,
focusNode: _simulasiFocusNodes[2],
rowIndex: 2,
),
SizedBox(height: 16 * s),
_simulasiCard(
@@ -3413,8 +3413,20 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
onTap: () => _activateSimulation(
() => _simulateEvent('adzan'),
),
focusNode: _simulasiFocusNodes[2],
rowIndex: 2,
focusNode: _simulasiFocusNodes[3],
rowIndex: 3,
),
SizedBox(height: 16 * s),
_simulasiCard(
s: s,
title: '15 Detik Sebelum Iqamah',
icon: HugeIcons.strokeRoundedTimer02,
desc: 'Melompat ke 15 detik sebelum Iqamah Dzuhur untuk memeriksa hitungan mundur terakhir.',
onTap: () => _activateSimulation(
() => _simulateEvent('pre_iqomah_15'),
),
focusNode: _simulasiFocusNodes[4],
rowIndex: 4,
),
SizedBox(height: 16 * s),
_simulasiCard(
@@ -3425,8 +3437,8 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
onTap: () => _activateSimulation(
() => _simulateEvent('iqomah'),
),
focusNode: _simulasiFocusNodes[3],
rowIndex: 3,
focusNode: _simulasiFocusNodes[5],
rowIndex: 5,
),
SizedBox(height: 16 * s),
_simulasiCard(
@@ -3437,8 +3449,8 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
onTap: () => _activateSimulation(
() => _simulateEvent('jumat_incoming'),
),
focusNode: _simulasiFocusNodes[4],
rowIndex: 4,
focusNode: _simulasiFocusNodes[6],
rowIndex: 6,
),
SizedBox(height: 16 * s),
_simulasiCard(
@@ -3449,8 +3461,8 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
onTap: () => _activateSimulation(
() => _simulateEvent('jumat_khutbah'),
),
focusNode: _simulasiFocusNodes[5],
rowIndex: 5,
focusNode: _simulasiFocusNodes[7],
rowIndex: 7,
),
SizedBox(height: 16 * s),
_simulasiCard(
@@ -3461,8 +3473,8 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
onTap: () => _activateSimulation(
() => _simulateEvent('shalat'),
),
focusNode: _simulasiFocusNodes[6],
rowIndex: 6,
focusNode: _simulasiFocusNodes[8],
rowIndex: 8,
),
],
),
@@ -3598,12 +3610,21 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
DateTime targetTime;
switch (eventType) {
case 'pre_adzan_15':
targetTime = dzuhurTime.subtract(const Duration(seconds: 15));
break;
case 'pre_adzan':
targetTime = dzuhurTime.subtract(const Duration(minutes: 2));
break;
case 'adzan':
targetTime = dzuhurTime;
break;
case 'pre_iqomah_15':
final settings = ref.read(settingsProvider);
targetTime = dzuhurTime
.add(Duration(minutes: settings.iqomahDzuhur))
.subtract(const Duration(seconds: 15));
break;
case 'iqomah':
targetTime = dzuhurTime.add(const Duration(seconds: 45)); // During iqomah
break;
@@ -3630,6 +3651,17 @@ class _AdminScreenState extends ConsumerState<AdminScreen> {
final offset = targetTime.difference(realNow);
_simulateTimeOffset(offset);
switch (eventType) {
case 'adzan':
unawaited(SoundService.instance.playAdzanBeep());
break;
case 'iqomah':
unawaited(SoundService.instance.playIqomahCountdown());
break;
default:
break;
}
}
void _activateSimulation(VoidCallback action) {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 520 B

After

Width:  |  Height:  |  Size: 878 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 917 B

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB