import "dart:convert"; import "package:collection/collection.dart"; import "package:fast_immutable_collections/fast_immutable_collections.dart"; import "package:flutter/foundation.dart"; import "package:flutter/material.dart"; import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:http/http.dart"; import "package:nexus/models/gemoji.dart"; class EmoteSection { final String category; final String label; final IconData icon; final List items; final bool isRecent; const EmoteSection({ required this.category, required this.label, required this.icon, required this.items, this.isRecent = false, }); } class EmoteItem { final String id; final String display; final List keywords; final int useCounter; final Image? customImage; const EmoteItem({ required this.id, required this.display, required this.keywords, required this.useCounter, this.customImage, }); } class EmojiController extends AsyncNotifier> { @override Future> build() async { final response = await get( .https("github.com", "github/gemoji/raw/refs/heads/master/db/emoji.json"), ); if (response.statusCode != 200) { throw Exception("Failed to load emoji data"); } return compute(parseEmojiJson, response.body); } static IList parseEmojiJson(String body) { final data = json.decode(body) as List; final allEntries = data .cast>() .map(Gemoji.fromJson) .toIList(); final groupedByCategory = groupBy(allEntries, (g) => g.category); final result = groupedByCategory.entries.fold>( .new(), (resultList, entry) => resultList.add( EmoteSection( category: entry.key, label: entry.key, icon: getIconForCategory(entry.key), items: entry.value .map( (gemoji) => EmoteItem( id: gemoji.emoji, display: gemoji.emoji, keywords: [ ...gemoji.tags, ...gemoji.aliases, ...gemoji.description.split(" "), ], useCounter: 0, ), ) .toList(), isRecent: false, ), ), ); return result; } static final provider = AsyncNotifierProvider>( EmojiController.new, ); static IconData getIconForCategory(String category) { switch (category.toLowerCase()) { case "smileys & emotion": return Icons.sentiment_very_satisfied; case "people & body": return Icons.face; case "food & drink": return Icons.restaurant; case "travel & places": return Icons.flag; case "activities": return Icons.sports_soccer; case "objects": return Icons.lightbulb; case "symbols": return Icons.circle; case "flags": return Icons.flag; default: return Icons.emoji_emotions_outlined; } } }