From 89a61c03eda337a7da119b347df203a015565749 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Mon, 21 Oct 2024 17:06:09 -0400 Subject: [PATCH] go back to fluffychat new space/group pages, delete add to space toggles widget --- lib/config/routes.dart | 6 +- lib/pages/chat_details/chat_details.dart | 5 +- lib/pages/chat_details/chat_details_view.dart | 8 - lib/pages/new_group/new_group.dart | 157 +--------- lib/pages/new_group/new_group_view.dart | 108 +++---- lib/pages/new_space/new_space.dart | 278 ++++++------------ lib/pages/new_space/new_space_view.dart | 83 ++---- .../widgets/class/add_space_toggles.dart | 268 ----------------- lib/utils/file_selector.dart | 78 +++++ pubspec.lock | 36 ++- pubspec.yaml | 1 + 11 files changed, 271 insertions(+), 757 deletions(-) delete mode 100644 lib/pangea/widgets/class/add_space_toggles.dart create mode 100644 lib/utils/file_selector.dart diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 0ee135e7d..515b25fd9 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -233,11 +233,7 @@ abstract class AppRoutes { pageBuilder: (context, state) => defaultPageBuilder( context, state, - NewGroup( - // #Pangea - spaceId: state.uri.queryParameters['spaceId'], - // Pangea# - ), + const NewGroup(), ), redirect: loggedOutRedirect, // #Pangea diff --git a/lib/pages/chat_details/chat_details.dart b/lib/pages/chat_details/chat_details.dart index 050a1b272..a94430da1 100644 --- a/lib/pages/chat_details/chat_details.dart +++ b/lib/pages/chat_details/chat_details.dart @@ -5,7 +5,6 @@ import 'package:fluffychat/pages/chat_details/chat_details_view.dart'; import 'package:fluffychat/pages/settings/settings.dart'; import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_description_button.dart'; import 'package:fluffychat/pangea/utils/set_class_name.dart'; -import 'package:fluffychat/pangea/widgets/class/add_space_toggles.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/widgets/app_lock.dart'; import 'package:fluffychat/widgets/matrix.dart'; @@ -41,9 +40,7 @@ class ChatDetailsController extends State { String? get roomId => widget.roomId; // #Pangea - final GlobalKey addToSpaceKey = GlobalKey(); - final GlobalKey - addConversationBotKey = + final GlobalKey addConversationBotKey = GlobalKey(); bool displayAddStudentOptions = false; diff --git a/lib/pages/chat_details/chat_details_view.dart b/lib/pages/chat_details/chat_details_view.dart index edf277e86..90f2a8927 100644 --- a/lib/pages/chat_details/chat_details_view.dart +++ b/lib/pages/chat_details/chat_details_view.dart @@ -10,7 +10,6 @@ import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_inv import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_name_button.dart'; import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/room_capacity_button.dart'; import 'package:fluffychat/pangea/utils/lock_room.dart'; -import 'package:fluffychat/pangea/widgets/class/add_space_toggles.dart'; import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings.dart'; import 'package:fluffychat/utils/fluffy_share.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; @@ -395,13 +394,6 @@ class ChatDetailsView extends StatelessWidget { room: room, ), const Divider(height: 1), - if (!room.isDirectChat && room.isRoomAdmin) - AddToSpaceToggles( - roomId: room.id, - key: controller.addToSpaceKey, - startOpen: false, - ), - const Divider(height: 1), ListTile( title: Text( L10n.of(context)!.leave, diff --git a/lib/pages/new_group/new_group.dart b/lib/pages/new_group/new_group.dart index 5d6a17012..df5f14aa0 100644 --- a/lib/pages/new_group/new_group.dart +++ b/lib/pages/new_group/new_group.dart @@ -1,33 +1,14 @@ import 'dart:typed_data'; -import 'package:file_picker/file_picker.dart'; import 'package:fluffychat/pages/new_group/new_group_view.dart'; -import 'package:fluffychat/pangea/constants/bot_mode.dart'; -import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; -import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart'; -import 'package:fluffychat/pangea/models/chat_topic_model.dart'; -import 'package:fluffychat/pangea/models/lemma.dart'; -import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/room_capacity_button.dart'; -import 'package:fluffychat/pangea/utils/bot_name.dart'; -import 'package:fluffychat/pangea/utils/class_chat_power_levels.dart'; -import 'package:fluffychat/pangea/utils/firebase_analytics.dart'; -import 'package:fluffychat/pangea/widgets/class/add_space_toggles.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings.dart'; +import 'package:fluffychat/utils/file_selector.dart'; import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:go_router/go_router.dart'; import 'package:matrix/matrix.dart' as sdk; class NewGroup extends StatefulWidget { - // #Pangea - final String? spaceId; - - const NewGroup({ - super.key, - this.spaceId, - }); - // Pangea# + const NewGroup({super.key}); @override NewGroupController createState() => NewGroupController(); @@ -47,50 +28,25 @@ class NewGroupController extends State { bool loading = false; - // #Pangea - PangeaController pangeaController = MatrixState.pangeaController; - final GlobalKey addToSpaceKey = GlobalKey(); - final GlobalKey addConversationBotKey = - GlobalKey(); - final GlobalKey addCapacityKey = - GlobalKey(); - - ChatTopic chatTopic = ChatTopic.empty; - - void setVocab(List vocab) => setState(() => chatTopic.vocab = vocab); - - String? get activeSpaceId => - GoRouterState.of(context).uri.queryParameters['spaceId']; - // Pangea# - void setPublicGroup(bool b) => setState(() => publicGroup = b); void setGroupCanBeFound(bool b) => setState(() => groupCanBeFound = b); void selectPhoto() async { - final photo = await FilePicker.platform.pickFiles( - type: FileType.image, + final photo = await selectFiles( + context, + type: FileSelectorType.images, allowMultiple: false, - withData: true, ); + final bytes = await photo.singleOrNull?.readAsBytes(); setState(() { avatarUrl = null; - avatar = photo?.files.singleOrNull?.bytes; + avatar = bytes; }); } void submitAction([_]) async { - // #Pangea - if (nameController.text.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(L10n.of(context)!.emptyChatNameWarning), - ), - ); - return; - } - // Pangea# final client = Matrix.of(context).client; try { @@ -104,67 +60,12 @@ class NewGroupController extends State { if (!mounted) return; - // #Pangea - // validate init bot options - if (addConversationBotKey.currentState?.formKey.currentState != null) { - final isValid = addConversationBotKey - .currentState!.formKey.currentState! - .validate(); - if (isValid == false) { - setState(() { - error = L10n.of(context)! - .conversationBotCustomZone_customSystemPromptEmptyError; - loading = false; - }); - return; - } - } - addConversationBotKey.currentState?.updateAllBotOptions(); - final addBot = addConversationBotKey.currentState?.addBot ?? false; - if (addBot) { - final botOptions = addConversationBotKey.currentState!.botOptions; - if (botOptions.mode == BotMode.custom) { - if (botOptions.customSystemPrompt == null || - botOptions.customSystemPrompt!.isEmpty) { - setState(() { - error = L10n.of(context)! - .conversationBotCustomZone_customSystemPromptEmptyError; - loading = false; - }); - return; - } - } else if (botOptions.mode == BotMode.textAdventure) { - if (botOptions.textAdventureGameMasterInstructions == null || - botOptions.textAdventureGameMasterInstructions!.isEmpty) { - setState(() { - error = L10n.of(context)! - .conversationBotCustomZone_instructionSystemPromptEmptyError; - loading = false; - }); - return; - } - } - } - // Pangea# - final roomId = await client.createGroupChat( - // #Pangea - // visibility: - // publicGroup ? sdk.Visibility.public : sdk.Visibility.private, - // preset: publicGroup - // ? sdk.CreateRoomPreset.publicChat - // : sdk.CreateRoomPreset.privateChat, - preset: sdk.CreateRoomPreset.publicChat, - powerLevelContentOverride: - await ClassChatPowerLevels.powerLevelOverrideForClassChat( - context, - addToSpaceKey.currentState!.parent, - ), - invite: [ - if (addConversationBotKey.currentState?.addBot ?? false) - BotName.byEnvironment, - ], - // Pangea# + visibility: + groupCanBeFound ? sdk.Visibility.public : sdk.Visibility.private, + preset: publicGroup + ? sdk.CreateRoomPreset.publicChat + : sdk.CreateRoomPreset.privateChat, groupName: nameController.text.isNotEmpty ? nameController.text : null, initialState: [ if (avatar != null) @@ -172,29 +73,9 @@ class NewGroupController extends State { type: sdk.EventTypes.RoomAvatar, content: {'url': avatarUrl.toString()}, ), - // #Pangea - if (addConversationBotKey.currentState?.addBot ?? false) - addConversationBotKey.currentState!.botOptions.toStateEvent, - // Pangea# ], ); if (!mounted) return; - if (publicGroup && groupCanBeFound) { - await client.setRoomVisibilityOnDirectory( - roomId, - visibility: sdk.Visibility.public, - ); - } - // #Pangea - GoogleAnalytics.createChat(roomId); - await addToSpaceKey.currentState!.addSpaces(roomId); - - final capacity = addCapacityKey.currentState?.capacity; - final room = client.getRoomById(roomId); - if (capacity != null && room != null) { - room.updateRoomCapacity(capacity); - } - // Pangea# context.go('/rooms/$roomId/invite'); } catch (e, s) { sdk.Logs().d('Unable to create group', e, s); @@ -205,20 +86,6 @@ class NewGroupController extends State { } } - //#Pangea - @override - void initState() { - Future.delayed(Duration.zero, () { - chatTopic.langCode = - pangeaController.languageController.userL2?.langCode ?? - pangeaController.pLanguageStore.targetOptions.first.langCode; - setState(() {}); - }); - - super.initState(); - } - //Pangea# - @override Widget build(BuildContext context) => NewGroupView(this); } diff --git a/lib/pages/new_group/new_group_view.dart b/lib/pages/new_group/new_group_view.dart index 6dfcec212..addf7b5f7 100644 --- a/lib/pages/new_group/new_group_view.dart +++ b/lib/pages/new_group/new_group_view.dart @@ -1,8 +1,5 @@ import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/pages/new_group/new_group.dart'; -import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/room_capacity_button.dart'; -import 'package:fluffychat/pangea/widgets/class/add_space_toggles.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings.dart'; import 'package:fluffychat/utils/localized_exception_extension.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/layouts/max_width_body.dart'; @@ -27,20 +24,8 @@ class NewGroupView extends StatelessWidget { onPressed: controller.loading ? null : Navigator.of(context).pop, ), ), - // #Pangea - // title: Text(L10n.of(context)!.createGroup), - title: Text(L10n.of(context)!.createChat), - // Pangea# + title: Text(L10n.of(context)!.createGroup), ), - // #Pangea - floatingActionButton: FloatingActionButton.extended( - onPressed: controller.loading ? null : controller.submitAction, - icon: controller.loading ? null : const Icon(Icons.chat_bubble_outline), - label: controller.loading - ? const CircularProgressIndicator.adaptive() - : Text(L10n.of(context)!.createChat), - ), - // Pangea# body: MaxWidthBody( child: Column( mainAxisSize: MainAxisSize.min, @@ -68,9 +53,6 @@ class NewGroupView extends StatelessWidget { Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: TextField( - // #Pangea - maxLength: 64, - // Pangea# autofocus: true, controller: controller.nameController, autocorrect: false, @@ -85,40 +67,31 @@ class NewGroupView extends StatelessWidget { ), ), const SizedBox(height: 16), - // #Pangea - RoomCapacityButton( - key: controller.addCapacityKey, + SwitchListTile.adaptive( + contentPadding: const EdgeInsets.symmetric(horizontal: 32), + secondary: const Icon(Icons.public_outlined), + title: Text(L10n.of(context)!.groupIsPublic), + value: controller.publicGroup, + onChanged: controller.loading ? null : controller.setPublicGroup, ), - ConversationBotSettings( - key: controller.addConversationBotKey, - activeSpaceId: controller.activeSpaceId, - ), - const Divider(height: 1), - AddToSpaceToggles( - key: controller.addToSpaceKey, - startOpen: true, - activeSpaceId: controller.activeSpaceId, + AnimatedSize( + duration: FluffyThemes.animationDuration, + child: controller.publicGroup + ? SwitchListTile.adaptive( + contentPadding: + const EdgeInsets.symmetric(horizontal: 32), + secondary: const Icon(Icons.search_outlined), + title: Text(L10n.of(context)!.groupCanBeFoundViaSearch), + value: controller.groupCanBeFound, + onChanged: controller.loading + ? null + : controller.setGroupCanBeFound, + ) + : const SizedBox.shrink(), ), + // #Pangea // SwitchListTile.adaptive( - // secondary: const Icon(Icons.public_outlined), - // title: Text(L10n.of(context)!.groupIsPublic), - // value: controller.publicGroup, - // onChanged: controller.loading ? null : controller.setPublicGroup, - // ), - // AnimatedSize( - // duration: FluffyThemes.animationDuration, - // child: controller.publicGroup - // ? SwitchListTile.adaptive( - // secondary: const Icon(Icons.search_outlined), - // title: Text(L10n.of(context)!.groupCanBeFoundViaSearch), - // value: controller.groupCanBeFound, - // onChanged: controller.loading - // ? null - // : controller.setGroupCanBeFound, - // ) - // : const SizedBox.shrink(), - // ), - // SwitchListTile.adaptive( + // contentPadding: const EdgeInsets.symmetric(horizontal: 32), // secondary: Icon( // Icons.lock_outlined, // color: theme.colorScheme.onSurface, @@ -132,29 +105,20 @@ class NewGroupView extends StatelessWidget { // value: !controller.publicGroup, // onChanged: null, // ), - // Padding( - // padding: const EdgeInsets.all(16.0), - // child: SizedBox( - // width: double.infinity, - // child: ElevatedButton( - // onPressed: - // controller.loading ? null : controller.submitAction, - // child: controller.loading - // ? const LinearProgressIndicator() - // : Row( - // children: [ - // Expanded( - // child: Text( - // L10n.of(context)!.createGroupAndInviteUsers, - // ), - // ), - // Icon(Icons.adaptive.arrow_forward_outlined), - // ], - // ), - // ), - // ), - // ), // Pangea# + Padding( + padding: const EdgeInsets.all(16.0), + child: SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: + controller.loading ? null : controller.submitAction, + child: controller.loading + ? const LinearProgressIndicator() + : Text(L10n.of(context)!.createGroupAndInviteUsers), + ), + ), + ), AnimatedSize( duration: FluffyThemes.animationDuration, child: error == null diff --git a/lib/pages/new_space/new_space.dart b/lib/pages/new_space/new_space.dart index 0a7b809d8..e89159900 100644 --- a/lib/pages/new_space/new_space.dart +++ b/lib/pages/new_space/new_space.dart @@ -1,20 +1,19 @@ -import 'package:file_picker/file_picker.dart'; +import 'dart:typed_data'; + import 'package:fluffychat/pages/new_space/new_space_view.dart'; import 'package:fluffychat/pangea/constants/class_default_values.dart'; import 'package:fluffychat/pangea/constants/model_keys.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart'; -import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/room_capacity_button.dart'; import 'package:fluffychat/pangea/utils/bot_name.dart'; -import 'package:fluffychat/pangea/utils/class_chat_power_levels.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:fluffychat/pangea/utils/firebase_analytics.dart'; import 'package:fluffychat/pangea/utils/space_code.dart'; -import 'package:fluffychat/pangea/widgets/class/add_space_toggles.dart'; +import 'package:fluffychat/utils/file_selector.dart'; +import 'package:fluffychat/utils/localized_exception_extension.dart'; import 'package:fluffychat/widgets/matrix.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' as sdk; import 'package:matrix/matrix.dart'; @@ -28,48 +27,32 @@ class NewSpace extends StatefulWidget { class NewSpaceController extends State { TextEditingController nameController = TextEditingController(); TextEditingController topicController = TextEditingController(); - // #Pangea bool publicGroup = false; - // bool publicGroup = true; - // final GlobalKey rulesEditorKey = GlobalKey(); - final GlobalKey addToSpaceKey = GlobalKey(); - // commenting out language settings in spaces for now - // final GlobalKey languageSettingsKey = - // GlobalKey(); - final GlobalKey addCapacityKey = - GlobalKey(); - - //Pangea# bool loading = false; - // #Pangea - // String? nameError; - // String? topicError; - // Pangea# + String? nameError; + String? topicError; Uint8List? avatar; Uri? avatarUrl; void selectPhoto() async { - final photo = await FilePicker.platform.pickFiles( - type: FileType.image, - allowMultiple: false, - withData: true, + final photo = await selectFiles( + context, + type: FileSelectorType.images, ); - + final bytes = await photo.firstOrNull?.readAsBytes(); setState(() { avatarUrl = null; - avatar = photo?.files.singleOrNull?.bytes; + avatar = bytes; }); } void setPublicGroup(bool b) => setState(() => publicGroup = b); // #Pangea - List get initialState { - final events = []; - - events.add( + List initialState(String joinCode) { + return [ StateEvent( type: EventTypes.RoomPowerLevels, stateKey: '', @@ -84,191 +67,94 @@ class NewSpaceController extends State { }, }, ), - ); - - // commenting out pangea room rules in spaces for now - // if (rulesEditorKey.currentState?.rules != null) { - // events.add(rulesEditorKey.currentState!.rules.toStateEvent); - // } else { - // debugger(when: kDebugMode); - // } - // commenting out language settings in spaces for now - // if (languageSettingsKey.currentState != null) { - // events - // .add(languageSettingsKey.currentState!.languageSettings.toStateEvent); - // } - - return events; + StateEvent( + type: sdk.EventTypes.RoomJoinRules, + content: { + ModelKey.joinRule: + sdk.JoinRules.knock.toString().replaceAll('JoinRules.', ''), + ModelKey.accessCode: joinCode, + }, + ), + ]; } //Pangea# void submitAction([_]) async { final client = Matrix.of(context).client; setState(() { - // #Pangea - // nameError = topicError = null; - // Pangea# + nameError = topicError = null; }); - // #Pangea - // commenting out pangea room rules in spaces for now - // if (rulesEditorKey.currentState == null) { - // debugger(when: kDebugMode); - // return; - // } - // commenting out language settings in spaces for now - // if (languageSettingsKey.currentState != null && - // languageSettingsKey.currentState!.sameLanguages) { - // ScaffoldMessenger.of(context).showSnackBar( - // SnackBar( - // content: Text(L10n.of(context)!.noIdenticalLanguages), - // ), - // ); - // return; - // } - // final int? languageLevel = - // languageSettingsKey.currentState!.languageSettings.languageLevel; - // if (languageLevel == null) { - // ScaffoldMessenger.of(context).showSnackBar( - // SnackBar(content: Text(L10n.of(context)!.languageLevelWarning)), - // ); - // return; - // } - // Pangea# if (nameController.text.isEmpty) { setState(() { - // #Pangea - // nameError = L10n.of(context)!.pleaseChoose; - final String warning = L10n.of(context)!.emptySpaceNameWarning; - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(warning)), - ); - // Pangea# + nameError = L10n.of(context)!.pleaseChoose; }); return; } setState(() { loading = true; }); - // #Pangea - // try { - await showFutureLoadingDialog( - context: context, - future: () async { - try { - // Pangea# - final avatar = this.avatar; - avatarUrl ??= - avatar == null ? null : await client.uploadContent(avatar); - final classCode = await SpaceCodeUtil.generateSpaceCode(client); - final spaceId = await client.createRoom( - // #Pangea - preset: publicGroup - ? sdk.CreateRoomPreset.publicChat - : sdk.CreateRoomPreset.privateChat, - // #Pangea - creationContent: {'type': RoomCreationTypes.mSpace}, - visibility: publicGroup ? sdk.Visibility.public : null, - // #Pangea - // roomAliasName: publicGroup - // ? nameController.text.trim().toLowerCase().replaceAll(' ', '_') - // : null, - // roomAliasName: SpaceCodeUtil.generateSpaceCode(), - // Pangea# - name: nameController.text.trim(), - topic: topicController.text.isEmpty ? null : topicController.text, - // #Pangea - // powerLevelContentOverride: {'events_default': 100}, - powerLevelContentOverride: addToSpaceKey.currentState != null - ? await ClassChatPowerLevels.powerLevelOverrideForClassChat( - context, - addToSpaceKey.currentState!.parent, - ) - : null, - // Pangea# - initialState: [ - // #Pangea - ...initialState, - if (avatar != null) - sdk.StateEvent( - type: sdk.EventTypes.RoomAvatar, - content: {'url': avatarUrl.toString()}, - ), - sdk.StateEvent( - type: sdk.EventTypes.RoomJoinRules, - content: { - ModelKey.joinRule: sdk.JoinRules.knock - .toString() - .replaceAll('JoinRules.', ''), - ModelKey.accessCode: classCode, - }, - ), - // Pangea# - ], - // Pangea# - ); - // #Pangea - final List> futures = [ - Matrix.of(context).client.waitForRoomInSync(spaceId, join: true), - ]; - if (addToSpaceKey.currentState != null) { - futures.add(addToSpaceKey.currentState!.addSpaces(spaceId)); - } - await Future.wait(futures); - - final capacity = addCapacityKey.currentState?.capacity; - final space = client.getRoomById(spaceId); - if (capacity != null && space != null) { - space.updateRoomCapacity(capacity); - } - - final Room? room = Matrix.of(context).client.getRoomById(spaceId); - if (room == null) { - ErrorHandler.logError( - e: 'Failed to get new space by id $spaceId', - ); - MatrixState.pangeaController.classController - .setActiveSpaceIdInChatListController(spaceId); - return; - } + try { + final avatar = this.avatar; + avatarUrl ??= avatar == null ? null : await client.uploadContent(avatar); + // #Pangea + final joinCode = await SpaceCodeUtil.generateSpaceCode(client); + // Pangea# - GoogleAnalytics.createClass(room.name, room.classCode); - try { - await room.invite(BotName.byEnvironment); - } catch (err) { - ErrorHandler.logError( - e: "Failed to invite pangea bot to space ${room.id}", - ); - } - // Pangea# - if (!mounted) return; + final spaceId = await client.createRoom( + preset: publicGroup + ? sdk.CreateRoomPreset.publicChat + : sdk.CreateRoomPreset.privateChat, + creationContent: {'type': RoomCreationTypes.mSpace}, + visibility: publicGroup ? sdk.Visibility.public : null, + roomAliasName: publicGroup + ? nameController.text.trim().toLowerCase().replaceAll(' ', '_') + : null, + name: nameController.text.trim(), + topic: topicController.text.isEmpty ? null : topicController.text, + powerLevelContentOverride: {'events_default': 100}, + initialState: [ // #Pangea - // context.pop(spaceId); - MatrixState.pangeaController.classController - .setActiveSpaceIdInChatListController(spaceId); + ...initialState(joinCode), // Pangea# - } catch (e, s) { - // #Pangea - ErrorHandler.logError(e: e, s: s); - rethrow; - // setState(() { - // topicError = e.toLocalizedString(context); - // }); - // Pangea# - } finally { - setState(() { - loading = false; - }); - } - }, - ); + if (avatar != null) + sdk.StateEvent( + type: sdk.EventTypes.RoomAvatar, + content: {'url': avatarUrl.toString()}, + ), + ], + ); + if (!mounted) return; + // #Pangea + Room? room = client.getRoomById(spaceId); + if (room == null) { + await Matrix.of(context).client.waitForRoomInSync(spaceId); + room = client.getRoomById(spaceId); + } + if (room == null) return; + GoogleAnalytics.createClass(room.name, room.classCode); + try { + await room.invite(BotName.byEnvironment); + } catch (err) { + ErrorHandler.logError( + e: "Failed to invite pangea bot to space ${room.id}", + ); + } + MatrixState.pangeaController.classController + .setActiveSpaceIdInChatListController(spaceId); + // Pangea# + context.pop(spaceId); + } catch (e) { + setState(() { + topicError = e.toLocalizedString(context); + }); + } finally { + setState(() { + loading = false; + }); + } // TODO: Go to spaces } @override - // #Pangea - // Widget build(BuildContext context) => NewSpaceView(this); - Widget build(BuildContext context) { - return NewSpaceView(this); - } - // Pangea# + Widget build(BuildContext context) => NewSpaceView(this); } diff --git a/lib/pages/new_space/new_space_view.dart b/lib/pages/new_space/new_space_view.dart index 087218a48..3842231c8 100644 --- a/lib/pages/new_space/new_space_view.dart +++ b/lib/pages/new_space/new_space_view.dart @@ -1,5 +1,3 @@ -import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/room_capacity_button.dart'; -import 'package:fluffychat/pangea/widgets/class/add_space_toggles.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/layouts/max_width_body.dart'; import 'package:flutter/material.dart'; @@ -19,15 +17,6 @@ class NewSpaceView extends StatelessWidget { appBar: AppBar( title: Text(L10n.of(context)!.createNewSpace), ), - // #Pangea - floatingActionButton: FloatingActionButton.extended( - onPressed: controller.loading ? null : controller.submitAction, - icon: controller.loading ? null : const Icon(Icons.workspaces_outlined), - label: controller.loading - ? const CircularProgressIndicator.adaptive() - : Text(L10n.of(context)!.createSpace), - ), - // Pangea# body: MaxWidthBody( child: Column( mainAxisSize: MainAxisSize.min, @@ -62,58 +51,38 @@ class NewSpaceView extends StatelessWidget { decoration: InputDecoration( prefixIcon: const Icon(Icons.people_outlined), labelText: L10n.of(context)!.spaceName, - // #Pangea - // errorText: controller.nameError, - // Pangea# + errorText: controller.nameError, ), ), ), const SizedBox(height: 16), - // #Pangea - RoomCapacityButton( - key: controller.addCapacityKey, - spaceMode: true, + SwitchListTile.adaptive( + contentPadding: const EdgeInsets.symmetric(horizontal: 32), + title: Text(L10n.of(context)!.spaceIsPublic), + value: controller.publicGroup, + onChanged: controller.setPublicGroup, + ), + ListTile( + contentPadding: const EdgeInsets.symmetric(horizontal: 32), + trailing: const Padding( + padding: EdgeInsets.symmetric(horizontal: 16.0), + child: Icon(Icons.info_outlined), + ), + subtitle: Text(L10n.of(context)!.newSpaceDescription), ), - AddToSpaceToggles( - key: controller.addToSpaceKey, - startOpen: true, - spaceMode: true, + Padding( + padding: const EdgeInsets.all(16.0), + child: SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: + controller.loading ? null : controller.submitAction, + child: controller.loading + ? const LinearProgressIndicator() + : Text(L10n.of(context)!.createNewSpace), + ), + ), ), - // SwitchListTile.adaptive( - // title: Text(L10n.of(context)!.spaceIsPublic), - // value: controller.publicGroup, - // onChanged: controller.setPublicGroup, - // ), - // ListTile( - // trailing: const Padding( - // padding: EdgeInsets.symmetric(horizontal: 16.0), - // child: Icon(Icons.info_outlined), - // ), - // subtitle: Text(L10n.of(context)!.newSpaceDescription), - // ), - // Padding( - // padding: const EdgeInsets.all(16.0), - // child: SizedBox( - // width: double.infinity, - // child: ElevatedButton( - // onPressed: - // controller.loading ? null : controller.submitAction, - // child: controller.loading - // ? const LinearProgressIndicator() - // : Row( - // children: [ - // Expanded( - // child: Text( - // L10n.of(context)!.createNewSpace, - // ), - // ), - // Icon(Icons.adaptive.arrow_forward_outlined), - // ], - // ), - // ), - // ), - // ), - // Pangea# ], ), ), diff --git a/lib/pangea/widgets/class/add_space_toggles.dart b/lib/pangea/widgets/class/add_space_toggles.dart deleted file mode 100644 index fd7843955..000000000 --- a/lib/pangea/widgets/class/add_space_toggles.dart +++ /dev/null @@ -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 { - late Room? room; - late Room? parent; - late List 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 _addSingleSpace(String roomToAddId, Room newParent) async { - GoogleAnalytics.addParent(roomToAddId, newParent.classCode); - await newParent.pangeaSetSpaceChild( - roomToAddId, - suggested: isSuggested, - ); - } - - Future addSpaces(String roomToAddId) async { - if (parent == null) return; - await _addSingleSpace(roomToAddId, parent!); - } - - Future 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 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, - ), - ), - ), - ), - ], - ], - ); - } -} diff --git a/lib/utils/file_selector.dart b/lib/utils/file_selector.dart new file mode 100644 index 000000000..e9d36652c --- /dev/null +++ b/lib/utils/file_selector.dart @@ -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> 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: ['jpg', 'JPG', 'jpeg', 'JPEG'], + ), + XTypeGroup( + label: 'PNGs', + extensions: ['png', 'PNG'], + ), + XTypeGroup( + label: 'WEBP', + extensions: ['WebP', 'WEBP'], + ), + ], + FileType.image, + null, + ), + zip( + [ + XTypeGroup( + label: 'ZIP', + extensions: ['zip', 'ZIP'], + ), + ], + FileType.custom, + ['zip', 'ZIP'], + ); + + const FileSelectorType(this.groups, this.filePickerType, this.extensions); + final List groups; + final FileType filePickerType; + final List? extensions; +} diff --git a/pubspec.lock b/pubspec.lock index 8ca2f83e7..c8a53d2c7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -424,6 +424,30 @@ packages: url: "https://pub.dev" source: hosted version: "8.0.6" + file_selector: + dependency: "direct main" + description: + name: file_selector + sha256: "5019692b593455127794d5718304ff1ae15447dea286cdda9f0db2a796a1b828" + url: "https://pub.dev" + source: hosted + version: "1.0.3" + file_selector_android: + dependency: transitive + description: + name: file_selector_android + sha256: "00aafa9ae05a8663d0b4f17abd2a02316911ca0f46f9b9dacb9578b324d99590" + url: "https://pub.dev" + source: hosted + version: "0.5.1+9" + file_selector_ios: + dependency: transitive + description: + name: file_selector_ios + sha256: "94b98ad950b8d40d96fee8fa88640c2e4bd8afcdd4817993bd04e20310f45420" + url: "https://pub.dev" + source: hosted + version: "0.5.3+1" file_selector_linux: dependency: transitive description: @@ -448,6 +472,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.6.2" + file_selector_web: + dependency: transitive + description: + name: file_selector_web + sha256: c4c0ea4224d97a60a7067eca0c8fd419e708ff830e0c83b11a48faf566cec3e7 + url: "https://pub.dev" + source: hosted + version: "0.9.4+2" file_selector_windows: dependency: transitive description: @@ -2756,5 +2788,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.4.0 <4.0.0" - flutter: ">=3.22.0" + dart: ">=3.5.0 <4.0.0" + flutter: ">=3.24.0" diff --git a/pubspec.yaml b/pubspec.yaml index 77dd5ad5c..69f0f1a63 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -32,6 +32,7 @@ dependencies: emojis: ^0.9.9 #fcm_shared_isolate: ^0.1.0 file_picker: ^8.0.6 + file_selector: ^1.0.3 flutter: sdk: flutter flutter_app_badger: ^1.5.0