Merge branch 'main' into span-card-hotfix

pull/1183/head
ggurdin 1 year ago committed by GitHub
commit 6dbff017d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -3708,7 +3708,7 @@
},
"noTeachersFound": "No teachers found to report to",
"pleaseEnterANumber": "Please enter a number greater than 0",
"archiveRoomDescription": "The chat will be moved to the archive. Other users will be able to see that you have left the chat.",
"archiveRoomDescription": "The chat will be moved to the archive for yourself and other non-admin users.",
"roomUpgradeDescription": "The chat will then be recreated with the new room version. All participants will be notified that they need to switch to the new chat. You can find out more about room versions at https://spec.matrix.org/latest/rooms/",
"removeDevicesDescription": "You will be logged out of this device and will no longer be able to receive messages.",
"banUserDescription": "The user will be banned from the chat and will not be able to enter the chat again until they are unbanned.",
@ -3947,5 +3947,12 @@
"studentAnalyticsNotAvailable": "Student data not currently available",
"roomDataMissing": "Some data may be missing from rooms in which you are not a member.",
"updatePhoneOS": "You may need to update your device's OS version.",
"wordsPerMinute": "Words per minute"
"wordsPerMinute": "Words per minute",
"leaveRoomDescription": "The chat will be moved to the archive. Other users will be able to see that you have left the chat.",
"archiveSpaceDescription": "All chats within this space will be moved to the archive for yourself and other non-admin users.",
"leaveSpaceDescription": "All chats within this space will be moved to the archive. Other users will be able to see that you have left the space.",
"onlyAdminDescription": "Since there are no other admins, all other participants will also be removed.",
"tooltipInstructionsTitle": "Not sure what that does?",
"tooltipInstructionsMobileBody": "Press and hold items to view tooltips.",
"tooltipInstructionsBrowserBody": "Hover over items to view tooltips."
}

@ -3698,7 +3698,7 @@
"@optionalRedactReason": {},
"dehydrate": "Exportar sesión y borrar dispositivo",
"@dehydrate": {},
"archiveRoomDescription": "",
"archiveRoomDescription": "El chat se moverá al archivo para ti y para otros usuarios que no sean administradores",
"@archiveRoomDescription": {},
"pleaseEnterRecoveryKeyDescription": "Para desbloquear sus mensajes antiguos, ingrese su clave de recuperación que se generó en una sesión anterior. Su clave de recuperación NO es su contraseña.",
"@pleaseEnterRecoveryKeyDescription": {},

@ -228,6 +228,17 @@ class ChatController extends State<ChatPageWithRoom>
context.go('/rooms');
}
// #Pangea
void archiveChat() async {
final success = await showFutureLoadingDialog(
context: context,
future: room.archive,
);
if (success.error != null) return;
context.go('/rooms');
}
// Pangea#
EmojiPickerType emojiPickerType = EmojiPickerType.keyboard;
// #Pangea

@ -367,6 +367,29 @@ class ChatView extends StatelessWidget {
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: [
// #Pangea
if (controller.room.isRoomAdmin)
TextButton.icon(
style: TextButton.styleFrom(
padding:
const EdgeInsets.all(
16,
),
foregroundColor:
Theme.of(context)
.colorScheme
.error,
),
icon: const Icon(
Icons.archive_outlined,
),
onPressed:
controller.archiveChat,
label: Text(
L10n.of(context)!.archive,
),
),
// Pangea#
TextButton.icon(
style: TextButton.styleFrom(
padding: const EdgeInsets.all(
@ -378,7 +401,10 @@ class ChatView extends StatelessWidget {
.error,
),
icon: const Icon(
Icons.archive_outlined,
// #Pangea
// Icons.archive_outlined,
Icons.arrow_forward,
// Pangea#
),
onPressed: controller.leaveChat,
label: Text(

@ -9,7 +9,6 @@ import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_det
import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_invitation_buttons.dart';
import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_name_button.dart';
import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/room_rules_editor.dart';
import 'package:fluffychat/pangea/utils/archive_space.dart';
import 'package:fluffychat/pangea/utils/lock_room.dart';
import 'package:fluffychat/pangea/widgets/class/add_class_and_invite.dart';
import 'package:fluffychat/pangea/widgets/class/add_space_toggles.dart';
@ -522,52 +521,126 @@ class ChatDetailsView extends StatelessWidget {
),
const Divider(height: 1),
if (!room.isDirectChat)
ListTile(
title: Text(
room.isSpace
? L10n.of(context)!.archiveSpace
: L10n.of(context)!.archive,
style: TextStyle(
color: Theme.of(context).colorScheme.secondary,
fontWeight: FontWeight.bold,
if (room.isRoomAdmin)
ListTile(
title: Text(
room.isSpace
? L10n.of(context)!.archiveSpace
: L10n.of(context)!.archive,
style: TextStyle(
color:
Theme.of(context).colorScheme.secondary,
fontWeight: FontWeight.bold,
),
),
),
leading: CircleAvatar(
backgroundColor:
Theme.of(context).scaffoldBackgroundColor,
foregroundColor: iconColor,
child: const Icon(
Icons.archive_outlined,
leading: CircleAvatar(
backgroundColor:
Theme.of(context).scaffoldBackgroundColor,
foregroundColor: iconColor,
child: const Icon(
Icons.archive_outlined,
),
),
onTap: () async {
OkCancelResult confirmed = OkCancelResult.ok;
bool shouldGo = false;
// archiveSpace has its own popup; only show if not space
if (!room.isSpace) {
confirmed = await showOkCancelAlertDialog(
useRootNavigator: false,
context: context,
title: L10n.of(context)!.areYouSure,
okLabel: L10n.of(context)!.ok,
cancelLabel: L10n.of(context)!.cancel,
message: L10n.of(context)!
.archiveRoomDescription,
);
}
if (confirmed == OkCancelResult.ok) {
if (room.isSpace) {
shouldGo = await room.archiveSpace(
context,
Matrix.of(context).client,
);
} else {
final success =
await showFutureLoadingDialog(
context: context,
future: () async {
await room.archive();
},
);
shouldGo = (success.error == null);
}
if (shouldGo) {
context.go('/rooms');
}
}
},
),
onTap: () async {
final confirmed = await showOkCancelAlertDialog(
ListTile(
title: Text(
L10n.of(context)!.leave,
style: TextStyle(
color: Theme.of(context).colorScheme.secondary,
fontWeight: FontWeight.bold,
),
),
leading: CircleAvatar(
backgroundColor:
Theme.of(context).scaffoldBackgroundColor,
foregroundColor: iconColor,
child: const Icon(
Icons.arrow_forward,
),
),
onTap: () async {
OkCancelResult confirmed = OkCancelResult.ok;
bool shouldGo = false;
// If user is only admin, room will be archived
final bool onlyAdmin = await room.isOnlyAdmin();
// archiveSpace has its own popup; only show if not space
if (!room.isSpace) {
confirmed = await showOkCancelAlertDialog(
useRootNavigator: false,
context: context,
title: L10n.of(context)!.areYouSure,
okLabel: L10n.of(context)!.ok,
cancelLabel: L10n.of(context)!.cancel,
message:
L10n.of(context)!.archiveRoomDescription,
message: onlyAdmin
? L10n.of(context)!.onlyAdminDescription
: L10n.of(context)!.leaveRoomDescription,
);
if (confirmed == OkCancelResult.ok) {
}
if (confirmed == OkCancelResult.ok) {
if (room.isSpace) {
shouldGo = onlyAdmin
? await room.archiveSpace(
context,
Matrix.of(context).client,
onlyAdmin: true,
)
: await room.leaveSpace(
context,
Matrix.of(context).client,
);
} else {
final success = await showFutureLoadingDialog(
context: context,
future: () async {
room.isSpace
? await archiveSpace(
room,
Matrix.of(context).client,
)
onlyAdmin
? await room.archive()
: await room.leave();
},
);
if (success.error == null) {
context.go('/rooms');
}
shouldGo = (success.error == null);
}
},
),
if (shouldGo) {
context.go('/rooms');
}
}
},
),
if (room.isRoomAdmin && !room.isDirectChat)
SwitchListTile.adaptive(
activeColor: AppConfig.activeToggleColor,

@ -515,7 +515,8 @@ class ChatListController extends State<ChatList>
//#Pangea
classStream = pangeaController.classController.stateStream.listen((event) {
if (event["activeSpaceId"] != null && mounted) {
// if (event["activeSpaceId"] != null && mounted) {
if (mounted) {
setActiveSpace(event["activeSpaceId"]);
}
});
@ -679,6 +680,38 @@ class ChatListController extends State<ChatList>
// Pangea#
}
// #Pangea
Future<void> leaveAction() async {
final bool onlyAdmin = await Matrix.of(context)
.client
.getRoomById(selectedRoomIds.first)
?.isOnlyAdmin() ??
false;
final confirmed = await showOkCancelAlertDialog(
useRootNavigator: false,
context: context,
title: L10n.of(context)!.areYouSure,
okLabel: L10n.of(context)!.yes,
cancelLabel: L10n.of(context)!.cancel,
message: onlyAdmin
? L10n.of(context)!.onlyAdminDescription
: L10n.of(context)!.leaveRoomDescription,
) ==
OkCancelResult.ok;
if (!confirmed) return;
final bool leftActiveRoom =
selectedRoomIds.contains(Matrix.of(context).activeRoomId);
await showFutureLoadingDialog(
context: context,
future: () => _leaveSelectedRooms(onlyAdmin),
);
setState(() {});
if (leftActiveRoom) {
context.go('/rooms');
}
}
// Pangea#
void dismissStatusList() async {
final result = await showOkCancelAlertDialog(
title: L10n.of(context)!.hidePresences,
@ -729,17 +762,35 @@ class ChatListController extends State<ChatList>
final roomId = selectedRoomIds.first;
try {
// #Pangea
if (client.getRoomById(roomId)!.isUnread) {
await client.getRoomById(roomId)!.markUnread(false);
}
// await client.getRoomById(roomId)!.leave();
await client.getRoomById(roomId)!.archive();
// Pangea#
await client.getRoomById(roomId)!.leave();
} finally {
toggleSelection(roomId);
}
}
}
// #Pangea
Future<void> _leaveSelectedRooms(bool onlyAdmin) async {
final client = Matrix.of(context).client;
while (selectedRoomIds.isNotEmpty) {
final roomId = selectedRoomIds.first;
try {
final room = client.getRoomById(roomId);
if (!room!.isSpace &&
room.membership == Membership.join &&
room.isUnread) {
await room.markUnread(false);
}
onlyAdmin ? await room.archive() : await room.leave();
} finally {
toggleSelection(roomId);
}
}
}
// Pangea#
Future<void> addToSpace() async {
final selectedSpace = await showConfirmationDialog<String>(
context: context,

@ -1,6 +1,8 @@
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pages/chat_list/chat_list.dart';
import 'package:fluffychat/pages/chat_list/client_chooser_button.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
@ -168,14 +170,33 @@ class ChatListHeader extends StatelessWidget implements PreferredSizeWidget {
tooltip: L10n.of(context)!.toggleMuted,
onPressed: controller.toggleMuted,
),
IconButton(
// #Pangea
// icon: const Icon(Icons.delete_outlined),
icon: const Icon(Icons.archive_outlined),
// #Pangea
if (controller.selectedRoomIds.length == 1 &&
!(Matrix.of(context)
.client
.getRoomById(controller.selectedRoomIds.single)
?.isRoomAdmin ??
false))
IconButton(
icon: const Icon(Icons.arrow_forward),
tooltip: L10n.of(context)!.leave,
onPressed: controller.leaveAction,
),
if (controller.selectedRoomIds.length == 1 &&
(Matrix.of(context)
.client
.getRoomById(controller.selectedRoomIds.single)
?.isRoomAdmin ??
false))
// Pangea#
tooltip: L10n.of(context)!.archive,
onPressed: controller.archiveAction,
),
IconButton(
// #Pangea
// icon: const Icon(Icons.delete_outlined),
icon: const Icon(Icons.archive_outlined),
// Pangea#
tooltip: L10n.of(context)!.archive,
onPressed: controller.archiveAction,
),
]
: null,
);

@ -53,14 +53,12 @@ class ChatListItem extends StatelessWidget {
message: L10n.of(context)!.archiveRoomDescription,
);
if (confirmed == OkCancelResult.cancel) return;
// #Pangea
if (room.isUnread) {
await room.markUnread(false);
}
// Pangea#
await showFutureLoadingDialog(
context: context,
future: () => room.leave(),
// #Pangea
// future: () => room.leave(),
future: () => room.archive(),
// Pangea#
);
return;
}

@ -11,7 +11,6 @@ import 'package:fluffychat/pangea/constants/class_default_values.dart';
import 'package:fluffychat/pangea/constants/pangea_room_types.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart';
import 'package:fluffychat/pangea/extensions/sync_update_extension.dart';
import 'package:fluffychat/pangea/utils/archive_space.dart';
import 'package:fluffychat/pangea/utils/chat_list_handle_space_tap.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
import 'package:fluffychat/widgets/avatar.dart';
@ -230,7 +229,10 @@ class _SpaceViewState extends State<SpaceView> {
),
message: spaceChild?.topic ?? room?.topic,
actions: [
if (room == null)
// #Pangea
// if (room == null)
if (room == null || room.membership == Membership.leave)
// Pangea#
SheetAction(
key: SpaceChildContextAction.join,
label: L10n.of(context)!.joinRoom,
@ -255,16 +257,21 @@ class _SpaceViewState extends State<SpaceView> {
label: L10n.of(context)!.addToSpace,
icon: Icons.workspaces_outlined,
),
if (room != null && room.isRoomAdmin)
if (room != null &&
room.isRoomAdmin &&
room.membership != Membership.leave)
SheetAction(
key: SpaceChildContextAction.archive,
label: room.isSpace
? L10n.of(context)!.archiveSpace
: L10n.of(context)!.archive,
icon: Icons.architecture_outlined,
isDestructiveAction: true,
),
// Pangea#
if (room != null)
if (room != null && room.membership != Membership.leave)
// if (room != null)
// Pangea#
SheetAction(
key: SpaceChildContextAction.leave,
label: L10n.of(context)!.leave,
@ -283,22 +290,32 @@ class _SpaceViewState extends State<SpaceView> {
_onJoinSpaceChild(spaceChild!);
break;
case SpaceChildContextAction.leave:
await showFutureLoadingDialog(
context: context,
// #Pangea
// future: room!.leave,
future: () async {
if (room!.isUnread) {
await room.markUnread(false);
}
await room.leave();
if (Matrix.of(context).activeRoomId == room.id) {
context.go('/rooms');
}
},
// Pangea#
);
// #Pangea
widget.controller.cancelAction();
if (room == null) return;
if (room.isSpace) {
await room.isOnlyAdmin()
? await room.archiveSpace(
context,
Matrix.of(context).client,
onlyAdmin: true,
)
: await room.leaveSpace(
context,
Matrix.of(context).client,
);
} else {
widget.controller.toggleSelection(room.id);
await widget.controller.leaveAction();
}
_refresh();
break;
// await showFutureLoadingDialog(
// context: context,
// future: room!.leave,
// );
// break;
// Pangea#
case SpaceChildContextAction.removeFromSpace:
await showFutureLoadingDialog(
context: context,
@ -310,20 +327,27 @@ class _SpaceViewState extends State<SpaceView> {
widget.controller.cancelAction();
// #Pangea
if (room == null) return;
// room.isSpace
// ? await showFutureLoadingDialog(
// context: context,
// future: () async {
// await room.archiveSpace(
// Matrix.of(context).client,
// );
// widget.controller.selectedRoomIds.clear();
// },
// )
// : await widget.controller.archiveAction();
if (room.isSpace) {
await room.archiveSpace(
context,
Matrix.of(context).client,
);
} else {
widget.controller.toggleSelection(room.id);
await widget.controller.archiveAction();
}
// Pangea#
widget.controller.toggleSelection(room.id);
room.isSpace
? await showFutureLoadingDialog(
context: context,
future: () async {
await archiveSpace(
room,
Matrix.of(context).client,
);
widget.controller.selectedRoomIds.clear();
},
)
: await widget.controller.archiveAction();
_refresh();
break;
case SpaceChildContextAction.addToSpace:
@ -333,8 +357,10 @@ class _SpaceViewState extends State<SpaceView> {
// Pangea#
widget.controller.toggleSelection(room.id);
await widget.controller.addToSpace();
// #Pangea
setState(() => widget.controller.selectedRoomIds.clear());
// Pangea#
break;
// Pangea#
}
}

@ -46,7 +46,9 @@ void onChatTap(Room room, BuildContext context) async {
}
if (inviteAction == InviteActions.decline) {
// #Pangea
if (room.isUnread) {
if (!room.isSpace &&
room.membership == Membership.join &&
room.isUnread) {
await room.markUnread(false);
}
// Pangea#

@ -27,7 +27,7 @@ class ClassController extends BaseController {
_pangeaController = pangeaController;
}
setActiveSpaceIdInChatListController(String classId) {
setActiveSpaceIdInChatListController(String? classId) {
setState(data: {"activeSpaceId": classId});
}

@ -232,6 +232,7 @@ class UserController extends BaseController {
bool? showedItInstructions,
bool? showedClickMessage,
bool? showedBlurMeansTranslate,
bool? showedTooltipInstructions,
String? createdAt,
String? targetLanguage,
String? sourceLanguage,
@ -304,6 +305,12 @@ class UserController extends BaseController {
showedBlurMeansTranslate,
);
}
if (showedTooltipInstructions != null) {
await _pangeaController.pStoreService.save(
MatrixProfile.showedTooltipInstructions.title,
showedTooltipInstructions,
);
}
if (createdAt != null) {
await _pangeaController.pStoreService.save(
MatrixProfile.createdAt.title,

@ -71,8 +71,8 @@ extension ClassAndExchangeSettingsRoomExtension on Room {
}
final spaceChildPower =
currentPowerContent["events"][EventTypes.spaceChild];
final studentAnalyticsPower =
currentPowerContent[PangeaEventTypes.studentAnalyticsSummary];
final studentAnalyticsPower = currentPowerContent["events"]
[PangeaEventTypes.studentAnalyticsSummary];
if ((spaceChildPower == null || studentAnalyticsPower == null)) {
currentPowerContent["events"][EventTypes.spaceChild] = 0;

@ -1,6 +1,102 @@
part of "pangea_room_extension.dart";
extension EventsRoomExtension on Room {
Future<void> _archive() async {
final students = (await requestParticipants())
.where(
(e) =>
e.id != client.userID &&
e.powerLevel < ClassDefaultValues.powerLevelOfAdmin &&
e.id != BotName.byEnvironment,
)
.toList();
try {
for (final student in students) {
await kick(student.id);
}
if (!isSpace && membership == Membership.join && isUnread) {
await markUnread(false);
}
await leave();
} catch (err, s) {
debugger(when: kDebugMode);
ErrorHandler.logError(e: err, s: s, data: toJson());
}
}
Future<bool> _archiveSpace(
BuildContext context,
Client client, {
bool onlyAdmin = false,
}) async {
final confirmed = await showOkCancelAlertDialog(
useRootNavigator: false,
context: context,
title: L10n.of(context)!.areYouSure,
okLabel: L10n.of(context)!.yes,
cancelLabel: L10n.of(context)!.cancel,
message: onlyAdmin
? L10n.of(context)!.onlyAdminDescription
: L10n.of(context)!.archiveSpaceDescription,
) ==
OkCancelResult.ok;
if (!confirmed) return false;
final success = await showFutureLoadingDialog(
context: context,
future: () async {
final List<Room> children = await getChildRooms();
for (final Room child in children) {
await child.archive();
}
await archive();
},
);
MatrixState.pangeaController.classController
.setActiveSpaceIdInChatListController(
null,
);
return success.error == null;
}
Future<bool> _leaveSpace(BuildContext context, Client client) async {
final confirmed = await showOkCancelAlertDialog(
useRootNavigator: false,
context: context,
title: L10n.of(context)!.areYouSure,
okLabel: L10n.of(context)!.yes,
cancelLabel: L10n.of(context)!.cancel,
message: L10n.of(context)!.leaveSpaceDescription,
) ==
OkCancelResult.ok;
if (!confirmed) return false;
final success = await showFutureLoadingDialog(
context: context,
future: () async {
try {
final List<Room> children = await getChildRooms();
for (final Room child in children) {
if (!child.isSpace &&
child.membership == Membership.join &&
child.isUnread) {
await child.markUnread(false);
}
await child.leave();
}
await leave();
} catch (err, stack) {
debugger(when: kDebugMode);
ErrorHandler.logError(e: err, s: stack, data: powerLevels);
rethrow;
}
},
);
MatrixState.pangeaController.classController
.setActiveSpaceIdInChatListController(
null,
);
return success.error == null;
}
Future<Event?> _sendPangeaEvent({
required Map<String, dynamic> content,
required String parentEventId,

@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:developer';
import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:collection/collection.dart';
import 'package:fluffychat/pangea/constants/class_default_values.dart';
import 'package:fluffychat/pangea/constants/model_keys.dart';
@ -11,8 +12,11 @@ import 'package:fluffychat/pangea/models/class_model.dart';
import 'package:fluffychat/pangea/models/tokens_event_content_model.dart';
import 'package:fluffychat/pangea/utils/bot_name.dart';
import 'package:fluffychat/pangea/utils/error_handler.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
// import markdown.dart
import 'package:html_unescape/html_unescape.dart';
import 'package:matrix/matrix.dart';
@ -138,6 +142,18 @@ extension PangeaRoom on Room {
// events
Future<void> archive() async => await _archive();
Future<bool> archiveSpace(
BuildContext context,
Client client, {
bool onlyAdmin = false,
}) async =>
await _archiveSpace(context, client, onlyAdmin: onlyAdmin);
Future<bool> leaveSpace(BuildContext context, Client client) async =>
await _leaveSpace(context, client);
Future<Event?> sendPangeaEvent({
required Map<String, dynamic> content,
required String parentEventId,
@ -260,6 +276,8 @@ extension PangeaRoom on Room {
// user_permissions
Future<bool> isOnlyAdmin() async => await _isOnlyAdmin();
bool isMadeByUser(String userId) => _isMadeByUser(userId);
bool get isSpaceAdmin => _isSpaceAdmin;

@ -1,6 +1,32 @@
part of "pangea_room_extension.dart";
extension UserPermissionsRoomExtension on Room {
// If there are no other admins, and at least one non-admin, return true
Future<bool> _isOnlyAdmin() async {
if (!isRoomAdmin) {
return false;
}
final List<User> participants = await requestParticipants();
return ((participants
.where(
(e) =>
e.powerLevel == ClassDefaultValues.powerLevelOfAdmin &&
e.id != BotName.byEnvironment,
)
.toList()
.length) ==
1) &&
(participants
.where(
(e) =>
e.powerLevel < ClassDefaultValues.powerLevelOfAdmin &&
e.id != BotName.byEnvironment,
)
.toList())
.isNotEmpty;
}
bool _isMadeByUser(String userId) =>
getState(EventTypes.RoomCreate)?.senderId == userId;

@ -63,6 +63,7 @@ enum MatrixProfile {
showedItInstructions,
showedClickMessage,
showedBlurMeansTranslate,
showedTooltipInstructions,
createdAt,
targetLanguage,
sourceLanguage,
@ -95,6 +96,8 @@ extension MatrixProfileExtension on MatrixProfile {
return InstructionsEnum.clickMessage.toString();
case MatrixProfile.showedBlurMeansTranslate:
return InstructionsEnum.blurMeansTranslate.toString();
case MatrixProfile.showedTooltipInstructions:
return InstructionsEnum.tooltipInstructions.toString();
case MatrixProfile.createdAt:
return ModelKey.userCreatedAt;
case MatrixProfile.targetLanguage:

@ -1,22 +0,0 @@
import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart';
import 'package:fluffychat/pangea/utils/error_handler.dart';
import 'package:matrix/matrix.dart';
Future<void> archiveSpace(Room? space, Client client) async {
if (space == null) {
ErrorHandler.logError(
e: 'Tried to archive a space that is null. This should not happen.',
s: StackTrace.current,
);
return;
}
final List<Room> children = await space.getChildRooms();
for (final Room child in children) {
if (child.isUnread) {
await child.markUnread(false);
}
await child.leave();
}
await space.leave();
}

@ -1,3 +1,4 @@
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
@ -102,6 +103,7 @@ enum InstructionsEnum {
itInstructions,
clickMessage,
blurMeansTranslate,
tooltipInstructions,
}
extension Copy on InstructionsEnum {
@ -113,6 +115,8 @@ extension Copy on InstructionsEnum {
return L10n.of(context)!.clickMessageTitle;
case InstructionsEnum.blurMeansTranslate:
return L10n.of(context)!.blurMeansTranslateTitle;
case InstructionsEnum.tooltipInstructions:
return L10n.of(context)!.tooltipInstructionsTitle;
}
}
@ -124,6 +128,10 @@ extension Copy on InstructionsEnum {
return L10n.of(context)!.clickMessageBody;
case InstructionsEnum.blurMeansTranslate:
return L10n.of(context)!.blurMeansTranslateBody;
case InstructionsEnum.tooltipInstructions:
return PlatformInfos.isMobile
? L10n.of(context)!.tooltipInstructionsMobileBody
: L10n.of(context)!.tooltipInstructionsBrowserBody;
}
}
}

@ -3,6 +3,7 @@ import 'dart:developer';
import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart';
import 'package:fluffychat/pangea/models/speech_to_text_models.dart';
import 'package:fluffychat/pangea/utils/error_handler.dart';
import 'package:fluffychat/pangea/utils/instructions.dart';
import 'package:fluffychat/pangea/widgets/chat/toolbar_content_loading_indicator.dart';
import 'package:fluffychat/pangea/widgets/common/icon_number_widget.dart';
import 'package:fluffychat/pangea/widgets/igc/card_error_widget.dart';
@ -175,12 +176,24 @@ class MessageSpeechToTextCardState extends State<MessageSpeechToTextCard> {
number:
"${selectedToken?.confidence ?? speechToTextResponse!.transcript.confidence}%",
toolTip: L10n.of(context)!.accuracy,
onPressed: () => MatrixState.pangeaController.instructions.show(
context,
InstructionsEnum.tooltipInstructions,
widget.messageEvent.eventId,
true,
),
),
IconNumberWidget(
icon: Icons.speed,
number:
wordsPerMinuteString != null ? "$wordsPerMinuteString" : "??",
toolTip: L10n.of(context)!.wordsPerMinute,
onPressed: () => MatrixState.pangeaController.instructions.show(
context,
InstructionsEnum.tooltipInstructions,
widget.messageEvent.eventId,
true,
),
),
],
),

@ -6,6 +6,7 @@ class IconNumberWidget extends StatelessWidget {
final Color? iconColor;
final double? iconSize;
final String? toolTip;
final VoidCallback onPressed;
const IconNumberWidget({
super.key,
@ -14,16 +15,20 @@ class IconNumberWidget extends StatelessWidget {
this.toolTip,
this.iconColor,
this.iconSize,
required this.onPressed,
});
Widget _content(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Icon(
icon,
color: iconColor ?? Theme.of(context).iconTheme.color,
size: iconSize ?? Theme.of(context).iconTheme.size,
IconButton(
icon: Icon(
icon,
color: iconColor ?? Theme.of(context).iconTheme.color,
size: iconSize ?? Theme.of(context).iconTheme.size,
),
onPressed: onPressed,
),
const SizedBox(width: 8),
Text(

@ -85,20 +85,31 @@ class ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
),
// #Pangea
if (!widget.room.isArchived)
// Pangea#
PopupMenuItem<String>(
value: 'leave',
child: Row(
children: [
// #Pangea
// const Icon(Icons.delete_outlined),
const Icon(Icons.arrow_forward),
// Pangea#
const SizedBox(width: 12),
Text(L10n.of(context)!.leave),
],
if (widget.room.isRoomAdmin)
PopupMenuItem<String>(
value: 'archive',
child: Row(
children: [
const Icon(Icons.archive_outlined),
const SizedBox(width: 12),
Text(L10n.of(context)!.archive),
],
),
),
// Pangea#
PopupMenuItem<String>(
value: 'leave',
child: Row(
children: [
// #Pangea
// const Icon(Icons.delete_outlined),
const Icon(Icons.arrow_forward),
// Pangea#
const SizedBox(width: 12),
Text(L10n.of(context)!.leave),
],
),
),
// #Pangea
if (classSettings != null)
PopupMenuItem<String>(
@ -167,7 +178,8 @@ class ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
PopupMenuButton(
onSelected: (String choice) async {
switch (choice) {
case 'leave':
// #Pangea
case 'archive':
final confirmed = await showOkCancelAlertDialog(
useRootNavigator: false,
context: context,
@ -179,7 +191,31 @@ class ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
if (confirmed == OkCancelResult.ok) {
final success = await showFutureLoadingDialog(
context: context,
future: () => widget.room.leave(),
future: () => widget.room.archive(),
);
if (success.error == null) {
context.go('/rooms');
}
}
break;
// Pangea#
case 'leave':
final bool onlyAdmin = await widget.room.isOnlyAdmin();
final confirmed = await showOkCancelAlertDialog(
useRootNavigator: false,
context: context,
title: L10n.of(context)!.areYouSure,
okLabel: L10n.of(context)!.ok,
cancelLabel: L10n.of(context)!.cancel,
message: onlyAdmin
? L10n.of(context)!.onlyAdminDescription
: L10n.of(context)!.leaveRoomDescription,
);
if (confirmed == OkCancelResult.ok) {
final success = await showFutureLoadingDialog(
context: context,
future: () =>
onlyAdmin ? widget.room.archive() : widget.room.leave(),
);
if (success.error == null) {
context.go('/rooms');

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save