import 'dart:async'; import 'package:flutter/material.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:matrix/matrix.dart'; import 'package:vrouter/vrouter.dart'; import 'package:fluffychat/pages/invitation_selection/invitation_selection_view.dart'; import 'package:fluffychat/widgets/matrix.dart'; import '../../utils/localized_exception_extension.dart'; class InvitationSelection extends StatefulWidget { const InvitationSelection({Key? key}) : super(key: key); @override InvitationSelectionController createState() => InvitationSelectionController(); } class InvitationSelectionController extends State { TextEditingController controller = TextEditingController(); late String currentSearchTerm; bool loading = false; List foundProfiles = []; Timer? coolDown; String? get roomId => VRouter.of(context).pathParameters['roomid']; Future> getContacts(BuildContext context) async { final client = Matrix.of(context).client; final room = client.getRoomById(roomId!)!; final participants = await room.requestParticipants(); participants.removeWhere( (u) => ![Membership.join, Membership.invite].contains(u.membership), ); final participantsIds = participants.map((p) => p.stateKey).toList(); final contacts = client.rooms .where((r) => r.isDirectChat) .map((r) => r.unsafeGetUserFromMemoryOrFallback(r.directChatMatrixID!)) .toList() ..removeWhere((u) => participantsIds.contains(u.stateKey)); contacts.sort( (a, b) => a.calcDisplayname().toLowerCase().compareTo( b.calcDisplayname().toLowerCase(), ), ); return contacts; } void inviteAction(BuildContext context, String id) async { final room = Matrix.of(context).client.getRoomById(roomId!)!; if (OkCancelResult.ok != await showOkCancelAlertDialog( context: context, title: L10n.of(context)!.inviteContactToGroup(room.displayname), okLabel: L10n.of(context)!.yes, cancelLabel: L10n.of(context)!.cancel, )) { return; } final success = await showFutureLoadingDialog( context: context, future: () => room.invite(id), ); if (success.error == null) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text(L10n.of(context)!.contactHasBeenInvitedToTheGroup))); } } void searchUserWithCoolDown(String text) async { coolDown?.cancel(); coolDown = Timer( const Duration(seconds: 1), () => searchUser(context, text), ); } void searchUser(BuildContext context, String text) async { coolDown?.cancel(); if (text.isEmpty) { setState(() => foundProfiles = []); } currentSearchTerm = text; if (currentSearchTerm.isEmpty) return; if (loading) return; setState(() => loading = true); final matrix = Matrix.of(context); SearchUserDirectoryResponse response; try { response = await matrix.client.searchUserDirectory(text, limit: 10); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text((e).toLocalizedString(context)))); return; } finally { setState(() => loading = false); } setState(() { foundProfiles = List.from(response.results); if (text.isValidMatrixId && foundProfiles.indexWhere((profile) => text == profile.userId) == -1) { setState(() => foundProfiles = [ Profile.fromJson({'user_id': text}), ]); } final participants = Matrix.of(context) .client .getRoomById(roomId!)! .getParticipants() .where((user) => [Membership.join, Membership.invite].contains(user.membership)) .toList(); foundProfiles.removeWhere((profile) => participants.indexWhere((u) => u.id == profile.userId) != -1); }); } @override Widget build(BuildContext context) => InvitationSelectionView(this); }