You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
fluffychat/lib/pangea/widgets/class/add_class_and_invite.dart

299 lines
9.3 KiB
Dart

import 'dart:developer';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:go_router/go_router.dart';
import 'package:matrix/matrix.dart';
import '../../../widgets/matrix.dart';
import '../../utils/error_handler.dart';
import '../../utils/firebase_analytics.dart';
enum AddToClassMode { exchange, chat }
class AddToClassAndInviteToggles extends StatefulWidget {
final String? roomId;
final bool startOpen;
final Function? setParentState;
final AddToClassMode mode;
const AddToClassAndInviteToggles({
super.key,
this.roomId,
this.startOpen = false,
this.setParentState,
required this.mode,
});
@override
AddToClassAndInviteState createState() => AddToClassAndInviteState();
}
class AddToClassAndInviteState extends State<AddToClassAndInviteToggles> {
late Room? room;
late List<Room> parents;
late List<Room> possibleParents;
late bool isOpen;
AddToClassAndInviteState({Key? key});
@override
void initState() {
room = widget.roomId != null
? Matrix.of(context).client.getRoomById(widget.roomId!)
: null;
if (room != null && room!.isPangeaClass) {
debugger(when: kDebugMode);
ErrorHandler.logError(
m: "should not be able to add class to space, not yet at least",
);
context.go('/rooms');
}
possibleParents = Matrix.of(context)
.client
.rooms
.where(
widget.mode == AddToClassMode.exchange
? (Room r) => r.isPangeaClass && widget.roomId != r.id
: (Room r) =>
(r.isPangeaClass || r.isExchange) && widget.roomId != r.id,
)
.toList();
parents = widget.roomId != null
? possibleParents
.where(
(r) =>
r.spaceChildren.any((room) => room.roomId == widget.roomId),
)
.toList()
: [];
isOpen = widget.startOpen;
super.initState();
}
Future<void> addParents(String roomToAddId) async {
final List<Future<void>> addFutures = [];
for (final Room newParent in parents) {
addFutures.add(_addSingleParent(roomToAddId, newParent));
}
await addFutures.wait;
}
Future<void> _addSingleParent(String roomToAddId, Room newParent) async {
GoogleAnalytics.addParent(roomToAddId, newParent.classCode);
final List<List<User>> existingMembers = await Future.wait([
room?.requestParticipants() ?? Future.value([]),
newParent.requestParticipants(),
]);
final List<User> roomMembers = existingMembers[0];
final List<User> spaceMembers = existingMembers[1];
final List<Future<void>> inviteFutures = [
newParent.setSpaceChild(roomToAddId, suggested: true),
];
for (final spaceMember
in spaceMembers.where((element) => element.id != room?.client.userID)) {
if (!roomMembers.any(
(m) => m.id == spaceMember.id && m.membership == Membership.join,
)) {
inviteFutures.add(_inviteSpaceMember(spaceMember));
} else {
debugPrint('User ${spaceMember.id} is already in the room');
}
}
await Future.wait(inviteFutures);
return;
}
//function for kicking single student and haandling error
Future<void> _kickSpaceMember(User spaceMember) async {
try {
await room?.kick(spaceMember.id);
debugPrint('Kicked ${spaceMember.id}');
} catch (e) {
debugger(when: kDebugMode);
ErrorHandler.logError(e: e);
}
}
//function for adding single student and haandling error
Future<void> _inviteSpaceMember(User spaceMember) async {
try {
await room?.invite(spaceMember.id);
debugPrint('added ${spaceMember.id}');
} catch (e) {
debugger(when: kDebugMode);
ErrorHandler.logError(e: e);
}
}
//remove single class
Future<void> _removeSingleSpaceFromParents(
String roomToRemoveId,
Room spaceToRemove,
) async {
GoogleAnalytics.removeChatFromClass(
roomToRemoveId,
spaceToRemove.classCode,
);
if (room == null) {
ErrorHandler.logError(m: 'Room is null in kickSpaceMembers');
debugger(when: kDebugMode);
return;
}
final List<List<User>> roomsMembers = await Future.wait([
room?.requestParticipants() ?? Future.value([]),
spaceToRemove.requestParticipants(),
]);
final List<User> toKick = roomsMembers[1]
.where(
(element) =>
element.id != room?.client.userID &&
roomsMembers[0].any((m) => m.id == element.id),
)
.toList();
final List<Future<void>> kickFutures = [
spaceToRemove.removeSpaceChild(roomToRemoveId),
];
for (final spaceMember in toKick) {
kickFutures.add(_kickSpaceMember(spaceMember));
}
await Future.wait(kickFutures);
// if (widget.setParentState != null) {
// widget.setParentState!();
// }
await room?.requestParticipants();
if (room != null) {
GoogleAnalytics.kickClassFromExchange(room!.id, spaceToRemove.id);
}
return;
}
// ignore: curly_braces_in_flow_control_structures
Future<void> _handleAdd(bool add, Room possibleParent) async {
//in this case, the room has already been made so we handle adding as it happens
if (room != null) {
await showFutureLoadingDialog(
context: context,
future: () async {
await (add
? _addSingleParent(room!.id, possibleParent)
: _removeSingleSpaceFromParents(room!.id, possibleParent));
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
add
? L10n.of(context)!.youAddedToSpace(
room!.name,
possibleParent.name,
)
: L10n.of(context)!.youRemovedFromSpace(
room!.name,
possibleParent.name,
),
),
),
);
},
);
}
setState(
() => add
? parents.add(possibleParent)
: parents.removeWhere((r) => r.id == possibleParent.id),
);
}
@override
Widget build(BuildContext context) {
return Column(
children: [
if (!widget.startOpen)
ListTile(
enableFeedback: !widget.startOpen,
title: Text(
widget.mode == AddToClassMode.exchange
? L10n.of(context)!.addToClass
: L10n.of(context)!.addToClassOrExchange,
style: TextStyle(
color: Theme.of(context).colorScheme.secondary,
fontWeight: FontWeight.bold,
),
),
leading: CircleAvatar(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
foregroundColor: Theme.of(context).textTheme.bodyLarge!.color,
child: const Icon(
Icons.workspaces_outline,
),
),
trailing: !widget.startOpen
? Icon(
isOpen
? Icons.keyboard_arrow_down_outlined
: Icons.keyboard_arrow_right_outlined,
)
: null,
onTap: () => setState(() => isOpen = !isOpen),
),
if (isOpen)
Padding(
padding: const EdgeInsets.fromLTRB(16.0, 0, 16.0, 0),
child: Column(
children: [
if (possibleParents.isEmpty)
ListTile(
title: Text(L10n.of(context)!.noEligibleSpaces),
),
ListView.builder(
shrinkWrap: true,
itemCount: possibleParents.length,
itemBuilder: (BuildContext context, int i) {
final bool canIAddSpaceChildren =
possibleParents[i].canIAddSpaceChild(room) &&
(room?.canIAddSpaceParents ?? true);
return Column(
children: [
Opacity(
opacity: canIAddSpaceChildren ? 1 : 0.5,
child: SwitchListTile.adaptive(
title: possibleParents[i].nameAndRoomTypeIcon(),
activeColor: AppConfig.activeToggleColor,
value: parents
.any((r) => r.id == possibleParents[i].id),
onChanged: (bool add) => canIAddSpaceChildren
? _handleAdd(add, possibleParents[i])
: ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text(L10n.of(context)!.noPermission),
),
),
),
),
],
);
},
),
],
),
),
],
);
}
}