mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-07 13:38:13 -08:00
feat: Properly recognize the current input method
This commit is contained in:
parent
561351dd09
commit
8b9bc04380
7 changed files with 154 additions and 36 deletions
|
|
@ -9,6 +9,7 @@ import 'package:fladder/providers/settings/home_settings_provider.dart';
|
|||
import 'package:fladder/screens/home_screen.dart';
|
||||
import 'package:fladder/util/adaptive_layout/adaptive_layout_model.dart';
|
||||
import 'package:fladder/util/debug_banner.dart';
|
||||
import 'package:fladder/util/input_detector.dart';
|
||||
import 'package:fladder/util/localization_helper.dart';
|
||||
import 'package:fladder/util/poster_defaults.dart';
|
||||
import 'package:fladder/util/resolution_checker.dart';
|
||||
|
|
@ -188,11 +189,6 @@ class _AdaptiveLayoutBuilderState extends ConsumerState<AdaptiveLayoutBuilder> {
|
|||
|
||||
final selectedViewSize = selectAvailableOrSmaller<ViewSize>(viewSize, acceptedViewSizes, ViewSize.values);
|
||||
final selectedLayoutMode = selectAvailableOrSmaller<LayoutMode>(layoutMode, acceptedLayouts, LayoutMode.values);
|
||||
final input = htpcMode
|
||||
? InputDevice.dPad
|
||||
: (isDesktop || kIsWeb)
|
||||
? InputDevice.pointer
|
||||
: InputDevice.touch;
|
||||
|
||||
final posterDefaults = const PosterDefaults(size: 350, ratio: 0.55);
|
||||
|
||||
|
|
@ -200,7 +196,7 @@ class _AdaptiveLayoutBuilderState extends ConsumerState<AdaptiveLayoutBuilder> {
|
|||
AdaptiveLayoutModel(
|
||||
viewSize: selectedViewSize,
|
||||
layoutMode: selectedLayoutMode,
|
||||
inputDevice: input,
|
||||
inputDevice: InputDevice.pointer,
|
||||
platform: currentPlatform,
|
||||
isDesktop: isDesktop,
|
||||
sideBarWidth: 0,
|
||||
|
|
@ -213,33 +209,38 @@ class _AdaptiveLayoutBuilderState extends ConsumerState<AdaptiveLayoutBuilder> {
|
|||
return ValueListenableBuilder(
|
||||
valueListenable: isKeyboardOpen,
|
||||
builder: (context, value, child) {
|
||||
return MediaQuery(
|
||||
data: mediaQuery.copyWith(
|
||||
padding: (isDesktop || kIsWeb
|
||||
? const EdgeInsets.only(top: defaultTitleBarHeight, bottom: 16)
|
||||
: mediaQuery.padding),
|
||||
viewPadding: isDesktop || kIsWeb ? const EdgeInsets.only(top: defaultTitleBarHeight, bottom: 16) : null,
|
||||
),
|
||||
child: AdaptiveLayout(
|
||||
data: currentLayout.copyWith(
|
||||
viewSize: selectedViewSize,
|
||||
layoutMode: selectedLayoutMode,
|
||||
inputDevice: input,
|
||||
platform: currentPlatform,
|
||||
isDesktop: isDesktop,
|
||||
controller: scrollControllers,
|
||||
posterDefaults: posterDefaults,
|
||||
return InputDetector(
|
||||
isDesktop: isDesktop,
|
||||
htpcMode: htpcMode,
|
||||
child: (input) => MediaQuery(
|
||||
data: mediaQuery.copyWith(
|
||||
navigationMode: input == InputDevice.dPad ? NavigationMode.directional : NavigationMode.traditional,
|
||||
padding: (isDesktop || kIsWeb
|
||||
? const EdgeInsets.only(top: defaultTitleBarHeight, bottom: 16)
|
||||
: mediaQuery.padding),
|
||||
viewPadding: isDesktop || kIsWeb ? const EdgeInsets.only(top: defaultTitleBarHeight, bottom: 16) : null,
|
||||
),
|
||||
child: Builder(
|
||||
builder: (context) => isDesktop
|
||||
? ResolutionChecker(
|
||||
child: widget.adaptiveLayout == null
|
||||
? DebugBanner(child: widget.child(context))
|
||||
: widget.child(context),
|
||||
)
|
||||
: widget.adaptiveLayout == null
|
||||
? DebugBanner(child: widget.child(context))
|
||||
: widget.child(context),
|
||||
child: AdaptiveLayout(
|
||||
data: currentLayout.copyWith(
|
||||
viewSize: selectedViewSize,
|
||||
layoutMode: selectedLayoutMode,
|
||||
inputDevice: input,
|
||||
platform: currentPlatform,
|
||||
isDesktop: isDesktop,
|
||||
controller: scrollControllers,
|
||||
posterDefaults: posterDefaults,
|
||||
),
|
||||
child: Builder(
|
||||
builder: (context) => isDesktop
|
||||
? ResolutionChecker(
|
||||
child: widget.adaptiveLayout == null
|
||||
? DebugBanner(child: widget.child(context))
|
||||
: widget.child(context),
|
||||
)
|
||||
: widget.adaptiveLayout == null
|
||||
? DebugBanner(child: widget.child(context))
|
||||
: widget.child(context),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -86,7 +86,10 @@ class AdaptiveLayoutModel {
|
|||
@override
|
||||
bool operator ==(covariant AdaptiveLayoutModel other) {
|
||||
if (identical(this, other)) return true;
|
||||
return other.viewSize == viewSize && other.layoutMode == layoutMode && other.sideBarWidth == sideBarWidth;
|
||||
return other.viewSize == viewSize &&
|
||||
other.layoutMode == layoutMode &&
|
||||
other.sideBarWidth == sideBarWidth &&
|
||||
other.inputDevice == inputDevice;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -146,6 +146,8 @@ class FocusButtonState extends State<FocusButton> {
|
|||
child: Focus(
|
||||
focusNode: focusNode,
|
||||
autofocus: widget.autoFocus,
|
||||
canRequestFocus: widget.onTap != null || widget.onLongPress != null || widget.onSecondaryTapDown != null,
|
||||
skipTraversal: widget.onTap == null && widget.onLongPress == null && widget.onSecondaryTapDown != null,
|
||||
onFocusChange: (value) {
|
||||
widget.onFocusChanged?.call(value);
|
||||
if (value) {
|
||||
|
|
|
|||
106
lib/util/input_detector.dart
Normal file
106
lib/util/input_detector.dart
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:fladder/util/adaptive_layout/adaptive_layout.dart';
|
||||
|
||||
class InputDetector extends StatefulWidget {
|
||||
final bool isDesktop;
|
||||
final bool htpcMode;
|
||||
final Widget Function(InputDevice input) child;
|
||||
|
||||
const InputDetector({
|
||||
super.key,
|
||||
required this.isDesktop,
|
||||
required this.htpcMode,
|
||||
required this.child,
|
||||
});
|
||||
|
||||
@override
|
||||
State<InputDetector> createState() => _InputDetectorState();
|
||||
}
|
||||
|
||||
class _InputDetectorState extends State<InputDetector> {
|
||||
late InputDevice _currentInput = widget.htpcMode
|
||||
? InputDevice.dPad
|
||||
: (widget.isDesktop || kIsWeb)
|
||||
? InputDevice.pointer
|
||||
: InputDevice.touch;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_startListeningToKeyboard();
|
||||
}
|
||||
|
||||
void _startListeningToKeyboard() {
|
||||
ServicesBinding.instance.keyboard.addHandler(_handleKeyPress);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
ServicesBinding.instance.keyboard.removeHandler(_handleKeyPress);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
bool _handleKeyPress(KeyEvent event) {
|
||||
if (event is KeyDownEvent) {
|
||||
if (_isEditableTextFocused() &&
|
||||
(event.logicalKey == LogicalKeyboardKey.arrowUp ||
|
||||
event.logicalKey == LogicalKeyboardKey.arrowDown ||
|
||||
event.logicalKey == LogicalKeyboardKey.arrowLeft ||
|
||||
event.logicalKey == LogicalKeyboardKey.arrowRight)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.logicalKey == LogicalKeyboardKey.arrowUp ||
|
||||
event.logicalKey == LogicalKeyboardKey.arrowDown ||
|
||||
event.logicalKey == LogicalKeyboardKey.arrowLeft ||
|
||||
event.logicalKey == LogicalKeyboardKey.arrowRight ||
|
||||
event.logicalKey == LogicalKeyboardKey.select) {
|
||||
_updateInputDevice(InputDevice.dPad);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool _isEditableTextFocused() {
|
||||
final focus = FocusManager.instance.primaryFocus;
|
||||
if (focus == null) return false;
|
||||
final ctx = focus.context;
|
||||
if (ctx == null) return false;
|
||||
|
||||
if (ctx.widget is EditableText) return true;
|
||||
return ctx.findAncestorWidgetOfExactType<EditableText>() != null;
|
||||
}
|
||||
|
||||
void _handlePointerEvent(PointerEvent event) {
|
||||
if (event is PointerDownEvent) {
|
||||
if (event.kind == PointerDeviceKind.touch) {
|
||||
_updateInputDevice(InputDevice.touch);
|
||||
} else if (event.kind == PointerDeviceKind.mouse) {
|
||||
_updateInputDevice(InputDevice.pointer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _updateInputDevice(InputDevice device) {
|
||||
if (_currentInput != device) {
|
||||
setState(() {
|
||||
_currentInput = device;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Listener(
|
||||
onPointerDown: _handlePointerEvent,
|
||||
behavior: HitTestBehavior.translucent,
|
||||
child: Builder(
|
||||
builder: (context) => widget.child(_currentInput),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,6 @@ class MediaQueryScaler extends StatelessWidget {
|
|||
final screenSize = MediaQuery.sizeOf(context) * scale;
|
||||
|
||||
final scaledMedia = mediaQuery.copyWith(
|
||||
navigationMode: NavigationMode.directional,
|
||||
size: screenSize,
|
||||
padding: mediaQuery.padding * scale,
|
||||
viewInsets: mediaQuery.viewInsets * scale,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,11 @@ class EnumBox<T> extends StatelessWidget {
|
|||
final String current;
|
||||
final List<ItemAction> Function(BuildContext context) itemBuilder;
|
||||
|
||||
const EnumBox({required this.current, required this.itemBuilder, super.key});
|
||||
const EnumBox({
|
||||
required this.current,
|
||||
required this.itemBuilder,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
|
||||
import 'package:fladder/models/item_base_model.dart';
|
||||
import 'package:fladder/theme.dart';
|
||||
import 'package:fladder/util/adaptive_layout/adaptive_layout.dart';
|
||||
import 'package:fladder/util/fladder_image.dart';
|
||||
|
||||
Future<void> showBottomSheetPill({
|
||||
|
|
@ -44,7 +45,9 @@ Future<void> showBottomSheetPill({
|
|||
height: 8,
|
||||
width: 35,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
color: AdaptiveLayout.inputDeviceOf(context) == InputDevice.touch
|
||||
? Theme.of(context).colorScheme.onSurface
|
||||
: Colors.transparent,
|
||||
borderRadius: FladderTheme.largeShape.borderRadius,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue