Files
neomovies-mobile/lib/utils/focus_manager.dart
2025-07-19 20:50:26 +03:00

163 lines
4.8 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
/// Глобальный менеджер фокуса для управления навигацией между элементами интерфейса
class GlobalFocusManager {
static final GlobalFocusManager _instance = GlobalFocusManager._internal();
factory GlobalFocusManager() => _instance;
GlobalFocusManager._internal();
// Фокус ноды для разных элементов интерфейса
FocusNode? _appBarFocusNode;
FocusNode? _contentFocusNode;
FocusNode? _bottomNavFocusNode;
// Текущее состояние фокуса
FocusArea _currentFocusArea = FocusArea.content;
// Callback для уведомления об изменении фокуса
VoidCallback? _onFocusChanged;
void initialize({
FocusNode? appBarFocusNode,
FocusNode? contentFocusNode,
FocusNode? bottomNavFocusNode,
VoidCallback? onFocusChanged,
}) {
_appBarFocusNode = appBarFocusNode;
_contentFocusNode = contentFocusNode;
_bottomNavFocusNode = bottomNavFocusNode;
_onFocusChanged = onFocusChanged;
}
/// Обработка глобальных клавиш
KeyEventResult handleGlobalKey(KeyEvent event) {
if (event is KeyDownEvent) {
switch (event.logicalKey) {
case LogicalKeyboardKey.escape:
case LogicalKeyboardKey.goBack:
_focusAppBar();
return KeyEventResult.handled;
case LogicalKeyboardKey.arrowUp:
if (_currentFocusArea == FocusArea.appBar) {
_focusContent();
return KeyEventResult.handled;
}
break;
case LogicalKeyboardKey.arrowDown:
if (_currentFocusArea == FocusArea.content) {
_focusBottomNav();
return KeyEventResult.handled;
} else if (_currentFocusArea == FocusArea.appBar) {
_focusContent();
return KeyEventResult.handled;
}
break;
}
}
return KeyEventResult.ignored;
}
void _focusAppBar() {
if (_appBarFocusNode != null) {
_currentFocusArea = FocusArea.appBar;
_appBarFocusNode!.requestFocus();
_onFocusChanged?.call();
}
}
void _focusContent() {
if (_contentFocusNode != null) {
_currentFocusArea = FocusArea.content;
_contentFocusNode!.requestFocus();
_onFocusChanged?.call();
}
}
void _focusBottomNav() {
if (_bottomNavFocusNode != null) {
_currentFocusArea = FocusArea.bottomNav;
_bottomNavFocusNode!.requestFocus();
_onFocusChanged?.call();
}
}
/// Установить фокус на контент (для использования извне)
void focusContent() => _focusContent();
/// Установить фокус на навбар (для использования извне)
void focusAppBar() => _focusAppBar();
/// Получить текущую область фокуса
FocusArea get currentFocusArea => _currentFocusArea;
/// Проверить, находится ли фокус в контенте
bool get isContentFocused => _currentFocusArea == FocusArea.content;
/// Проверить, находится ли фокус в навбаре
bool get isAppBarFocused => _currentFocusArea == FocusArea.appBar;
void dispose() {
_appBarFocusNode = null;
_contentFocusNode = null;
_bottomNavFocusNode = null;
_onFocusChanged = null;
}
}
/// Области фокуса в приложении
enum FocusArea {
appBar,
content,
bottomNav,
}
/// Виджет-обертка для глобального управления фокусом
class GlobalFocusWrapper extends StatefulWidget {
final Widget child;
final FocusNode? contentFocusNode;
const GlobalFocusWrapper({
super.key,
required this.child,
this.contentFocusNode,
});
@override
State<GlobalFocusWrapper> createState() => _GlobalFocusWrapperState();
}
class _GlobalFocusWrapperState extends State<GlobalFocusWrapper> {
final GlobalFocusManager _focusManager = GlobalFocusManager();
late final FocusNode _wrapperFocusNode;
@override
void initState() {
super.initState();
_wrapperFocusNode = FocusNode();
// Инициализируем глобальный менеджер фокуса
_focusManager.initialize(
contentFocusNode: widget.contentFocusNode ?? _wrapperFocusNode,
onFocusChanged: () => setState(() {}),
);
}
@override
void dispose() {
_wrapperFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Focus(
focusNode: _wrapperFocusNode,
onKeyEvent: (node, event) => _focusManager.handleGlobalKey(event),
child: widget.child,
);
}
}