refactor: new invite page design (#2763)
This commit is contained in:
parent
6f71dd4e95
commit
b41d572698
8 changed files with 437 additions and 429 deletions
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
],
|
||||
|
|
|
|||
137
lib/pangea/chat_settings/widgets/space_invite_buttons.dart
Normal file
137
lib/pangea/chat_settings/widgets/space_invite_buttons.dart
Normal 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,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -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() {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue