feat: add edit course page (#3971)
This commit is contained in:
parent
95bff8a2f0
commit
c831d6964d
4 changed files with 255 additions and 8 deletions
|
|
@ -32,6 +32,7 @@ import 'package:fluffychat/pangea/activity_sessions/activity_session_start/activ
|
|||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_page/analytics_page.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_indicators_enum.dart';
|
||||
import 'package:fluffychat/pangea/chat_settings/pages/edit_course.dart';
|
||||
import 'package:fluffychat/pangea/chat_settings/pages/pangea_invitation_selection.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/course_creation/new_course_page.dart';
|
||||
|
|
@ -996,6 +997,15 @@ abstract class AppRoutes {
|
|||
];
|
||||
|
||||
static List<RouteBase> roomDetailsRoutes(String roomKey) => [
|
||||
GoRoute(
|
||||
path: '/edit',
|
||||
redirect: loggedOutRedirect,
|
||||
pageBuilder: (context, state) => defaultPageBuilder(
|
||||
context,
|
||||
state,
|
||||
EditCourse(roomId: state.pathParameters[roomKey]!),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/analytics',
|
||||
redirect: loggedOutRedirect,
|
||||
|
|
|
|||
|
|
@ -5232,5 +5232,7 @@
|
|||
"results": "Results",
|
||||
"activityDone": "Activity Done!",
|
||||
"moreLabel": "more",
|
||||
"promoCodeInfo": "Promo codes can be entered on the next page"
|
||||
"promoCodeInfo": "Promo codes can be entered on the next page",
|
||||
"editsComingSoon": "The ability to edit cities and activities is coming soon.",
|
||||
"editing": "Editing"
|
||||
}
|
||||
|
|
|
|||
237
lib/pangea/chat_settings/pages/edit_course.dart
Normal file
237
lib/pangea/chat_settings/pages/edit_course.dart
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/l10n/l10n.dart';
|
||||
import 'package:fluffychat/pages/settings/settings.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/url_image_widget.dart';
|
||||
import 'package:fluffychat/pangea/course_plans/map_clipper.dart';
|
||||
import 'package:fluffychat/utils/file_selector.dart';
|
||||
import 'package:fluffychat/utils/platform_infos.dart';
|
||||
import 'package:fluffychat/widgets/adaptive_dialogs/show_modal_action_popup.dart';
|
||||
import 'package:fluffychat/widgets/future_loading_dialog.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class EditCourse extends StatefulWidget {
|
||||
final String roomId;
|
||||
const EditCourse({super.key, required this.roomId});
|
||||
|
||||
@override
|
||||
EditCourseController createState() => EditCourseController();
|
||||
}
|
||||
|
||||
class EditCourseController extends State<EditCourse> {
|
||||
final _titleController = TextEditingController();
|
||||
final _descController = TextEditingController();
|
||||
MatrixFile? _avatar;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (_room != null) {
|
||||
_titleController.text = _room!.name;
|
||||
_descController.text = _room!.topic;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_titleController.dispose();
|
||||
_descController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Room? get _room => Matrix.of(context).client.getRoomById(widget.roomId);
|
||||
|
||||
Future<void> _saveChanges() async {
|
||||
if (_room == null) return;
|
||||
final title = _titleController.text.trim();
|
||||
final desc = _descController.text.trim();
|
||||
|
||||
if (title.isNotEmpty && title != _room!.name) {
|
||||
await _room!.setName(title);
|
||||
}
|
||||
if (desc.isNotEmpty && desc != _room!.topic) {
|
||||
await _room!.setDescription(desc);
|
||||
}
|
||||
if (_avatar != null) {
|
||||
await _room!.setAvatar(_avatar!);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _setAvatarAction() async {
|
||||
if (_room == null) return;
|
||||
final actions = [
|
||||
if (PlatformInfos.isMobile)
|
||||
AdaptiveModalAction(
|
||||
value: AvatarAction.camera,
|
||||
label: L10n.of(context).openCamera,
|
||||
isDefaultAction: true,
|
||||
icon: const Icon(Icons.camera_alt_outlined),
|
||||
),
|
||||
AdaptiveModalAction(
|
||||
value: AvatarAction.file,
|
||||
label: L10n.of(context).openGallery,
|
||||
icon: const Icon(Icons.photo_outlined),
|
||||
),
|
||||
];
|
||||
final action = actions.length == 1
|
||||
? actions.single.value
|
||||
: await showModalActionPopup<AvatarAction>(
|
||||
context: context,
|
||||
title: L10n.of(context).editRoomAvatar,
|
||||
cancelLabel: L10n.of(context).cancel,
|
||||
actions: actions,
|
||||
);
|
||||
if (action == null) return;
|
||||
if (PlatformInfos.isMobile) {
|
||||
final result = await ImagePicker().pickImage(
|
||||
source: action == AvatarAction.camera
|
||||
? ImageSource.camera
|
||||
: ImageSource.gallery,
|
||||
imageQuality: 50,
|
||||
);
|
||||
if (result == null) return;
|
||||
_avatar = MatrixFile(
|
||||
bytes: await result.readAsBytes(),
|
||||
name: result.path,
|
||||
);
|
||||
} else {
|
||||
final picked = await selectFiles(
|
||||
context,
|
||||
allowMultiple: false,
|
||||
type: FileSelectorType.images,
|
||||
);
|
||||
final pickedFile = picked.firstOrNull;
|
||||
if (pickedFile == null) return;
|
||||
_avatar = MatrixFile(
|
||||
bytes: await pickedFile.readAsBytes(),
|
||||
name: pickedFile.name,
|
||||
);
|
||||
}
|
||||
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: const Center(child: BackButton()),
|
||||
title: Text(L10n.of(context).editing),
|
||||
),
|
||||
body: StreamBuilder(
|
||||
stream: Matrix.of(context).client.onRoomState.stream.where(
|
||||
(u) => u.roomId == widget.roomId,
|
||||
),
|
||||
builder: (context, snapshot) {
|
||||
return SafeArea(
|
||||
child: Container(
|
||||
alignment: Alignment.topCenter,
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 600,
|
||||
),
|
||||
child: _room == null || !_room!.isSpace
|
||||
? Center(child: Text(L10n.of(context).noRoomsFound))
|
||||
: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
spacing: 16.0,
|
||||
children: [
|
||||
Stack(
|
||||
children: [
|
||||
ClipPath(
|
||||
clipper: MapClipper(),
|
||||
child: _avatar != null
|
||||
? Image.memory(
|
||||
_avatar!.bytes,
|
||||
width: 200.0,
|
||||
height: 200.0,
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: ImageByUrl(
|
||||
imageUrl:
|
||||
_room?.avatar.toString(),
|
||||
width: 200.0,
|
||||
borderRadius:
|
||||
BorderRadius.circular(0.0),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
child: FloatingActionButton.small(
|
||||
onPressed: _setAvatarAction,
|
||||
child: const Icon(
|
||||
Icons.camera_alt_outlined,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
TextField(
|
||||
controller: _titleController,
|
||||
decoration: InputDecoration(
|
||||
border: OutlineInputBorder(
|
||||
borderRadius:
|
||||
BorderRadius.circular(4.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
TextField(
|
||||
controller: _descController,
|
||||
decoration: InputDecoration(
|
||||
border: OutlineInputBorder(
|
||||
borderRadius:
|
||||
BorderRadius.circular(4.0),
|
||||
),
|
||||
),
|
||||
maxLines: null,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 16.0,
|
||||
),
|
||||
child: Text(
|
||||
L10n.of(context).editsComingSoon,
|
||||
style: const TextStyle(
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
child: ElevatedButton(
|
||||
onPressed: () => showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: _saveChanges,
|
||||
),
|
||||
child: Row(
|
||||
spacing: 8.0,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(Icons.save_outlined),
|
||||
Text(L10n.of(context).saveChanges),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,6 @@ import 'package:fluffychat/pangea/course_plans/course_plan_builder.dart';
|
|||
import 'package:fluffychat/pangea/course_plans/course_plan_room_extension.dart';
|
||||
import 'package:fluffychat/pangea/course_plans/map_clipper.dart';
|
||||
import 'package:fluffychat/pangea/course_settings/course_settings.dart';
|
||||
import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart';
|
||||
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
|
||||
import 'package:fluffychat/pangea/space_analytics/space_analytics.dart';
|
||||
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
|
||||
|
|
@ -112,16 +111,15 @@ class SpaceDetailsContent extends StatelessWidget {
|
|||
'/rooms/spaces/${room.id}/details/invite?filter=$filter',
|
||||
);
|
||||
},
|
||||
enabled: room.canInvite && !room.isDirectChat,
|
||||
enabled: room.canInvite,
|
||||
showInMainView: false,
|
||||
),
|
||||
ButtonDetails(
|
||||
title: l10n.editCourse,
|
||||
description: l10n.editCourseDesc,
|
||||
icon: const Icon(Icons.edit_outlined, size: 30.0),
|
||||
onPressed: () {},
|
||||
visible: false,
|
||||
enabled: room.canChangeStateEvent(PangeaEventTypes.coursePlan),
|
||||
onPressed: () => context.go('/rooms/${room.id}/details/edit'),
|
||||
enabled: room.isRoomAdmin,
|
||||
showInMainView: false,
|
||||
),
|
||||
ButtonDetails(
|
||||
|
|
@ -129,7 +127,7 @@ class SpaceDetailsContent extends StatelessWidget {
|
|||
description: l10n.permissionsDesc,
|
||||
icon: const Icon(Icons.edit_attributes_outlined, size: 30.0),
|
||||
onPressed: () => context.go('/rooms/${room.id}/details/permissions'),
|
||||
enabled: room.isRoomAdmin && !room.isDirectChat,
|
||||
enabled: room.isRoomAdmin,
|
||||
showInMainView: false,
|
||||
),
|
||||
ButtonDetails(
|
||||
|
|
@ -193,7 +191,7 @@ class SpaceDetailsContent extends StatelessWidget {
|
|||
context.go("/rooms");
|
||||
}
|
||||
},
|
||||
enabled: room.isRoomAdmin && !room.isDirectChat,
|
||||
enabled: room.isRoomAdmin,
|
||||
showInMainView: false,
|
||||
),
|
||||
];
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue