179 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Dart
		
	
	
	
			
		
		
	
	
			179 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Dart
		
	
	
	
| import 'package:flutter/material.dart';
 | |
| 
 | |
| import 'package:cross_file/cross_file.dart';
 | |
| import 'package:flutter_gen/gen_l10n/l10n.dart';
 | |
| import 'package:go_router/go_router.dart';
 | |
| import 'package:matrix/matrix.dart';
 | |
| 
 | |
| import 'package:fluffychat/config/app_config.dart';
 | |
| import 'package:fluffychat/config/themes.dart';
 | |
| import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
 | |
| import 'package:fluffychat/widgets/avatar.dart';
 | |
| import 'package:fluffychat/widgets/matrix.dart';
 | |
| 
 | |
| abstract class ShareItem {}
 | |
| 
 | |
| class TextShareItem extends ShareItem {
 | |
|   final String value;
 | |
|   TextShareItem(this.value);
 | |
| }
 | |
| 
 | |
| class ContentShareItem extends ShareItem {
 | |
|   final Map<String, Object?> value;
 | |
|   ContentShareItem(this.value);
 | |
| }
 | |
| 
 | |
| class FileShareItem extends ShareItem {
 | |
|   final XFile value;
 | |
|   FileShareItem(this.value);
 | |
| }
 | |
| 
 | |
| class ShareScaffoldDialog extends StatefulWidget {
 | |
|   final List<ShareItem> items;
 | |
| 
 | |
|   const ShareScaffoldDialog({required this.items, super.key});
 | |
| 
 | |
|   @override
 | |
|   State<ShareScaffoldDialog> createState() => _ShareScaffoldDialogState();
 | |
| }
 | |
| 
 | |
| class _ShareScaffoldDialogState extends State<ShareScaffoldDialog> {
 | |
|   final TextEditingController _filterController = TextEditingController();
 | |
| 
 | |
|   String? selectedRoomId;
 | |
| 
 | |
|   void _toggleRoom(String roomId) {
 | |
|     setState(() {
 | |
|       selectedRoomId = roomId;
 | |
|     });
 | |
|   }
 | |
| 
 | |
|   void _forwardAction() async {
 | |
|     final roomId = selectedRoomId;
 | |
|     if (roomId == null) {
 | |
|       throw Exception(
 | |
|         'Started forward action before room was selected. This should never happen.',
 | |
|       );
 | |
|     }
 | |
|     while (context.canPop()) {
 | |
|       context.pop();
 | |
|     }
 | |
|     context.go('/rooms/$roomId', extra: widget.items);
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   Widget build(BuildContext context) {
 | |
|     final theme = Theme.of(context);
 | |
|     final rooms = Matrix.of(context)
 | |
|         .client
 | |
|         .rooms
 | |
|         .where(
 | |
|           (room) =>
 | |
|               room.canSendDefaultMessages &&
 | |
|               !room.isSpace &&
 | |
|               room.membership == Membership.join,
 | |
|         )
 | |
|         .toList();
 | |
|     final filter = _filterController.text.trim().toLowerCase();
 | |
|     return Scaffold(
 | |
|       appBar: AppBar(
 | |
|         leading: Center(child: CloseButton(onPressed: context.pop)),
 | |
|         title: Text(L10n.of(context).share),
 | |
|       ),
 | |
|       body: CustomScrollView(
 | |
|         slivers: [
 | |
|           SliverAppBar(
 | |
|             floating: true,
 | |
|             toolbarHeight: 72,
 | |
|             scrolledUnderElevation: 0,
 | |
|             backgroundColor: Colors.transparent,
 | |
|             automaticallyImplyLeading: false,
 | |
|             title: TextField(
 | |
|               controller: _filterController,
 | |
|               onChanged: (_) => setState(() {}),
 | |
|               textInputAction: TextInputAction.search,
 | |
|               decoration: InputDecoration(
 | |
|                 filled: true,
 | |
|                 fillColor: theme.colorScheme.secondaryContainer,
 | |
|                 border: OutlineInputBorder(
 | |
|                   borderSide: BorderSide.none,
 | |
|                   borderRadius: BorderRadius.circular(99),
 | |
|                 ),
 | |
|                 contentPadding: EdgeInsets.zero,
 | |
|                 hintText: L10n.of(context).search,
 | |
|                 hintStyle: TextStyle(
 | |
|                   color: theme.colorScheme.onPrimaryContainer,
 | |
|                   fontWeight: FontWeight.normal,
 | |
|                 ),
 | |
|                 floatingLabelBehavior: FloatingLabelBehavior.never,
 | |
|                 prefixIcon: IconButton(
 | |
|                   onPressed: () {},
 | |
|                   icon: Icon(
 | |
|                     Icons.search_outlined,
 | |
|                     color: theme.colorScheme.onPrimaryContainer,
 | |
|                   ),
 | |
|                 ),
 | |
|               ),
 | |
|             ),
 | |
|           ),
 | |
|           SliverList.builder(
 | |
|             itemCount: rooms.length,
 | |
|             itemBuilder: (context, i) {
 | |
|               final room = rooms[i];
 | |
|               final displayname = room.getLocalizedDisplayname(
 | |
|                 MatrixLocals(L10n.of(context)),
 | |
|               );
 | |
|               final value = selectedRoomId == room.id;
 | |
|               final filterOut = !displayname.toLowerCase().contains(filter);
 | |
|               if (!value && filterOut) {
 | |
|                 return const SizedBox.shrink();
 | |
|               }
 | |
|               return Padding(
 | |
|                 padding: const EdgeInsets.symmetric(horizontal: 16.0),
 | |
|                 child: Opacity(
 | |
|                   opacity: filterOut ? 0.5 : 1,
 | |
|                   child: CheckboxListTile.adaptive(
 | |
|                     checkboxShape: RoundedRectangleBorder(
 | |
|                       borderRadius: BorderRadius.circular(90),
 | |
|                     ),
 | |
|                     controlAffinity: ListTileControlAffinity.trailing,
 | |
|                     shape: RoundedRectangleBorder(
 | |
|                       borderRadius:
 | |
|                           BorderRadius.circular(AppConfig.borderRadius),
 | |
|                     ),
 | |
|                     secondary: Avatar(
 | |
|                       mxContent: room.avatar,
 | |
|                       name: displayname,
 | |
|                       size: Avatar.defaultSize * 0.75,
 | |
|                     ),
 | |
|                     title: Text(displayname),
 | |
|                     value: selectedRoomId == room.id,
 | |
|                     onChanged: (_) => _toggleRoom(room.id),
 | |
|                   ),
 | |
|                 ),
 | |
|               );
 | |
|             },
 | |
|           ),
 | |
|         ],
 | |
|       ),
 | |
|       bottomNavigationBar: AnimatedSize(
 | |
|         duration: FluffyThemes.animationDuration,
 | |
|         curve: FluffyThemes.animationCurve,
 | |
|         child: selectedRoomId == null
 | |
|             ? const SizedBox.shrink()
 | |
|             : Material(
 | |
|                 elevation: 8,
 | |
|                 shadowColor: theme.appBarTheme.shadowColor,
 | |
|                 child: Padding(
 | |
|                   padding: const EdgeInsets.all(16.0),
 | |
|                   child: ElevatedButton(
 | |
|                     onPressed: _forwardAction,
 | |
|                     child: Text(L10n.of(context).forward),
 | |
|                   ),
 | |
|                 ),
 | |
|               ),
 | |
|       ),
 | |
|     );
 | |
|   }
 | |
| }
 |