Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ux): update the search focus for emojis, emoticons, and gifs #36

Merged
merged 1 commit into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 33 additions & 23 deletions lib/components/root/emoji.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import 'package:collection/collection.dart';
import 'package:flemozi/collections/emojis.dart';
import 'package:flemozi/components/root/twemoji.dart';
import 'package:flemozi/hooks/use_window_listeners.dart';
import 'package:flemozi/intents/close_window.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flemozi/collections/emojis.dart';
import 'package:fuzzywuzzy/fuzzywuzzy.dart';

typedef RatioEmojiType = ({
Expand All @@ -21,14 +21,16 @@ typedef RatioEmojiType = ({
});

class Emoji extends HookWidget {
const Emoji({Key? key}) : super(key: key);
const Emoji({super.key});

@override
Widget build(BuildContext context) {
final searchFocusNode = useFocusNode();
final searchTerm = useState("");
final firstEmojiFocusNode = useFocusNode();

FocusScope.of(context).requestFocus(searchFocusNode);

final filteredEmojis = useMemoized(
() {
if (searchTerm.value.isEmpty) {
Expand Down Expand Up @@ -80,7 +82,7 @@ class Emoji extends HookWidget {

useWindowListeners(
onWindowFocus: () {
searchFocusNode.requestFocus();
FocusScope.of(context).requestFocus(searchFocusNode);
},
);

Expand Down Expand Up @@ -128,28 +130,36 @@ class Emoji extends HookWidget {
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
CallbackShortcuts(
bindings: {
LogicalKeySet(LogicalKeyboardKey.arrowDown): () {
FocusScope.of(context).requestFocus(firstEmojiFocusNode);
Padding(
padding: const EdgeInsets.only( bottom: 12.0),
child: CallbackShortcuts(
bindings: {
LogicalKeySet(LogicalKeyboardKey.arrowDown): () {
if (filteredEmojis.isNotEmpty) {
FocusScope.of(context).requestFocus(firstEmojiFocusNode);
}
},
},
},
child: TextField(
autofocus: true,
focusNode: searchFocusNode,
decoration: const InputDecoration(
hintText: "Search",
prefixIcon: Icon(Icons.search),
child: TextField(
autofocus: true,
focusNode: searchFocusNode,
decoration: const InputDecoration(
hintText: "Search",
prefixIcon: Icon(Icons.search),
),
onChanged: (value) {
searchTerm.value = value;
},
onSubmitted: (value) {
if (filteredEmojis.isNotEmpty) {
FocusScope.of(context).requestFocus(firstEmojiFocusNode);
} else {
FocusScope.of(context).requestFocus(searchFocusNode);
}
},
),
onChanged: (value) {
searchTerm.value = value;
},
onSubmitted: (value) {
searchFocusNode.nextFocus();
},
),
),
const SizedBox(height: 10),
Expanded(
child: GridView.builder(
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
Expand All @@ -163,7 +173,7 @@ class Emoji extends HookWidget {
return HookBuilder(builder: (context) {
final focusnodeUn = useFocusNode();
final focusNode =
index == 0 ? firstEmojiFocusNode : focusnodeUn;
index == 0 ? firstEmojiFocusNode : focusnodeUn;
final emoji = filteredEmojis.elementAt(index);
final tooltipKey = GlobalKey<TooltipState>();

Expand All @@ -184,7 +194,7 @@ class Emoji extends HookWidget {
return CallbackShortcuts(
bindings: {
LogicalKeySet(LogicalKeyboardKey.escape): () {
searchFocusNode.requestFocus();
FocusScope.of(context).requestFocus(searchFocusNode);
},
},
child: Tooltip(
Expand Down
50 changes: 30 additions & 20 deletions lib/components/root/emoticon.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:fuzzywuzzy/fuzzywuzzy.dart';

class Emoticon extends HookWidget {
const Emoticon({Key? key}) : super(key: key);
const Emoticon({super.key});

@override
Widget build(BuildContext context) {
final searchFocusNode = useFocusNode();
final searchTerm = useState("");
final firstEmoticonFocusNode = useFocusNode();

FocusScope.of(context).requestFocus(searchFocusNode);

final List<Map<String, String>> filteredEmoticons = useMemoized(
() {
if (searchTerm.value.isEmpty) {
Expand Down Expand Up @@ -70,28 +72,36 @@ class Emoticon extends HookWidget {
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
CallbackShortcuts(
bindings: {
LogicalKeySet(LogicalKeyboardKey.arrowDown): () {
FocusScope.of(context).requestFocus(firstEmoticonFocusNode);
Padding(
padding: const EdgeInsets.only(bottom: 12.0),
child: CallbackShortcuts(
bindings: {
LogicalKeySet(LogicalKeyboardKey.arrowDown): () {
if (filteredEmoticons.isNotEmpty) {
FocusScope.of(context).requestFocus(firstEmoticonFocusNode);
}
},
},
},
child: TextField(
autofocus: true,
focusNode: searchFocusNode,
decoration: const InputDecoration(
hintText: "Search",
prefixIcon: Icon(Icons.search),
child: TextField(
autofocus: true,
focusNode: searchFocusNode,
decoration: const InputDecoration(
hintText: "Search",
prefixIcon: Icon(Icons.search),
),
onChanged: (value) {
searchTerm.value = value;
},
onSubmitted: (value) {
if (filteredEmoticons.isNotEmpty) {
firstEmoticonFocusNode.requestFocus();
} else {
FocusScope.of(context).requestFocus(searchFocusNode);
}
},
),
onChanged: (value) {
searchTerm.value = value;
},
onSubmitted: (value) {
searchFocusNode.nextFocus();
},
),
),
const SizedBox(height: 10),
Expanded(
child: GridView.builder(
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
Expand Down Expand Up @@ -165,7 +175,7 @@ class Emoticon extends HookWidget {
return CallbackShortcuts(
bindings: {
LogicalKeySet(LogicalKeyboardKey.escape): () {
searchFocusNode.requestFocus();
FocusScope.of(context).requestFocus(searchFocusNode);
},
},
child: Tooltip(
Expand Down
42 changes: 27 additions & 15 deletions lib/components/root/gif.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const placeholder = SizedBox(
);

class Gif extends HookConsumerWidget {
const Gif({Key? key}) : super(key: key);
const Gif({super.key});

@override
Widget build(BuildContext context, ref) {
Expand Down Expand Up @@ -86,6 +86,8 @@ class Gif extends HookConsumerWidget {
final gifs =
text.value.isEmpty || searchGifs.isEmpty ? displayGifs : searchGifs;

FocusScope.of(context).requestFocus(searchFocusNode);

useEffect(() {
if (text.value.isNotEmpty) {
WidgetsBinding.instance.addPostFrameCallback((_) async {
Expand Down Expand Up @@ -120,18 +122,28 @@ class Gif extends HookConsumerWidget {

return Column(
children: [
CallbackShortcuts(
bindings: {
LogicalKeySet(LogicalKeyboardKey.arrowDown): () {
FocusScope.of(context).requestFocus(focusNode);
Padding(
padding: const EdgeInsets.only(bottom: 12.0),
child: CallbackShortcuts(
bindings: {
LogicalKeySet(LogicalKeyboardKey.arrowDown): () {
FocusScope.of(context).requestFocus(focusNode);
},
},
},
child: TextField(
autofocus: true,
focusNode: searchFocusNode,
onChanged: (value) => text.value = value,
decoration: const InputDecoration(
hintText: 'Search GIFs and Stickers',
child: TextField(
autofocus: true,
focusNode: searchFocusNode,
onChanged: (value) => text.value = value,
onSubmitted: (_) => {
if (gifs.isNotEmpty) {
FocusScope.of(context).requestFocus(focusNode),
} else {
FocusScope.of(context).requestFocus(searchFocusNode),
}
},
decoration: const InputDecoration(
hintText: 'Search GIFs and Stickers',
),
),
),
),
Expand Down Expand Up @@ -194,8 +206,8 @@ class Gif extends HookConsumerWidget {
}
}
},
child: Stack(
children: const [
child: const Stack(
children: [
Center(
child: SizedBox(
height: 50,
Expand All @@ -221,7 +233,7 @@ class Gif extends HookConsumerWidget {
if (imageFile == null) {
return;
}
await ClipboardWriter.instance.write([
await SystemClipboard.instance?.write([
DataWriterItem(suggestedName: basename(gif))
..add(Formats.png(imageFile))
..add(Formats.bmp(imageFile))
Expand Down