import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:matrix/matrix.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/utils/url_launcher.dart'; import 'package:fluffychat/widgets/mxc_image.dart'; import '../../widgets/avatar.dart'; class StickerPickerDialog extends StatefulWidget { final Room room; final void Function(ImagePackImageContent) onSelected; const StickerPickerDialog({ required this.onSelected, required this.room, super.key, }); @override StickerPickerDialogState createState() => StickerPickerDialogState(); } class StickerPickerDialogState extends State { String? searchFilter; @override Widget build(BuildContext context) { final stickerPacks = widget.room.getImagePacks(ImagePackUsage.sticker); final packSlugs = stickerPacks.keys.toList(); // ignore: prefer_function_declarations_over_variables final packBuilder = (BuildContext context, int packIndex) { final pack = stickerPacks[packSlugs[packIndex]]!; final filteredImagePackImageEntried = pack.images.entries.toList(); if (searchFilter?.isNotEmpty ?? false) { filteredImagePackImageEntried.removeWhere( (e) => !(e.key.toLowerCase().contains(searchFilter!.toLowerCase()) || (e.value.body ?.toLowerCase() .contains(searchFilter!.toLowerCase()) ?? false)), ); } final imageKeys = filteredImagePackImageEntried.map((e) => e.key).toList(); if (imageKeys.isEmpty) { return const SizedBox.shrink(); } final packName = pack.pack.displayName ?? packSlugs[packIndex]; return Column( children: [ if (packIndex != 0) const SizedBox(height: 20), if (packName != 'user') ListTile( leading: Avatar( mxContent: pack.pack.avatarUrl, name: packName, client: widget.room.client, ), title: Text(packName), ), const SizedBox(height: 6), GridView.builder( itemCount: imageKeys.length, gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 128, ), shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemBuilder: (BuildContext context, int imageIndex) { final image = pack.images[imageKeys[imageIndex]]!; return InkWell( radius: AppConfig.borderRadius, key: ValueKey(image.url.toString()), onTap: () { // copy the image final imageCopy = ImagePackImageContent.fromJson(image.toJson().copy()); // set the body, if it doesn't exist, to the key imageCopy.body ??= imageKeys[imageIndex]; widget.onSelected(imageCopy); }, child: AbsorbPointer( absorbing: true, child: MxcImage( uri: image.url, fit: BoxFit.contain, width: 128, height: 128, animated: true, ), ), ); }, ), ], ); }; return Scaffold( backgroundColor: Theme.of(context).colorScheme.onInverseSurface, body: SizedBox( width: double.maxFinite, child: CustomScrollView( slivers: [ SliverAppBar( floating: true, pinned: true, automaticallyImplyLeading: false, backgroundColor: Colors.transparent, title: SizedBox( height: 42, child: TextField( autofocus: false, decoration: InputDecoration( hintText: L10n.of(context)!.search, prefixIcon: const Icon(Icons.search_outlined), contentPadding: EdgeInsets.zero, ), onChanged: (s) => setState(() => searchFilter = s), ), ), ), if (packSlugs.isEmpty) SliverFillRemaining( child: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Text(L10n.of(context)!.noEmotesFound), const SizedBox(height: 12), OutlinedButton.icon( onPressed: () => UrlLauncher( context, 'https://matrix.to/#/#fluffychat-stickers:janian.de', ).launchUrl(), icon: const Icon(Icons.explore_outlined), label: Text(L10n.of(context)!.discover), ), ], ), ), ) else SliverList( delegate: SliverChildBuilderDelegate( packBuilder, childCount: packSlugs.length, ), ), ], ), ), ); } }