go back to fluffychat new space/group pages, delete add to space toggles widget
parent
162019221a
commit
89a61c03ed
@ -1,268 +0,0 @@
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart';
|
||||
import 'package:fluffychat/pangea/utils/error_handler.dart';
|
||||
import 'package:fluffychat/utils/localized_exception_extension.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:matrix/matrix.dart';
|
||||
|
||||
import '../../../widgets/matrix.dart';
|
||||
import '../../utils/firebase_analytics.dart';
|
||||
|
||||
//PTODO - auto invite students when you add a space and delete the add_class_and_invite.dart file
|
||||
class AddToSpaceToggles extends StatefulWidget {
|
||||
final String? roomId;
|
||||
final bool startOpen;
|
||||
final String? activeSpaceId;
|
||||
final bool spaceMode;
|
||||
|
||||
const AddToSpaceToggles({
|
||||
super.key,
|
||||
this.roomId,
|
||||
this.startOpen = false,
|
||||
this.activeSpaceId,
|
||||
this.spaceMode = false,
|
||||
});
|
||||
|
||||
@override
|
||||
AddToSpaceState createState() => AddToSpaceState();
|
||||
}
|
||||
|
||||
class AddToSpaceState extends State<AddToSpaceToggles> {
|
||||
late Room? room;
|
||||
late Room? parent;
|
||||
late List<Room> possibleParents;
|
||||
late bool isOpen;
|
||||
late bool isSuggested;
|
||||
|
||||
AddToSpaceState({Key? key});
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
initialize();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(AddToSpaceToggles oldWidget) {
|
||||
if (oldWidget.roomId != widget.roomId) {
|
||||
initialize();
|
||||
}
|
||||
super.didUpdateWidget(oldWidget);
|
||||
}
|
||||
|
||||
void initialize() {
|
||||
//if roomId is null, it means this widget is being used in the creation flow
|
||||
room = widget.roomId != null
|
||||
? Matrix.of(context).client.getRoomById(widget.roomId!)
|
||||
: null;
|
||||
|
||||
isSuggested = true;
|
||||
room?.isSuggested().then((value) => isSuggested = value);
|
||||
|
||||
possibleParents = Matrix.of(context)
|
||||
.client
|
||||
.rooms
|
||||
.where(
|
||||
(Room r) => r.isSpace && widget.roomId != r.id,
|
||||
)
|
||||
.toList();
|
||||
|
||||
parent = widget.roomId != null
|
||||
? possibleParents.firstWhereOrNull(
|
||||
(r) => r.spaceChildren.any((room) => room.roomId == widget.roomId),
|
||||
)
|
||||
: null;
|
||||
|
||||
//sort possibleParents
|
||||
//if possibleParent in parents, put first
|
||||
//use sort but use any instead of contains because contains uses == and we want to compare by id
|
||||
possibleParents.sort((a, b) {
|
||||
if (parent?.id == a.id) {
|
||||
return -1;
|
||||
} else if (parent?.id == b.id) {
|
||||
return 1;
|
||||
} else {
|
||||
return a.name.compareTo(b.name);
|
||||
}
|
||||
});
|
||||
|
||||
isOpen = widget.startOpen;
|
||||
|
||||
if (widget.activeSpaceId != null) {
|
||||
final activeSpace =
|
||||
Matrix.of(context).client.getRoomById(widget.activeSpaceId!);
|
||||
if (activeSpace == null) {
|
||||
ErrorHandler.logError(
|
||||
e: Exception('activeSpaceId ${widget.activeSpaceId} not found'),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (activeSpace.canSendEvent(EventTypes.SpaceChild)) {
|
||||
parent = activeSpace;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _addSingleSpace(String roomToAddId, Room newParent) async {
|
||||
GoogleAnalytics.addParent(roomToAddId, newParent.classCode);
|
||||
await newParent.pangeaSetSpaceChild(
|
||||
roomToAddId,
|
||||
suggested: isSuggested,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> addSpaces(String roomToAddId) async {
|
||||
if (parent == null) return;
|
||||
await _addSingleSpace(roomToAddId, parent!);
|
||||
}
|
||||
|
||||
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: () => add
|
||||
? _addSingleSpace(room!.id, possibleParent)
|
||||
: possibleParent.removeSpaceChild(room!.id),
|
||||
onError: (e) {
|
||||
// if error occurs, do not change value of toggle
|
||||
add = !add;
|
||||
return (e as Object?)?.toLocalizedString(context) ??
|
||||
e?.toString() ??
|
||||
L10n.of(context)!.oopsSomethingWentWrong;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
setState(
|
||||
() => add ? parent = possibleParent : parent = null,
|
||||
);
|
||||
}
|
||||
|
||||
Widget getAddToSpaceToggleItem(int index) {
|
||||
final Room possibleParent = possibleParents[index];
|
||||
final bool canAdd = possibleParent.canAddAsParentOf(
|
||||
room,
|
||||
spaceMode: widget.spaceMode,
|
||||
);
|
||||
|
||||
return Opacity(
|
||||
opacity: canAdd ? 1 : 0.5,
|
||||
child: Column(
|
||||
children: [
|
||||
SwitchListTile.adaptive(
|
||||
title: possibleParent.nameAndRoomTypeIcon(),
|
||||
activeColor: AppConfig.activeToggleColor,
|
||||
value: parent?.id == possibleParent.id,
|
||||
onChanged: (bool add) => canAdd
|
||||
? handleAdd(add, possibleParent)
|
||||
: ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(L10n.of(context)!.noPermission),
|
||||
),
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
height: 0.5,
|
||||
color: Theme.of(context).colorScheme.secondary.withAlpha(25),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> setSuggested(bool suggested) async {
|
||||
setState(() => isSuggested = suggested);
|
||||
if (room != null) {
|
||||
await showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () async => await room?.setSuggested(suggested),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
ListTile(
|
||||
title: Text(
|
||||
L10n.of(context)!.addToSpace,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
widget.spaceMode || (room?.isSpace ?? false)
|
||||
? L10n.of(context)!.addSpaceToSpaceDesc
|
||||
: L10n.of(context)!.addChatToSpaceDesc,
|
||||
),
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||
foregroundColor: Theme.of(context).textTheme.bodyLarge!.color,
|
||||
child: const Icon(Icons.workspaces_outlined),
|
||||
),
|
||||
trailing: Icon(
|
||||
isOpen
|
||||
? Icons.keyboard_arrow_down_outlined
|
||||
: Icons.keyboard_arrow_right_outlined,
|
||||
),
|
||||
onTap: () {
|
||||
setState(() => isOpen = !isOpen);
|
||||
},
|
||||
),
|
||||
if (isOpen) ...[
|
||||
const Divider(height: 1),
|
||||
possibleParents.isNotEmpty
|
||||
? Column(
|
||||
children: [
|
||||
SwitchListTile.adaptive(
|
||||
title: Text(
|
||||
widget.spaceMode || (room?.isSpace ?? false)
|
||||
? L10n.of(context)!.suggestToSpace
|
||||
: L10n.of(context)!.suggestToChat,
|
||||
),
|
||||
secondary: Icon(
|
||||
isSuggested
|
||||
? Icons.visibility_outlined
|
||||
: Icons.visibility_off_outlined,
|
||||
),
|
||||
subtitle: Text(
|
||||
widget.spaceMode || (room?.isSpace ?? false)
|
||||
? L10n.of(context)!.suggestToSpaceDesc
|
||||
: L10n.of(context)!.suggestToChatDesc,
|
||||
),
|
||||
activeColor: AppConfig.activeToggleColor,
|
||||
value: isSuggested,
|
||||
onChanged: (bool add) => setSuggested(add),
|
||||
),
|
||||
Divider(
|
||||
height: 0.5,
|
||||
color:
|
||||
Theme.of(context).colorScheme.secondary.withAlpha(25),
|
||||
),
|
||||
...possibleParents.mapIndexed(
|
||||
(index, _) => getAddToSpaceToggleItem(index),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Text(
|
||||
L10n.of(context)!.inNoSpaces,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:file_selector/file_selector.dart';
|
||||
import 'package:fluffychat/utils/platform_infos.dart';
|
||||
import 'package:fluffychat/widgets/app_lock.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
Future<List<XFile>> selectFiles(
|
||||
BuildContext context, {
|
||||
String? title,
|
||||
FileSelectorType type = FileSelectorType.any,
|
||||
bool allowMultiple = false,
|
||||
}) async {
|
||||
if (!PlatformInfos.isLinux) {
|
||||
final result = await AppLock.of(context).pauseWhile(
|
||||
FilePicker.platform.pickFiles(
|
||||
compressionQuality: 0,
|
||||
allowMultiple: allowMultiple,
|
||||
type: type.filePickerType,
|
||||
allowedExtensions: type.extensions,
|
||||
),
|
||||
);
|
||||
return result?.xFiles ?? [];
|
||||
}
|
||||
|
||||
if (allowMultiple) {
|
||||
return await AppLock.of(context).pauseWhile(
|
||||
openFiles(
|
||||
confirmButtonText: title,
|
||||
acceptedTypeGroups: type.groups,
|
||||
),
|
||||
);
|
||||
}
|
||||
final file = await AppLock.of(context).pauseWhile(
|
||||
openFile(
|
||||
confirmButtonText: title,
|
||||
acceptedTypeGroups: type.groups,
|
||||
),
|
||||
);
|
||||
if (file == null) return [];
|
||||
return [file];
|
||||
}
|
||||
|
||||
enum FileSelectorType {
|
||||
any([], FileType.any, null),
|
||||
images(
|
||||
[
|
||||
XTypeGroup(
|
||||
label: 'JPG',
|
||||
extensions: <String>['jpg', 'JPG', 'jpeg', 'JPEG'],
|
||||
),
|
||||
XTypeGroup(
|
||||
label: 'PNGs',
|
||||
extensions: <String>['png', 'PNG'],
|
||||
),
|
||||
XTypeGroup(
|
||||
label: 'WEBP',
|
||||
extensions: <String>['WebP', 'WEBP'],
|
||||
),
|
||||
],
|
||||
FileType.image,
|
||||
null,
|
||||
),
|
||||
zip(
|
||||
[
|
||||
XTypeGroup(
|
||||
label: 'ZIP',
|
||||
extensions: <String>['zip', 'ZIP'],
|
||||
),
|
||||
],
|
||||
FileType.custom,
|
||||
['zip', 'ZIP'],
|
||||
);
|
||||
|
||||
const FileSelectorType(this.groups, this.filePickerType, this.extensions);
|
||||
final List<XTypeGroup> groups;
|
||||
final FileType filePickerType;
|
||||
final List<String>? extensions;
|
||||
}
|
||||
Loading…
Reference in New Issue