refactor: new invite page design (#2763)

This commit is contained in:
ggurdin 2025-05-12 11:40:06 -04:00 committed by GitHub
parent 6f71dd4e95
commit b41d572698
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 437 additions and 429 deletions

View file

@ -4870,7 +4870,7 @@
"areYouLikeMe": "Are you like me?",
"tryAgainLater": "Too many attempts made. Please try again in 5 minutes.",
"enterSpaceCode": "Enter space code",
"shareSpaceLink": "Share link to space",
"shareSpaceLink": "Share link",
"byUsingPangeaChat": "By using Pangea Chat, I agree to the ",
"details": "Details",
"languageLevelPreA1Desc": "I have never learned or used the language.",
@ -4912,5 +4912,14 @@
"forms": "Forms",
"exampleMessages": "Example messages",
"timesUsedIndependently": "Times used independently",
"timesUsedWithAssistance": "Times used with assistance"
"timesUsedWithAssistance": "Times used with assistance",
"goToSpaceButton": "Go to space",
"shareInviteCode": "Share invite code: {code}",
"@shareInviteCode": {
"placeholders": {
"code": {
"type": "String"
}
}
}
}

View file

@ -888,10 +888,13 @@ class ChatController extends State<ChatPageWithRoom>
pangeaEditingEvent = previousEdit;
}
GoogleAnalytics.sendMessage(
room.id,
room.classCode(context),
);
final spaceCode = room.classCode(context);
if (spaceCode != null) {
GoogleAnalytics.sendMessage(
room.id,
spaceCode,
);
}
if (msgEventId == null) {
ErrorHandler.logError(

View file

@ -35,6 +35,36 @@ class InvitationSelectionController extends State<InvitationSelection> {
String? get roomId => widget.roomId;
// #Pangea
final viewportKey = GlobalKey();
final participantListItemHeight = 72.0;
final goToChatButtonHeight = 50.0;
final shareButtonsHeight = 150.0;
final padding = 16.0 * 2;
final fixedParticipantHeight = 72.0;
double? viewportHeight;
double get availableHeight =>
(viewportHeight ?? 0) -
goToChatButtonHeight -
shareButtonsHeight -
padding;
bool showShareButtons(int numParticipants) =>
(fixedParticipantHeight * numParticipants) < availableHeight;
@override
initState() {
WidgetsBinding.instance.addPostFrameCallback((_) {
final context = viewportKey.currentContext;
if (context == null) return;
final renderBox = context.findRenderObject() as RenderBox;
final size = renderBox.size;
setState(() => viewportHeight = size.height);
});
super.initState();
}
List<User>? get participants {
final room = Matrix.of(context).client.getRoomById(roomId!);
return room?.getParticipants();

View file

@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:collection/collection.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:go_router/go_router.dart';
import 'package:matrix/matrix.dart';
@ -14,11 +13,11 @@ import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pages/invitation_selection/invitation_selection.dart';
import 'package:fluffychat/pangea/analytics_misc/level_display_name.dart';
import 'package:fluffychat/pangea/chat_settings/constants/room_settings_constants.dart';
import 'package:fluffychat/pangea/chat_settings/widgets/refer_friends_dialog.dart';
import 'package:fluffychat/pangea/chat_settings/widgets/space_invite_buttons.dart';
import 'package:fluffychat/pangea/common/config/environment.dart';
import 'package:fluffychat/pangea/common/widgets/full_width_dialog.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
import 'package:fluffychat/pangea/spaces/constants/space_constants.dart';
import 'package:fluffychat/utils/stream_extension.dart';
import 'package:fluffychat/widgets/avatar.dart';
import 'package:fluffychat/widgets/layouts/max_width_body.dart';
import 'package:fluffychat/widgets/matrix.dart';
@ -53,346 +52,247 @@ class InvitationSelectionView extends StatelessWidget {
leading: const Center(child: BackButton()),
titleSpacing: 0,
title: Text(L10n.of(context).inviteContact),
// #Pangea
actions: [
if (room.classCode(context) != null)
PopupMenuButton<int>(
icon: const Icon(Icons.share_outlined),
onSelected: (value) async {
final spaceCode = room.classCode(context)!;
String toCopy = spaceCode;
if (value == 0) {
final String initialUrl =
kIsWeb ? html.window.origin! : Environment.frontendURL;
toCopy =
"$initialUrl/#/join_with_link?${SpaceConstants.classCode}=${room.classCode(context)}";
}
await Clipboard.setData(ClipboardData(text: toCopy));
ScaffoldMessenger.of(
context,
).showSnackBar(
SnackBar(
content: Text(
L10n.of(context).copiedToClipboard,
),
),
);
},
itemBuilder: (BuildContext context) => <PopupMenuEntry<int>>[
PopupMenuItem<int>(
value: 0,
child: ListTile(
leading: const Icon(Icons.share_outlined),
title: Text(L10n.of(context).shareSpaceLink),
contentPadding: const EdgeInsets.all(0),
),
),
PopupMenuItem<int>(
value: 1,
child: ListTile(
leading: const Icon(Icons.share_outlined),
title: Text(
L10n.of(context)
.shareInviteCode(room.classCode(context)!),
),
contentPadding: const EdgeInsets.all(0),
),
),
],
),
],
// Pangea#
),
body: MaxWidthBody(
innerPadding: const EdgeInsets.symmetric(vertical: 8),
// #Pangea
withScrolling: false,
// Pangea#
child: Column(
child: Stack(
alignment: Alignment.bottomCenter,
children: [
// #Pangea
Padding(
padding: const EdgeInsets.all(16.0),
child: InkWell(
customBorder: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(99),
),
onTap: () async {
await Clipboard.setData(
ClipboardData(text: room.classCode(context)),
);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(L10n.of(context).copiedToClipboard)),
);
},
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 12.0,
horizontal: 16.0,
),
decoration: BoxDecoration(
color: theme.colorScheme.secondaryContainer,
borderRadius: BorderRadius.circular(99),
),
child: Row(
spacing: 16.0,
children: [
const Icon(
Icons.copy_outlined,
size: 20.0,
),
Text(
"${L10n.of(context).copyClassCode}: ${room.classCode(context)}",
style: TextStyle(
color: theme.colorScheme.onPrimaryContainer,
fontWeight: FontWeight.normal,
fontSize: 16.0,
),
),
],
child: SizedBox(
width: 450,
child: CachedNetworkImage(
imageUrl:
"${AppConfig.assetsBaseURL}/${RoomSettingsConstants.referFriendAsset}",
errorWidget: (context, url, error) => const SizedBox(),
placeholder: (context, url) => const Center(
child: CircularProgressIndicator.adaptive(),
),
),
),
),
Padding(
padding: const EdgeInsets.only(
bottom: 16.0,
left: 16.0,
right: 16.0,
),
child: InkWell(
customBorder: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(99),
),
onTap: () async {
final String initialUrl =
kIsWeb ? html.window.origin! : Environment.frontendURL;
final link =
"$initialUrl/#/join_with_link?${SpaceConstants.classCode}=${room.classCode(context)}";
await Clipboard.setData(ClipboardData(text: link));
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(L10n.of(context).copiedToClipboard)),
);
},
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 12.0,
horizontal: 16.0,
),
decoration: BoxDecoration(
color: theme.colorScheme.secondaryContainer,
borderRadius: BorderRadius.circular(99),
),
child: Row(
spacing: 16.0,
children: [
const Icon(
Icons.copy_outlined,
size: 20.0,
),
Text(
L10n.of(context).copyClassLink,
style: TextStyle(
color: theme.colorScheme.onPrimaryContainer,
fontWeight: FontWeight.normal,
fontSize: 16.0,
),
),
],
),
),
),
),
// Pangea#
Padding(
// #Pangea
// padding: const EdgeInsets.all(16.0),
padding: const EdgeInsets.only(
bottom: 16.0,
left: 16.0,
right: 16.0,
),
// Pangea#
child: TextField(
textInputAction: TextInputAction.search,
decoration: InputDecoration(
filled: true,
fillColor: theme.colorScheme.secondaryContainer,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(99),
),
hintStyle: TextStyle(
color: theme.colorScheme.onPrimaryContainer,
fontWeight: FontWeight.normal,
),
Column(
children: [
Padding(
// #Pangea
hintText: L10n.of(context).inviteStudentByUserName,
// hintText: L10n.of(context).inviteContactToGroup(groupName),
// padding: const EdgeInsets.all(16.0),
padding: const EdgeInsets.only(
bottom: 16.0,
left: 16.0,
right: 16.0,
),
// Pangea#
prefixIcon: controller.loading
? const Padding(
padding: EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 12,
),
child: SizedBox.square(
dimension: 24,
child: CircularProgressIndicator.adaptive(
strokeWidth: 2,
),
),
)
: const Icon(Icons.search_outlined),
),
onChanged: controller.searchUserWithCoolDown,
),
),
// #Pangea
// StreamBuilder<Object>(
Expanded(
child: StreamBuilder<Object>(
// Pangea#
stream: room.client.onRoomState.stream
.where((update) => update.roomId == room.id),
builder: (context, snapshot) {
final participants =
room.getParticipants().map((user) => user.id).toSet();
return controller.foundProfiles.isNotEmpty
? ListView.builder(
// #Pangea
// physics: const NeverScrollableScrollPhysics(),
// shrinkWrap: true,
// Pangea#
itemCount: controller.foundProfiles.length,
itemBuilder: (BuildContext context, int i) =>
_InviteContactListTile(
profile: controller.foundProfiles[i],
isMember: participants
.contains(controller.foundProfiles[i].userId),
onTap: () => controller.inviteAction(
context,
controller.foundProfiles[i].userId,
controller.foundProfiles[i].displayName ??
controller
.foundProfiles[i].userId.localpart ??
L10n.of(context).user,
),
),
)
: FutureBuilder<List<User>>(
future: controller.getContacts(context),
builder: (BuildContext context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: TextField(
textInputAction: TextInputAction.search,
decoration: InputDecoration(
filled: true,
fillColor: theme.colorScheme.secondaryContainer,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(99),
),
hintStyle: TextStyle(
color: theme.colorScheme.onPrimaryContainer,
fontWeight: FontWeight.normal,
),
// #Pangea
hintText: L10n.of(context).inviteStudentByUserName,
// hintText: L10n.of(context).inviteContactToGroup(groupName),
// Pangea#
prefixIcon: controller.loading
? const Padding(
padding: EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 12,
),
child: SizedBox.square(
dimension: 24,
child: CircularProgressIndicator.adaptive(
strokeWidth: 2,
),
);
}
final contacts = snapshot.data!;
return ListView.builder(
),
)
: const Icon(Icons.search_outlined),
),
onChanged: controller.searchUserWithCoolDown,
),
),
// #Pangea
// StreamBuilder<Object>(
Expanded(
key: controller.viewportKey,
child: StreamBuilder<Object>(
// stream: room.client.onRoomState.stream
// .where((update) => update.roomId == room.id),
stream: room.client.onRoomState.stream
.where((update) => update.roomId == room.id)
.rateLimit(const Duration(seconds: 1)),
// Pangea#
builder: (context, snapshot) {
final participants =
room.getParticipants().map((user) => user.id).toSet();
return controller.foundProfiles.isNotEmpty
? ListView.builder(
// #Pangea
// physics: const NeverScrollableScrollPhysics(),
// shrinkWrap: true,
// itemCount: contacts.length,
// itemBuilder: (BuildContext context, int i) =>
// _InviteContactListTile(
itemCount: contacts.length + 1,
itemBuilder: (BuildContext context, int i) {
if (i == contacts.length) {
return room.isSpace
? const SizedBox()
: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: SizedBox(
width: 450,
child: CachedNetworkImage(
imageUrl:
"${AppConfig.assetsBaseURL}/${RoomSettingsConstants.referFriendAsset}",
errorWidget:
(context, url, error) =>
const SizedBox(),
placeholder: (context, url) =>
const Center(
child:
CircularProgressIndicator
.adaptive(),
),
),
),
),
);
// Pangea#
itemCount: controller.foundProfiles.length,
itemBuilder: (BuildContext context, int i) =>
_InviteContactListTile(
profile: controller.foundProfiles[i],
isMember: participants.contains(
controller.foundProfiles[i].userId,
),
onTap: () => controller.inviteAction(
context,
controller.foundProfiles[i].userId,
controller.foundProfiles[i].displayName ??
controller
.foundProfiles[i].userId.localpart ??
L10n.of(context).user,
),
),
)
: FutureBuilder<List<User>>(
future: controller.getContacts(context),
builder: (BuildContext context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator.adaptive(
strokeWidth: 2,
),
);
}
return _InviteContactListTile(
// Pangea#
user: contacts[i],
profile: Profile(
avatarUrl: contacts[i].avatarUrl,
displayName: contacts[i].displayName ??
contacts[i].id.localpart ??
L10n.of(context).user,
userId: contacts[i].id,
),
isMember:
participants.contains(contacts[i].id),
onTap: () => controller.inviteAction(
context,
contacts[i].id,
contacts[i].displayName ??
contacts[i].id.localpart ??
L10n.of(context).user,
),
final contacts = snapshot.data!;
return ListView.builder(
// #Pangea
roomPowerLevel: controller.participants
?.firstWhereOrNull(
(element) =>
element.id == contacts[i].id,
)
?.powerLevel,
membership: controller.participants
?.firstWhereOrNull(
(element) =>
element.id == contacts[i].id,
)
?.membership,
// Pangea#
// physics: const NeverScrollableScrollPhysics(),
// shrinkWrap: true,
// itemCount: contacts.length,
// itemBuilder: (BuildContext context, int i) =>
// _InviteContactListTile(
itemCount: contacts.length + 1,
itemBuilder: (BuildContext context, int i) {
if (i == contacts.length) {
final showButtons = controller
.showShareButtons(contacts.length);
return AnimatedOpacity(
duration:
FluffyThemes.animationDuration,
opacity: showButtons ? 1.0 : 0.0,
child: SpaceInviteButtons(room: room),
);
}
return _InviteContactListTile(
// Pangea#
user: contacts[i],
profile: Profile(
avatarUrl: contacts[i].avatarUrl,
displayName: contacts[i].displayName ??
contacts[i].id.localpart ??
L10n.of(context).user,
userId: contacts[i].id,
),
isMember:
participants.contains(contacts[i].id),
onTap: () => controller.inviteAction(
context,
contacts[i].id,
contacts[i].displayName ??
contacts[i].id.localpart ??
L10n.of(context).user,
),
);
},
);
},
);
},
);
},
),
},
),
),
],
),
// #Pangea
if (!room.isSpace)
Padding(
padding: EdgeInsets.only(
left: 8.0,
right: 8.0,
top: 16.0,
bottom: FluffyThemes.isColumnMode(context) ? 0 : 16.0,
Padding(
padding: const EdgeInsets.all(16.0),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: theme.colorScheme.primaryContainer,
elevation: 5.0,
),
child: Row(
spacing: 8.0,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: ElevatedButton(
onPressed: () => showDialog(
context: context,
builder: (context) => FullWidthDialog(
dialogContent: ReferFriendsDialog(room: room),
maxWidth: 600.0,
maxHeight: 800.0,
),
),
style: ElevatedButton.styleFrom(
backgroundColor: AppConfig.gold,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 12.0,
children: [
Icon(
Icons.redeem_outlined,
color: Theme.of(context).brightness ==
Brightness.light
? DefaultTextStyle.of(context).style.color
: Theme.of(context).colorScheme.surface,
),
Text(
L10n.of(context).referFriends,
style: TextStyle(
color: Theme.of(context).brightness ==
Brightness.light
? null
: Theme.of(context).colorScheme.surface,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
Expanded(
child: ElevatedButton(
onPressed: () => context.go("/rooms/${room.id}"),
style: ElevatedButton.styleFrom(),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 12.0,
children: [
Icon(
Icons.chat_outlined,
color: DefaultTextStyle.of(context).style.color,
),
Text(
L10n.of(context).goToChat,
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
],
),
Text(
room.isSpace
? L10n.of(context).goToSpaceButton
: L10n.of(context).goToChat,
style: TextStyle(
color: theme.colorScheme.onPrimaryContainer,
),
),
],
),
onPressed: () => room.isSpace
? context.push("/rooms/${room.id}/details")
: context.go("/rooms/${room.id}"),
),
// Pangea#
),
],
),
),
@ -405,48 +305,19 @@ class _InviteContactListTile extends StatelessWidget {
final User? user;
final bool isMember;
final void Function() onTap;
// #Pangea
final int? roomPowerLevel;
final Membership? membership;
// Pangea#
const _InviteContactListTile({
required this.profile,
this.user,
required this.isMember,
required this.onTap,
// #Pangea
this.roomPowerLevel,
this.membership,
// Pangea#
});
@override
Widget build(BuildContext context) {
// #Pangea
String? permissionCopy() {
if (roomPowerLevel == null) {
return null;
}
return roomPowerLevel! >= 100
? L10n.of(context).admin
: roomPowerLevel! >= 50
? L10n.of(context).moderator
: null;
}
String? membershipCopy() => switch (membership) {
Membership.ban => L10n.of(context).banned,
Membership.invite => L10n.of(context).invited,
Membership.join => null,
Membership.knock => L10n.of(context).knocking,
Membership.leave => L10n.of(context).leftTheChat,
null => null,
};
// final theme = Theme.of(context);
// Pangea#
final theme = Theme.of(context);
final l10n = L10n.of(context);
return ListTile(
@ -464,10 +335,8 @@ class _InviteContactListTile extends StatelessWidget {
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
subtitle:
// #Pangea
LevelDisplayName(userId: profile.userId),
// Text(
// #Pangea
// subtitle: Text(
// profile.userId,
// maxLines: 1,
// overflow: TextOverflow.ellipsis,
@ -475,60 +344,13 @@ class _InviteContactListTile extends StatelessWidget {
// color: theme.colorScheme.secondary,
// ),
// ),
// trailing: TextButton.icon(
// onPressed: isMember ? null : onTap,
// label: Text(isMember ? l10n.participant : l10n.invite),
// icon: Icon(isMember ? Icons.check : Icons.add),
// ),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (membershipCopy() != null)
Container(
padding: const EdgeInsets.all(4),
margin: const EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(
color: theme.secondaryHeaderColor,
borderRadius: BorderRadius.circular(8),
),
child: Text(
membershipCopy()!,
style: theme.textTheme.labelSmall,
),
)
else if (permissionCopy() != null)
Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 6,
),
margin: const EdgeInsets.only(right: 8),
decoration: BoxDecoration(
color: roomPowerLevel! >= 100
? theme.colorScheme.tertiary
: theme.colorScheme.tertiaryContainer,
borderRadius: BorderRadius.circular(
AppConfig.borderRadius,
),
),
child: Text(
permissionCopy()!,
style: theme.textTheme.labelSmall?.copyWith(
color: roomPowerLevel! >= 100
? theme.colorScheme.onTertiary
: theme.colorScheme.onTertiaryContainer,
),
),
)
else if (!isMember || roomPowerLevel == null || roomPowerLevel! < 50)
TextButton.icon(
onPressed: isMember ? null : onTap,
label: Text(isMember ? l10n.participant : l10n.invite),
icon: Icon(isMember ? Icons.check : Icons.add),
),
],
),
subtitle: LevelDisplayName(userId: profile.userId),
// Pangea#
trailing: TextButton.icon(
onPressed: isMember ? null : onTap,
label: Text(isMember ? l10n.participant : l10n.invite),
icon: Icon(isMember ? Icons.check : Icons.add),
),
);
}
}

View file

@ -236,7 +236,10 @@ class NewGroupController extends State<NewGroup> {
room = client.getRoomById(spaceId);
}
if (room == null) return;
GoogleAnalytics.createClass(room.name, room.classCode(context));
final spaceCode = room.classCode(context);
if (spaceCode != null) {
GoogleAnalytics.createClass(room.name, spaceCode);
}
// if a timeout happened, don't redirect to the space
if (error != null) return;

View file

@ -48,31 +48,35 @@ class ClassInvitationButtons extends StatelessWidget {
},
);
final copyCodeListTile = ListTile(
title: Text(
"${L10n.of(context).copyClassCode}: ${room.classCode(context)}",
style: TextStyle(
color: Theme.of(context).colorScheme.secondary,
fontWeight: FontWeight.bold,
final spaceCode = room.classCode(context);
Widget? copyCodeListTile;
if (spaceCode != null) {
copyCodeListTile = ListTile(
title: Text(
"${L10n.of(context).copyClassCode}: $spaceCode",
style: TextStyle(
color: Theme.of(context).colorScheme.secondary,
fontWeight: FontWeight.bold,
),
),
),
subtitle: Text(L10n.of(context).copyClassCodeDesc),
leading: CircleAvatar(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
foregroundColor: Theme.of(context).textTheme.bodyLarge!.color,
child: const Icon(
Icons.copy,
subtitle: Text(L10n.of(context).copyClassCodeDesc),
leading: CircleAvatar(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
foregroundColor: Theme.of(context).textTheme.bodyLarge!.color,
child: const Icon(
Icons.copy,
),
),
),
onTap: () async {
//PTODO-Lala: Standarize toast
//PTODO - explore using Fluffyshare for this
await Clipboard.setData(ClipboardData(text: room.classCode(context)));
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(L10n.of(context).copiedToClipboard)),
);
},
);
onTap: () async {
//PTODO-Lala: Standarize toast
//PTODO - explore using Fluffyshare for this
await Clipboard.setData(ClipboardData(text: spaceCode));
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(L10n.of(context).copiedToClipboard)),
);
},
);
}
// final inviateWithEmailListTile = ListTile(
// enabled: false,
@ -118,7 +122,7 @@ class ClassInvitationButtons extends StatelessWidget {
children: [
// inviteStudentByUserNameTile,
copyClassLinkListTile,
copyCodeListTile,
if (copyCodeListTile != null) copyCodeListTile,
// inviateWithEmailListTile,
// addFromGoogleClassooomListTile,
],

View file

@ -0,0 +1,137 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';
import 'package:universal_html/html.dart' as html;
import 'package:fluffychat/pangea/common/config/environment.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
import 'package:fluffychat/pangea/spaces/constants/space_constants.dart';
class SpaceInviteButtons extends StatefulWidget {
final Room room;
// final ScrollController scrollController;
const SpaceInviteButtons({
super.key,
required this.room,
// required this.scrollController,
});
@override
SpaceInviteButtonsController createState() => SpaceInviteButtonsController();
}
class SpaceInviteButtonsController extends State<SpaceInviteButtons> {
// bool get isVisible {
// final context = (widget.key as GlobalKey).currentContext;
// if (context == null) return false;
// final renderBox = context.findRenderObject() as RenderBox;
// final position = renderBox.localToGlobal(Offset.zero);
// final size = renderBox.size;
// final screenHeight = MediaQuery.of(context).size.height;
// debugPrint("position: $position, size: $size, screenHeight: $screenHeight");
// // Check if any part of the widget is within the visible range
// return position.dy + size.height > 0 && position.dy < screenHeight;
// }
@override
void initState() {
// WidgetsBinding.instance.addPostFrameCallback(
// (_) => debugPrint("isVisible: $isVisible"),
// );
super.initState();
}
@override
Widget build(BuildContext context) {
final spaceCode = widget.room.classCode(context);
if (spaceCode == null) {
return const SizedBox.shrink();
}
return SizedBox(
height: 150.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(
top: 16.0,
right: 16.0,
left: 16.0,
),
child: ElevatedButton(
child: Row(
spacing: 8.0,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.share_outlined,
),
Text(L10n.of(context).shareSpaceLink),
],
),
onPressed: () async {
final String initialUrl =
kIsWeb ? html.window.origin! : Environment.frontendURL;
final link =
"$initialUrl/#/join_with_link?${SpaceConstants.classCode}=$spaceCode";
await Clipboard.setData(
ClipboardData(
text: link,
),
);
ScaffoldMessenger.of(
context,
).showSnackBar(
SnackBar(
content: Text(
L10n.of(context).copiedToClipboard,
),
),
);
},
),
),
Padding(
padding: const EdgeInsets.only(
top: 16.0,
right: 16.0,
left: 16.0,
),
child: ElevatedButton(
child: Row(
spacing: 8.0,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.share_outlined,
),
Text(L10n.of(context).shareInviteCode(spaceCode)),
],
),
onPressed: () async {
await Clipboard.setData(ClipboardData(text: spaceCode));
ScaffoldMessenger.of(
context,
).showSnackBar(
SnackBar(
content: Text(
L10n.of(context).copiedToClipboard,
),
),
);
},
),
),
],
),
);
}
}

View file

@ -1,14 +1,14 @@
part of "pangea_room_extension.dart";
extension SpaceRoomExtension on Room {
String classCode(BuildContext context) {
String? classCode(BuildContext context) {
if (!isSpace) {
for (final Room potentialClassRoom in pangeaSpaceParents) {
if (potentialClassRoom.isSpace) {
return SpaceRoomExtension(potentialClassRoom).classCode(context);
}
}
return L10n.of(context).notInClass;
return null;
}
final roomJoinRules = getState(EventTypes.RoomJoinRules, "");
if (roomJoinRules != null) {
@ -17,7 +17,7 @@ extension SpaceRoomExtension on Room {
return accessCode;
}
}
return L10n.of(context).noClassCode;
return null;
}
void checkClass() {