Dismiss course invite (#4509)

* Copy chat invite behavior for course invite

* Add badge to distinguish joined courses from invited courses

* Edit badge appearance

* Badge position tweak, fix intl_en from merge
This commit is contained in:
Kelrap 2025-10-27 10:16:17 -04:00 committed by GitHub
parent 6e50354636
commit b781aebf58
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 103 additions and 38 deletions

View file

@ -5314,5 +5314,7 @@
"alreadyInCourseWithID": "You are already in a course with this plan. Do you want to create a course with the same plan, or go to the existing course?",
"goToExistingCourse": "Go to existing course",
"emojiView": "Emoji view",
"feedbackDialogDesc": "I make mistakes too! Anything to help me improve?"
}
"feedbackDialogDesc": "I make mistakes too! Anything to help me improve?",
"getStartedFriendsButton": "Invite a friend",
"contactHasBeenInvitedToTheCourse": "Contact has been invited to the course"
}

View file

@ -5,43 +5,80 @@ import 'package:matrix/matrix.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
import 'package:fluffychat/utils/localized_exception_extension.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/adaptive_dialog_action.dart';
import 'package:fluffychat/widgets/future_loading_dialog.dart';
import 'package:fluffychat/widgets/matrix.dart';
import '../../common/utils/error_handler.dart';
Future<void> showInviteDialog(Room room, BuildContext context) async {
if (room.membership != Membership.invite) return;
final acceptInvite = await showOkCancelAlertDialog(
context: context,
title: L10n.of(context).youreInvited,
message: room.isSpace
? L10n.of(context).invitedToSpace(room.name, room.creatorId ?? "???")
: L10n.of(context).invitedToChat(room.name, room.creatorId ?? "???"),
okLabel: L10n.of(context).accept,
cancelLabel: L10n.of(context).decline,
);
final resp = await showFutureLoadingDialog(
final theme = Theme.of(context);
final action = await showAdaptiveDialog<CourseInviteAction>(
barrierDismissible: true,
context: context,
builder: (context) => AlertDialog.adaptive(
title: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 256),
child: Center(
child: Text(
L10n.of(context).youreInvited,
textAlign: TextAlign.center,
),
),
),
content: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 256, maxHeight: 256),
child: Text(
room.isSpace
? L10n.of(context)
.invitedToSpace(room.name, room.creatorId ?? "???")
: L10n.of(context)
.invitedToChat(room.name, room.creatorId ?? "???"),
textAlign: TextAlign.center,
),
),
actions: [
AdaptiveDialogAction(
onPressed: () =>
Navigator.of(context).pop(CourseInviteAction.decline),
bigButtons: true,
child: Text(
L10n.of(context).decline,
style: TextStyle(color: theme.colorScheme.error),
),
),
AdaptiveDialogAction(
onPressed: () => Navigator.of(context).pop(CourseInviteAction.accept),
bigButtons: true,
child: Text(L10n.of(context).accept),
),
],
),
);
switch (action) {
case null:
return;
case CourseInviteAction.accept:
break;
case CourseInviteAction.decline:
await room.leave();
return;
}
final joinResult = await showFutureLoadingDialog(
context: context,
future: () async {
if (acceptInvite == OkCancelResult.ok) {
await room.join();
context.go(
room.isSpace
? "/rooms/spaces/${room.id}/details"
: "/rooms/${room.id}",
);
return room.id;
} else if (acceptInvite == OkCancelResult.cancel) {
await room.leave();
}
await room.join();
},
exceptionContext: ExceptionContext.joinRoom,
);
if (joinResult.error != null) return;
if (!resp.isError && resp.result is String) {
context.go("/rooms/spaces/${resp.result}/details");
}
context.go(
room.isSpace ? "/rooms/spaces/${room.id}/details" : "/rooms/${room.id}",
);
}
// ignore: curly_braces_in_flow_control_structures
@ -100,3 +137,5 @@ void chatListHandleSpaceTap(
break;
}
}
enum CourseInviteAction { accept, decline }

View file

@ -402,7 +402,11 @@ class PangeaInvitationSelectionController
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(L10n.of(context).contactHasBeenInvitedToTheChat),
content: Text(
room.isSpace
? L10n.of(context).contactHasBeenInvitedToTheCourse
: L10n.of(context).contactHasBeenInvitedToTheChat,
),
),
);
}

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:badges/badges.dart' as b;
import 'package:go_router/go_router.dart';
import 'package:matrix/matrix.dart';
@ -224,17 +225,36 @@ class SpacesNavigationRail extends StatelessWidget {
// AppConfig.borderRadius / 2,
// ),
// ),
icon: ClipPath(
clipper: MapClipper(),
child: Avatar(
mxContent: rootSpaces[i].avatar,
name: displayname,
border: BorderSide(
width: 1,
color: Theme.of(context).dividerColor,
icon: b.Badge(
showBadge:
rootSpaces[i].membership == Membership.invite,
badgeStyle: b.BadgeStyle(
badgeColor: Theme.of(context).colorScheme.error,
elevation: 4,
borderSide: BorderSide.none,
padding: const EdgeInsetsGeometry.all(0),
),
badgeContent: Icon(
Icons.error_outline,
color: Theme.of(context).colorScheme.onPrimary,
size: 16,
),
position: b.BadgePosition.topEnd(
top: -5,
end: -7,
),
child: ClipPath(
clipper: MapClipper(),
child: Avatar(
mxContent: rootSpaces[i].avatar,
name: displayname,
border: BorderSide(
width: 1,
color: Theme.of(context).dividerColor,
),
borderRadius: BorderRadius.circular(0),
size: width - (isColumnMode ? 32.0 : 24.0),
),
borderRadius: BorderRadius.circular(0),
size: width - (isColumnMode ? 32.0 : 24.0),
),
),
// Pangea#