refactor: invite page redesign (#2186)
This commit is contained in:
parent
af923d67bf
commit
fae97c0ab2
5 changed files with 487 additions and 140 deletions
|
|
@ -4813,5 +4813,9 @@
|
|||
"pleaseEnterInt": "Please enter a number",
|
||||
"home": "Home",
|
||||
"join": "Join",
|
||||
"learnByTexting": "Learn by texting"
|
||||
"learnByTexting": "Learn by texting",
|
||||
"startChatting": "Start chatting",
|
||||
"referFriends": "Refer friends",
|
||||
"referFriendDialogTitle": "Invite a friend to your conversation",
|
||||
"referFriendDialogDesc": "Do you have a friend who is excited to learn a new language with you? Then copy and send this invitation link to join and start chatting with you today."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,13 +34,82 @@ class InvitationSelectionController extends State<InvitationSelection> {
|
|||
|
||||
String? get roomId => widget.roomId;
|
||||
|
||||
// #Pangea
|
||||
List<User>? get participants {
|
||||
final room = Matrix.of(context).client.getRoomById(roomId!);
|
||||
return room?.getParticipants();
|
||||
}
|
||||
|
||||
List<Membership> get _membershipOrder => [
|
||||
Membership.join,
|
||||
Membership.invite,
|
||||
Membership.knock,
|
||||
Membership.leave,
|
||||
Membership.ban,
|
||||
];
|
||||
|
||||
String? membershipCopy(Membership? membership) => 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,
|
||||
};
|
||||
|
||||
int _sortUsers(User a, User b) {
|
||||
// sort yourself to the top
|
||||
final client = Matrix.of(context).client;
|
||||
if (a.id == client.userID) return -1;
|
||||
if (b.id == client.userID) return 1;
|
||||
|
||||
// sort the bot to the bottom
|
||||
if (a.id == BotName.byEnvironment) return 1;
|
||||
if (b.id == BotName.byEnvironment) return -1;
|
||||
|
||||
if (participants != null) {
|
||||
final participantA = participants!.firstWhereOrNull((u) => u.id == a.id);
|
||||
final participantB = participants!.firstWhereOrNull((u) => u.id == b.id);
|
||||
// sort all participants first, with admins first, then moderators, then the rest
|
||||
if (participantA?.membership == null &&
|
||||
participantB?.membership != null) {
|
||||
return 1;
|
||||
}
|
||||
if (participantA?.membership != null &&
|
||||
participantB?.membership == null) {
|
||||
return -1;
|
||||
}
|
||||
if (participantA?.membership != null &&
|
||||
participantB?.membership != null) {
|
||||
final aIndex = _membershipOrder.indexOf(participantA!.membership);
|
||||
final bIndex = _membershipOrder.indexOf(participantB!.membership);
|
||||
if (aIndex != bIndex) {
|
||||
return aIndex.compareTo(bIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// finally, sort by displayname
|
||||
final aName = a.calcDisplayname().toLowerCase();
|
||||
final bName = b.calcDisplayname().toLowerCase();
|
||||
return aName.compareTo(bName);
|
||||
}
|
||||
// Pangea#
|
||||
|
||||
Future<List<User>> getContacts(BuildContext context) async {
|
||||
final client = Matrix.of(context).client;
|
||||
final room = client.getRoomById(roomId!)!;
|
||||
|
||||
final participants = (room.summary.mJoinedMemberCount ?? 0) > 100
|
||||
? room.getParticipants()
|
||||
: await room.requestParticipants();
|
||||
// #Pangea
|
||||
// : await room.requestParticipants();
|
||||
: await room.requestParticipants(
|
||||
[Membership.join, Membership.invite, Membership.knock],
|
||||
false,
|
||||
true,
|
||||
);
|
||||
// Pangea#
|
||||
participants.removeWhere(
|
||||
(u) => ![Membership.join, Membership.invite].contains(u.membership),
|
||||
);
|
||||
|
|
@ -53,16 +122,26 @@ class InvitationSelectionController extends State<InvitationSelection> {
|
|||
.getParticipants()
|
||||
.firstWhereOrNull((u) => u.id != client.userID),
|
||||
)
|
||||
.where((u) => u != null)
|
||||
.cast<User>()
|
||||
// Pangea#
|
||||
.toList();
|
||||
// #Pangea
|
||||
contacts.removeWhere((u) => u == null || u.id != BotName.byEnvironment);
|
||||
contacts.sort(
|
||||
(a, b) => a!.calcDisplayname().toLowerCase().compareTo(
|
||||
b!.calcDisplayname().toLowerCase(),
|
||||
),
|
||||
);
|
||||
return contacts.cast<User>();
|
||||
final mutuals = client.rooms
|
||||
.where((r) => r.isSpace)
|
||||
.map((r) => r.getParticipants())
|
||||
.expand((element) => element)
|
||||
.toList();
|
||||
|
||||
for (final user in mutuals) {
|
||||
final index = contacts.indexWhere((u) => u.id == user.id);
|
||||
if (index == -1) {
|
||||
contacts.add(user);
|
||||
}
|
||||
}
|
||||
|
||||
contacts.sort(_sortUsers);
|
||||
return contacts;
|
||||
// contacts.sort(
|
||||
// (a, b) => a.calcDisplayname().toLowerCase().compareTo(
|
||||
// b.calcDisplayname().toLowerCase(),
|
||||
|
|
@ -72,72 +151,6 @@ class InvitationSelectionController extends State<InvitationSelection> {
|
|||
//Pangea#
|
||||
}
|
||||
|
||||
//#Pangea
|
||||
// // add all students (already local) from spaceParents who aren't already in room to eligibleStudents
|
||||
// // use room.members to get all users in room
|
||||
// bool _initialized = false;
|
||||
// Future<List<User>> eligibleStudents(
|
||||
// BuildContext context,
|
||||
// String text,
|
||||
// ) async {
|
||||
// if (!_initialized) {
|
||||
// _initialized = true;
|
||||
// await requestParentSpaceParticipants();
|
||||
// }
|
||||
|
||||
// final eligibleStudents = <User>[];
|
||||
// final spaceParents = room?.pangeaSpaceParents;
|
||||
// if (spaceParents == null) return eligibleStudents;
|
||||
|
||||
// final userId = Matrix.of(context).client.userID;
|
||||
// for (final Room space in spaceParents) {
|
||||
// eligibleStudents.addAll(
|
||||
// space.getParticipants().where(
|
||||
// (spaceUser) =>
|
||||
// spaceUser.id != BotName.byEnvironment &&
|
||||
// spaceUser.id != "@support:staging.pangea.chat" &&
|
||||
// spaceUser.id != userId &&
|
||||
// (text.isEmpty ||
|
||||
// (spaceUser.displayName
|
||||
// ?.toLowerCase()
|
||||
// .contains(text.toLowerCase()) ??
|
||||
// false) ||
|
||||
// spaceUser.id.toLowerCase().contains(text.toLowerCase())),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// return eligibleStudents;
|
||||
// }
|
||||
|
||||
// Future<SearchUserDirectoryResponse>
|
||||
// eligibleStudentsAsSearchUserDirectoryResponse(
|
||||
// BuildContext context,
|
||||
// String text,
|
||||
// ) async {
|
||||
// return SearchUserDirectoryResponse(
|
||||
// results: (await eligibleStudents(context, text))
|
||||
// .map(
|
||||
// (e) => Profile(
|
||||
// userId: e.id,
|
||||
// avatarUrl: e.avatarUrl,
|
||||
// displayName: e.displayName,
|
||||
// ),
|
||||
// )
|
||||
// .toList(),
|
||||
// limited: false,
|
||||
// );
|
||||
// }
|
||||
|
||||
// List<User?> studentsInRoom(BuildContext context) =>
|
||||
// room
|
||||
// ?.getParticipants()
|
||||
// .where(
|
||||
// (u) => [Membership.join, Membership.invite].contains(u.membership),
|
||||
// )
|
||||
// .toList() ??
|
||||
// <User>[];
|
||||
//Pangea#
|
||||
|
||||
void inviteAction(BuildContext context, String id, String displayname) async {
|
||||
final room = Matrix.of(context).client.getRoomById(roomId!)!;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,19 @@
|
|||
import 'package:flutter/material.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';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pages/invitation_selection/invitation_selection.dart';
|
||||
import 'package:fluffychat/pages/user_bottom_sheet/user_bottom_sheet.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/common/widgets/full_width_dialog.dart';
|
||||
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
|
||||
import 'package:fluffychat/widgets/avatar.dart';
|
||||
import 'package:fluffychat/widgets/layouts/max_width_body.dart';
|
||||
|
|
@ -42,10 +51,20 @@ class InvitationSelectionView extends StatelessWidget {
|
|||
),
|
||||
body: MaxWidthBody(
|
||||
innerPadding: const EdgeInsets.symmetric(vertical: 8),
|
||||
// #Pangea
|
||||
withScrolling: false,
|
||||
// Pangea#
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
// #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(
|
||||
|
|
@ -81,70 +100,200 @@ class InvitationSelectionView extends StatelessWidget {
|
|||
onChanged: controller.searchUserWithCoolDown,
|
||||
),
|
||||
),
|
||||
StreamBuilder<Object>(
|
||||
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(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
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,
|
||||
// #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: CircularProgressIndicator.adaptive(
|
||||
strokeWidth: 2,
|
||||
),
|
||||
);
|
||||
}
|
||||
final contacts = snapshot.data!;
|
||||
return 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(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
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
|
||||
roomPowerLevel: controller.participants
|
||||
?.firstWhereOrNull(
|
||||
(element) =>
|
||||
element.id == contacts[i].id,
|
||||
)
|
||||
?.powerLevel,
|
||||
membership: controller.participants
|
||||
?.firstWhereOrNull(
|
||||
(element) =>
|
||||
element.id == contacts[i].id,
|
||||
)
|
||||
?.membership,
|
||||
// Pangea#
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
// #Pangea
|
||||
if (!room.isSpace)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: 8.0,
|
||||
right: 8.0,
|
||||
top: 16.0,
|
||||
bottom: FluffyThemes.isColumnMode(context) ? 0 : 16.0,
|
||||
),
|
||||
child: Row(
|
||||
spacing: 8.0,
|
||||
children: [
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
onPressed: () => showDialog(
|
||||
context: context,
|
||||
builder: (context) => FullWidthDialog(
|
||||
dialogContent: ReferFriendsDialog(room: room),
|
||||
maxWidth: 600.0,
|
||||
maxHeight: 800.0,
|
||||
),
|
||||
),
|
||||
)
|
||||
: FutureBuilder<List<User>>(
|
||||
future: controller.getContacts(context),
|
||||
builder: (BuildContext context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator.adaptive(
|
||||
strokeWidth: 2,
|
||||
),
|
||||
);
|
||||
}
|
||||
final contacts = snapshot.data!;
|
||||
return ListView.builder(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
itemCount: contacts.length,
|
||||
itemBuilder: (BuildContext context, int i) =>
|
||||
_InviteContactListTile(
|
||||
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,
|
||||
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).startChatting,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Pangea#
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
@ -157,16 +306,47 @@ 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,
|
||||
};
|
||||
// Pangea#
|
||||
|
||||
final theme = Theme.of(context);
|
||||
final l10n = L10n.of(context);
|
||||
|
||||
|
|
@ -197,11 +377,62 @@ 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),
|
||||
// #Pangea
|
||||
// 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: [
|
||||
LevelDisplayName(userId: profile.userId),
|
||||
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),
|
||||
),
|
||||
],
|
||||
),
|
||||
// Pangea#
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
class RoomSettingsConstants {
|
||||
static const String referFriendAsset = "Refer+a+friend.png";
|
||||
static const String referFriendDialogAsset = "Refer+a+friend_2.png";
|
||||
}
|
||||
95
lib/pangea/chat_settings/widgets/refer_friends_dialog.dart
Normal file
95
lib/pangea/chat_settings/widgets/refer_friends_dialog.dart
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/chat_settings/constants/room_settings_constants.dart';
|
||||
import 'package:fluffychat/pangea/common/config/environment.dart';
|
||||
|
||||
class ReferFriendsDialog extends StatelessWidget {
|
||||
final Room room;
|
||||
|
||||
const ReferFriendsDialog({
|
||||
required this.room,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final inviteLink =
|
||||
"${Environment.frontendURL}/#/join_with_alias?alias=${Uri.encodeComponent(room.id)}";
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
borderRadius: BorderRadius.circular(20.0),
|
||||
border: Border.all(
|
||||
color: Theme.of(context).colorScheme.primary.withAlpha(50),
|
||||
width: 0.5,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
spacing: 16.0,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: SizedBox(
|
||||
width: 450,
|
||||
child: CachedNetworkImage(
|
||||
imageUrl:
|
||||
"${AppConfig.assetsBaseURL}/${RoomSettingsConstants.referFriendDialogAsset}",
|
||||
errorWidget: (context, url, error) => const SizedBox(),
|
||||
placeholder: (context, url) => const Center(
|
||||
child: CircularProgressIndicator.adaptive(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
L10n.of(context).referFriendDialogTitle,
|
||||
style: Theme.of(context).textTheme.displaySmall?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
L10n.of(context).referFriendDialogDesc,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
Material(
|
||||
color: Colors.transparent, // Keeps the `Container`'s background
|
||||
child: ListTile(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(24.0),
|
||||
side: BorderSide(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
title: Text(
|
||||
inviteLink,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
trailing: const Icon(Icons.copy_outlined),
|
||||
onTap: () async {
|
||||
Clipboard.setData(
|
||||
ClipboardData(text: inviteLink),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue