forked from Nexus/nexus
Small refactor of emoji controller and widget
Isolated deserialization of the large emoji json to not keep main thread busy to long Refactored textController logic in EmojiPickerButton to make popping mid buid impossible. The bug from the comment should be impossible now (The bug could be reproduce with future.delayed and microtask but)
This commit is contained in:
parent
716541b457
commit
0813597a53
2 changed files with 43 additions and 25 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
import "dart:convert";
|
import "dart:convert";
|
||||||
import "package:emoji_text_field/models/emoji_category.dart";
|
import "package:emoji_text_field/models/emoji_category.dart";
|
||||||
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
||||||
|
import "package:flutter/foundation.dart";
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
import "package:http/http.dart";
|
import "package:http/http.dart";
|
||||||
|
|
@ -19,9 +20,12 @@ class EmojiController extends AsyncNotifier<EmojiTuple> {
|
||||||
throw Exception("Failed to load emoji data");
|
throw Exception("Failed to load emoji data");
|
||||||
}
|
}
|
||||||
|
|
||||||
final data = json.decode(response.body);
|
return compute(_parseEmojiJson, response.body);
|
||||||
|
}
|
||||||
|
|
||||||
final entries = (data as List)
|
static EmojiTuple _parseEmojiJson(String body) {
|
||||||
|
final data = json.decode(body) as List;
|
||||||
|
final entries = data
|
||||||
.cast<Map<String, dynamic>>()
|
.cast<Map<String, dynamic>>()
|
||||||
.map(Emoji.fromJson)
|
.map(Emoji.fromJson)
|
||||||
.toIList();
|
.toIList();
|
||||||
|
|
|
||||||
|
|
@ -20,32 +20,46 @@ class EmojiPickerButton extends HookConsumerWidget {
|
||||||
Widget build(_, WidgetRef ref) => IconButton(
|
Widget build(_, WidgetRef ref) => IconButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
onPressed?.call();
|
onPressed?.call();
|
||||||
final controller = this.controller ?? .new();
|
|
||||||
|
final tempController = controller ?? TextEditingController();
|
||||||
|
final shouldDispose = controller == null;
|
||||||
|
var hasPopped = false;
|
||||||
|
|
||||||
|
void handler() {
|
||||||
|
if (tempController.text.isEmpty || hasPopped) return;
|
||||||
|
hasPopped = true;
|
||||||
|
|
||||||
|
onSelection?.call(tempController.text);
|
||||||
|
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
if (context.mounted) Navigator.of(context).maybePop();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
final emojis = await ref.watch(EmojiController.provider.future);
|
final emojis = await ref.watch(EmojiController.provider.future);
|
||||||
if (context.mounted) {
|
if (!context.mounted) {
|
||||||
showModalBottomSheet(
|
if (shouldDispose) tempController.dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => EmojiKeyboardView(
|
builder: (sheetContext) => EmojiKeyboardView(
|
||||||
config: .new(
|
config: .new(
|
||||||
showRecentTab: false,
|
showRecentTab: false,
|
||||||
customCategories: emojis.$1.unlock,
|
customCategories: emojis.$1.unlock,
|
||||||
customKeywords: emojis.$2.unlock,
|
customKeywords: emojis.$2.unlock,
|
||||||
backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
|
backgroundColor: Theme.of(
|
||||||
|
sheetContext,
|
||||||
|
).colorScheme.surfaceContainer,
|
||||||
height: 600,
|
height: 600,
|
||||||
),
|
),
|
||||||
textController: controller
|
textController: tempController..addListener(handler),
|
||||||
..addListener(() {
|
|
||||||
// Without this, there will sometimes be a debugLocked is not true error sometimes
|
|
||||||
// It might be preferable to use a microtask instead of a `Future.delayed`.
|
|
||||||
Future.delayed(.zero, () {
|
|
||||||
if (context.mounted) Navigator.of(context).pop();
|
|
||||||
});
|
|
||||||
onSelection?.call(controller.text);
|
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
tempController.removeListener(handler);
|
||||||
|
if (shouldDispose) tempController.dispose();
|
||||||
},
|
},
|
||||||
icon: Icon(Icons.emoji_emotions),
|
icon: Icon(Icons.emoji_emotions),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue