mirror of
https://codeberg.org/shroff/phylum.git
synced 2026-05-09 05:39:35 -05:00
[client] Search focus
This commit is contained in:
@@ -9,7 +9,9 @@ import 'package:provider/provider.dart';
|
||||
|
||||
class AppActions extends StatelessWidget {
|
||||
final Widget child;
|
||||
const AppActions({super.key, required this.child});
|
||||
final FocusNode searchFocusNode;
|
||||
|
||||
const AppActions({super.key, required this.child, required this.searchFocusNode});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -65,6 +67,7 @@ class AppActions extends StatelessWidget {
|
||||
NavForwardIntent: CallbackAction<NavForwardIntent>(
|
||||
onInvoke: (i) => context.read<PhylumRouterDelegate>().goForward(),
|
||||
),
|
||||
FocusSearchIntent: CallbackAction<FocusSearchIntent>(onInvoke: (i) => searchFocusNode.requestFocus()),
|
||||
},
|
||||
child: child,
|
||||
);
|
||||
|
||||
@@ -13,7 +13,7 @@ import 'package:phylum/ui/menu/bottom_sheet.dart';
|
||||
import 'package:phylum/ui/menu/option_groups.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class AppLayout extends StatelessWidget {
|
||||
class AppLayout extends StatefulWidget {
|
||||
const AppLayout._();
|
||||
|
||||
static Widget create() {
|
||||
@@ -24,10 +24,28 @@ class AppLayout extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
State<AppLayout> createState() => _AppLayoutState();
|
||||
}
|
||||
|
||||
class _AppLayoutState extends State<AppLayout> {
|
||||
final _searchFocusNode = FocusNode();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_searchFocusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final size = MediaQuery.sizeOf(context);
|
||||
final layout = size.width <= 600 ? CollapsedAppLayout() : ExpandedAppLayout(large: size.width > 1200);
|
||||
final layout = size.width <= 600
|
||||
? CollapsedAppLayout()
|
||||
: ExpandedAppLayout(
|
||||
large: size.width > 1200,
|
||||
searchFocusNode: _searchFocusNode,
|
||||
);
|
||||
return ExternalDropRegion(
|
||||
buildItem: (context, dropTargetActive) {
|
||||
final child = (dropTargetActive)
|
||||
@@ -48,7 +66,10 @@ class AppLayout extends StatelessWidget {
|
||||
],
|
||||
)
|
||||
: layout;
|
||||
return AppActions(child: child);
|
||||
return AppActions(
|
||||
searchFocusNode: _searchFocusNode,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -121,8 +142,10 @@ class CollapsedAppLayout extends StatelessWidget {
|
||||
}
|
||||
|
||||
class ExpandedAppLayout extends StatelessWidget {
|
||||
final FocusNode searchFocusNode;
|
||||
final bool large;
|
||||
const ExpandedAppLayout({super.key, required this.large});
|
||||
|
||||
const ExpandedAppLayout({super.key, required this.large, required this.searchFocusNode});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -156,7 +179,9 @@ class ExpandedAppLayout extends StatelessWidget {
|
||||
child: Icon(Icons.search),
|
||||
),
|
||||
Expanded(
|
||||
child: SearchField(),
|
||||
child: SearchField(
|
||||
focusNode: searchFocusNode,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -96,6 +96,10 @@ class NavIntent extends Intent {
|
||||
const NavIntent({required this.target});
|
||||
}
|
||||
|
||||
class FocusSearchIntent extends Intent {
|
||||
const FocusSearchIntent();
|
||||
}
|
||||
|
||||
Map<ShortcutActivator, Intent> get appShortcuts => const {
|
||||
// General
|
||||
SingleActivator(LogicalKeyboardKey.tab): NextFocusIntent(),
|
||||
@@ -142,6 +146,7 @@ Map<ShortcutActivator, Intent> get appShortcuts => const {
|
||||
// Top-level Navigation
|
||||
SingleActivator(LogicalKeyboardKey.arrowUp, alt: true): NavUpIntent(),
|
||||
SingleActivator(LogicalKeyboardKey.keyH, alt: true): NavIntent(target: ExplorerPageHome()),
|
||||
SingleActivator(LogicalKeyboardKey.keyS, alt: true): FocusSearchIntent(),
|
||||
if (!kIsWeb) SingleActivator(LogicalKeyboardKey.arrowLeft, alt: true): NavBackIntent(),
|
||||
if (!kIsWeb) SingleActivator(LogicalKeyboardKey.arrowRight, alt: true): NavForwardIntent(),
|
||||
};
|
||||
|
||||
@@ -5,7 +5,9 @@ import 'package:phylum/ui/explorer/page.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class SearchField extends StatefulWidget {
|
||||
const SearchField({super.key});
|
||||
final FocusNode focusNode;
|
||||
|
||||
const SearchField({super.key, required this.focusNode});
|
||||
|
||||
@override
|
||||
State<SearchField> createState() => _SearchFieldState();
|
||||
@@ -35,19 +37,25 @@ class _SearchFieldState extends State<SearchField> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TextField(
|
||||
decoration: InputDecoration.collapsed(
|
||||
hintText: 'Search Files...',
|
||||
hintStyle: TextStyle(fontSize: 18),
|
||||
),
|
||||
controller: _controller,
|
||||
style: TextStyle(fontSize: 18),
|
||||
onSubmitted: (text) {
|
||||
final query = text.trim();
|
||||
if (query.isNotEmpty) {
|
||||
context.read<PhylumRouterDelegate>().go(ExplorerPageSearch(query: query));
|
||||
}
|
||||
return Actions(
|
||||
actions: {
|
||||
DismissIntent: CallbackAction<DismissIntent>(onInvoke: (i) => widget.focusNode.nextFocus()),
|
||||
},
|
||||
child: TextField(
|
||||
decoration: InputDecoration.collapsed(
|
||||
hintText: 'Search Files...',
|
||||
hintStyle: TextStyle(fontSize: 18),
|
||||
),
|
||||
focusNode: widget.focusNode,
|
||||
controller: _controller,
|
||||
style: TextStyle(fontSize: 18),
|
||||
onSubmitted: (text) {
|
||||
final query = text.trim();
|
||||
if (query.isNotEmpty) {
|
||||
context.read<PhylumRouterDelegate>().go(ExplorerPageSearch(query: query));
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user