| 
									
										
										
										
											2023-11-22 10:49:22 +08:00
										 |  |  | import 'dart:io'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-02 15:24:17 +08:00
										 |  |  | import 'package:appflowy/plugins/base/emoji/emoji_picker_header.dart'; | 
					
						
							|  |  |  | import 'package:appflowy/plugins/base/emoji/emoji_search_bar.dart'; | 
					
						
							|  |  |  | import 'package:appflowy/plugins/base/emoji/emoji_skin_tone.dart'; | 
					
						
							|  |  |  | import 'package:flowy_infra_ui/flowy_infra_ui.dart'; | 
					
						
							|  |  |  | import 'package:flutter/material.dart'; | 
					
						
							| 
									
										
										
										
											2023-11-14 22:33:07 +08:00
										 |  |  | import 'package:flutter_emoji_mart/flutter_emoji_mart.dart'; | 
					
						
							| 
									
										
										
										
											2023-11-22 10:49:22 +08:00
										 |  |  | import 'package:google_fonts/google_fonts.dart'; | 
					
						
							| 
									
										
										
										
											2023-11-02 15:24:17 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // use a global value to store the selected emoji to prevent reloading every time.
 | 
					
						
							| 
									
										
										
										
											2024-04-30 16:55:15 +08:00
										 |  |  | EmojiData? kCachedEmojiData; | 
					
						
							| 
									
										
										
										
											2023-11-02 15:24:17 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | class FlowyEmojiPicker extends StatefulWidget { | 
					
						
							|  |  |  |   const FlowyEmojiPicker({ | 
					
						
							|  |  |  |     super.key, | 
					
						
							|  |  |  |     required this.onEmojiSelected, | 
					
						
							| 
									
										
										
										
											2023-11-17 13:51:26 +08:00
										 |  |  |     this.emojiPerLine = 9, | 
					
						
							| 
									
										
										
										
											2023-11-02 15:24:17 +08:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   final EmojiSelectedCallback onEmojiSelected; | 
					
						
							| 
									
										
										
										
											2023-11-17 13:51:26 +08:00
										 |  |  |   final int emojiPerLine; | 
					
						
							| 
									
										
										
										
											2023-11-02 15:24:17 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   State<FlowyEmojiPicker> createState() => _FlowyEmojiPickerState(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _FlowyEmojiPickerState extends State<FlowyEmojiPicker> { | 
					
						
							|  |  |  |   EmojiData? emojiData; | 
					
						
							| 
									
										
										
										
											2023-11-22 10:49:22 +08:00
										 |  |  |   List<String>? fallbackFontFamily; | 
					
						
							| 
									
										
										
										
											2023-11-02 15:24:17 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							|  |  |  |     super.initState(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // load the emoji data from cache if it's available
 | 
					
						
							| 
									
										
										
										
											2024-04-30 16:55:15 +08:00
										 |  |  |     if (kCachedEmojiData != null) { | 
					
						
							|  |  |  |       emojiData = kCachedEmojiData; | 
					
						
							| 
									
										
										
										
											2023-11-02 15:24:17 +08:00
										 |  |  |     } else { | 
					
						
							|  |  |  |       EmojiData.builtIn().then( | 
					
						
							|  |  |  |         (value) { | 
					
						
							| 
									
										
										
										
											2024-04-30 16:55:15 +08:00
										 |  |  |           kCachedEmojiData = value; | 
					
						
							| 
									
										
										
										
											2023-11-02 15:24:17 +08:00
										 |  |  |           setState(() { | 
					
						
							|  |  |  |             emojiData = value; | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-11-22 10:49:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (Platform.isAndroid || Platform.isLinux) { | 
					
						
							|  |  |  |       final notoColorEmoji = GoogleFonts.notoColorEmoji().fontFamily; | 
					
						
							|  |  |  |       if (notoColorEmoji != null) { | 
					
						
							|  |  |  |         fallbackFontFamily = [notoColorEmoji]; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-11-02 15:24:17 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     if (emojiData == null) { | 
					
						
							|  |  |  |       return const Center( | 
					
						
							|  |  |  |         child: SizedBox.square( | 
					
						
							|  |  |  |           dimension: 24.0, | 
					
						
							|  |  |  |           child: CircularProgressIndicator( | 
					
						
							|  |  |  |             strokeWidth: 2.0, | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return EmojiPicker( | 
					
						
							|  |  |  |       emojiData: emojiData!, | 
					
						
							|  |  |  |       configuration: EmojiPickerConfiguration( | 
					
						
							|  |  |  |         showTabs: false, | 
					
						
							|  |  |  |         defaultSkinTone: lastSelectedEmojiSkinTone ?? EmojiSkinTone.none, | 
					
						
							| 
									
										
										
										
											2023-11-17 13:51:26 +08:00
										 |  |  |         perLine: widget.emojiPerLine, | 
					
						
							| 
									
										
										
										
											2023-11-02 15:24:17 +08:00
										 |  |  |       ), | 
					
						
							|  |  |  |       onEmojiSelected: widget.onEmojiSelected, | 
					
						
							|  |  |  |       headerBuilder: (context, category) { | 
					
						
							|  |  |  |         return FlowyEmojiHeader( | 
					
						
							|  |  |  |           category: category, | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       itemBuilder: (context, emojiId, emoji, callback) { | 
					
						
							|  |  |  |         return FlowyIconButton( | 
					
						
							|  |  |  |           iconPadding: const EdgeInsets.all(2.0), | 
					
						
							|  |  |  |           icon: FlowyText( | 
					
						
							|  |  |  |             emoji, | 
					
						
							|  |  |  |             fontSize: 28.0, | 
					
						
							| 
									
										
										
										
											2023-11-22 10:49:22 +08:00
										 |  |  |             fallbackFontFamily: fallbackFontFamily, | 
					
						
							| 
									
										
										
										
											2023-11-02 15:24:17 +08:00
										 |  |  |           ), | 
					
						
							|  |  |  |           onPressed: () => callback(emojiId, emoji), | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       searchBarBuilder: (context, keyword, skinTone) { | 
					
						
							|  |  |  |         return FlowyEmojiSearchBar( | 
					
						
							|  |  |  |           emojiData: emojiData!, | 
					
						
							|  |  |  |           onKeywordChanged: (value) { | 
					
						
							|  |  |  |             keyword.value = value; | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           onSkinToneChanged: (value) { | 
					
						
							|  |  |  |             skinTone.value = value; | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           onRandomEmojiSelected: widget.onEmojiSelected, | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |