Merge branch 'main' into fix-analytics-overflow

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

@ -475,10 +475,6 @@ class ChatController extends State<ChatPageWithRoom>
if (kIsWeb && !Matrix.of(context).webHasFocus) return;
// #Pangea
} catch (err, s) {
ErrorHandler.logError(
e: PangeaWarningError("Web focus error: $err"),
s: s,
);
return;
}
// Pangea#

@ -289,17 +289,20 @@ class MessageContent extends StatelessWidget {
// #Pangea
// return Linkify(
final messageTextStyle = TextStyle(
overflow: TextOverflow.ellipsis,
color: textColor,
fontSize: bigEmotes ? fontSize * 3 : fontSize,
decoration: event.redacted ? TextDecoration.lineThrough : null,
height: 1.3,
);
if (immersionMode && pangeaMessageEvent != null) {
return PangeaRichText(
style: messageTextStyle,
pangeaMessageEvent: pangeaMessageEvent!,
immersionMode: immersionMode,
toolbarController: toolbarController,
return Flexible(
child: PangeaRichText(
style: messageTextStyle,
pangeaMessageEvent: pangeaMessageEvent!,
immersionMode: immersionMode,
toolbarController: toolbarController,
),
);
} else if (pangeaMessageEvent != null) {
toolbarController?.toolbar?.textSelection.setMessageText(

@ -504,6 +504,9 @@ class InputBar extends StatelessWidget {
onSubmitted!(text);
},
// #Pangea
style: controller?.isMaxLength ?? false
? const TextStyle(color: Colors.red)
: null,
onTap: () {
controller!.onInputTap(
context,

@ -1,5 +1,4 @@
import 'package:fluffychat/pangea/constants/age_limits.dart';
import 'package:fluffychat/pangea/constants/pangea_event_types.dart';
import 'package:fluffychat/pangea/controllers/base_controller.dart';
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart';
@ -36,63 +35,73 @@ class PermissionsController extends BaseController {
return dob?.isAtLeastYearsOld(AgeLimits.toAccessFeatures) ?? false;
}
/// A user can private chat if
/// 1) they are 18 and outside a class context or
/// 2) they are in a class context and the class rules permit it
/// If no class is passed, uses classController.activeClass
/// A user can private chat if they are 18+
bool canUserPrivateChat({String? roomID}) {
final Room? classContext =
firstRoomWithState(roomID: roomID, type: PangeaEventTypes.rules);
return classContext?.pangeaRoomRules == null
? isUser18()
: classContext!.pangeaRoomRules!.oneToOneChatClass ||
classContext.isRoomAdmin;
return isUser18();
// Rules can't be edited; default to true
// final Room? classContext =
// firstRoomWithState(roomID: roomID, type: PangeaEventTypes.rules);
// return classContext?.pangeaRoomRules == null
// ? isUser18()
// : classContext!.pangeaRoomRules!.oneToOneChatClass ||
// classContext.isRoomAdmin;
}
bool canUserGroupChat({String? roomID}) {
final Room? classContext =
firstRoomWithState(roomID: roomID, type: PangeaEventTypes.rules);
return classContext?.pangeaRoomRules == null
? isUser18()
: classContext!.pangeaRoomRules!.isCreateRooms ||
classContext.isRoomAdmin;
return isUser18();
// Rules can't be edited; default to true
// final Room? classContext =
// firstRoomWithState(roomID: roomID, type: PangeaEventTypes.rules);
// return classContext?.pangeaRoomRules == null
// ? isUser18()
// : classContext!.pangeaRoomRules!.isCreateRooms ||
// classContext.isRoomAdmin;
}
bool showChatInputAddButton(String roomId) {
final PangeaRoomRules? perms = _getRoomRules(roomId);
if (perms == null) return isUser18();
return perms.isShareFiles ||
perms.isShareLocation ||
perms.isSharePhoto ||
perms.isShareVideo;
// Rules can't be edited; default to true
// final PangeaRoomRules? perms = _getRoomRules(roomId);
// if (perms == null) return isUser18();
// return perms.isShareFiles ||
// perms.isShareLocation ||
// perms.isSharePhoto ||
// perms.isShareVideo;
return isUser18();
}
/// works for both roomID of chat and class
bool canShareVideo(String? roomID) =>
_getRoomRules(roomID)?.isShareVideo ?? isUser18();
bool canShareVideo(String? roomID) => isUser18();
// Rules can't be edited; default to true
// _getRoomRules(roomID)?.isShareVideo ?? isUser18();
/// works for both roomID of chat and class
bool canSharePhoto(String? roomID) =>
_getRoomRules(roomID)?.isSharePhoto ?? isUser18();
bool canSharePhoto(String? roomID) => isUser18();
// Rules can't be edited; default to true
// _getRoomRules(roomID)?.isSharePhoto ?? isUser18();
/// works for both roomID of chat and class
bool canShareFile(String? roomID) =>
_getRoomRules(roomID)?.isShareFiles ?? isUser18();
bool canShareFile(String? roomID) => isUser18();
// Rules can't be edited; default to true
// _getRoomRules(roomID)?.isShareFiles ?? isUser18();
/// works for both roomID of chat and class
bool canShareLocation(String? roomID) =>
_getRoomRules(roomID)?.isShareLocation ?? isUser18();
bool canShareLocation(String? roomID) => isUser18();
// Rules can't be edited; default to true
// _getRoomRules(roomID)?.isShareLocation ?? isUser18();
int? classLanguageToolPermission(Room room, ToolSetting setting) =>
room.firstRules?.getToolSettings(setting);
int? classLanguageToolPermission(Room room, ToolSetting setting) => 1;
// Rules can't be edited; default to student choice
// room.firstRules?.getToolSettings(setting);
//what happens if a room isn't in a class?
// what happens if a room isn't in a class?
bool isToolDisabledByClass(ToolSetting setting, Room? room) {
if (room?.isSpaceAdmin ?? false) return false;
final int? classPermission =
room != null ? classLanguageToolPermission(room, setting) : 1;
return classPermission == 0;
return false;
// Rules can't be edited; default to false
// if (room?.isSpaceAdmin ?? false) return false;
// final int? classPermission =
// room != null ? classLanguageToolPermission(room, setting) : 1;
// return classPermission == 0;
}
bool userToolSetting(ToolSetting setting) {
@ -117,18 +126,22 @@ class PermissionsController extends BaseController {
}
bool isToolEnabled(ToolSetting setting, Room? room) {
if (room?.isSpaceAdmin ?? false) {
return userToolSetting(setting);
}
final int? classPermission =
room != null ? classLanguageToolPermission(room, setting) : 1;
if (classPermission == 0) return false;
if (classPermission == 2) return true;
// Rules can't be edited; default to true
return userToolSetting(setting);
// if (room?.isSpaceAdmin ?? false) {
// return userToolSetting(setting);
// }
// final int? classPermission =
// room != null ? classLanguageToolPermission(room, setting) : 1;
// if (classPermission == 0) return false;
// if (classPermission == 2) return true;
// return userToolSetting(setting);
}
bool isWritingAssistanceEnabled(Room? room) {
return isToolEnabled(ToolSetting.interactiveTranslator, room) &&
isToolEnabled(ToolSetting.interactiveGrammar, room);
// Rules can't be edited; default to true
return true;
// return isToolEnabled(ToolSetting.interactiveTranslator, room) &&
// isToolEnabled(ToolSetting.interactiveGrammar, room);
}
}

@ -54,6 +54,7 @@ extension AnalyticsRoomExtension on Room {
return Future.value();
}
// Checks that user has permission to add child to space
if (!canSendEvent(EventTypes.SpaceChild)) return;
if (spaceChildren.any((sc) => sc.roomId == analyticsRoom.id)) return;
@ -103,17 +104,19 @@ extension AnalyticsRoomExtension on Room {
.where((teacher) => !participants.contains(teacher))
.toList();
Future.wait(
uninvitedTeachers.map(
(teacher) => analyticsRoom.invite(teacher.id).catchError((err, s) {
ErrorHandler.logError(
e: err,
m: "Failed to invite teacher ${teacher.id} to analytics room ${analyticsRoom.id}",
s: s,
);
}),
),
);
if (analyticsRoom.canSendEvent(EventTypes.RoomMember)) {
Future.wait(
uninvitedTeachers.map(
(teacher) => analyticsRoom.invite(teacher.id).catchError((err, s) {
ErrorHandler.logError(
e: err,
m: "Failed to invite teacher ${teacher.id} to analytics room ${analyticsRoom.id}",
s: s,
);
}),
),
);
}
}
/// Invite all the user's teachers to 1 analytics room.

@ -44,6 +44,7 @@ class InputBarWrapper extends StatefulWidget {
class InputBarWrapperState extends State<InputBarWrapper> {
StreamSubscription? _choreoSub;
String _currentText = '';
@override
void initState() {
@ -61,6 +62,24 @@ class InputBarWrapperState extends State<InputBarWrapper> {
super.dispose();
}
void refreshOnChange(String text) {
if (widget.onChanged != null) {
widget.onChanged!(text);
}
final bool decreasedFromMaxLength =
_currentText.length >= PangeaTextController.maxLength &&
text.length < PangeaTextController.maxLength;
final bool reachedMaxLength =
_currentText.length < PangeaTextController.maxLength &&
text.length < PangeaTextController.maxLength;
if (decreasedFromMaxLength || reachedMaxLength) {
setState(() {});
}
_currentText = text;
}
@override
Widget build(BuildContext context) {
return InputBar(
@ -73,7 +92,7 @@ class InputBarWrapperState extends State<InputBarWrapper> {
focusNode: widget.focusNode,
controller: widget.controller,
decoration: widget.decoration,
onChanged: widget.onChanged,
onChanged: refreshOnChange,
autofocus: widget.autofocus,
textInputAction: widget.textInputAction,
readOnly: widget.readOnly,

@ -419,85 +419,83 @@ class MessageToolbarState extends State<MessageToolbar> {
@override
Widget build(BuildContext context) {
return Flexible(
child: Material(
type: MaterialType.transparency,
child: Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Theme.of(context).cardColor,
border: Border.all(
width: 2,
color: Theme.of(context).colorScheme.primary,
),
borderRadius: const BorderRadius.all(
Radius.circular(25),
),
return Material(
type: MaterialType.transparency,
child: Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Theme.of(context).cardColor,
border: Border.all(
width: 2,
color: Theme.of(context).colorScheme.primary,
),
constraints: const BoxConstraints(
maxWidth: 300,
minWidth: 300,
maxHeight: 300,
borderRadius: const BorderRadius.all(
Radius.circular(25),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: SingleChildScrollView(
child: AnimatedSize(
duration: FluffyThemes.animationDuration,
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: toolbarContent ?? const SizedBox(),
),
SizedBox(height: toolbarContent == null ? 0 : 20),
],
),
),
constraints: const BoxConstraints(
maxWidth: 300,
minWidth: 300,
maxHeight: 300,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: SingleChildScrollView(
child: AnimatedSize(
duration: FluffyThemes.animationDuration,
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: toolbarContent ?? const SizedBox(),
),
SizedBox(height: toolbarContent == null ? 0 : 20),
],
),
),
),
Row(
mainAxisSize: MainAxisSize.min,
children: MessageMode.values.map((mode) {
if ([
MessageMode.definition,
MessageMode.textToSpeech,
MessageMode.translation,
].contains(mode) &&
widget.pangeaMessageEvent.isAudioMessage) {
return const SizedBox.shrink();
}
if (mode == MessageMode.speechToText &&
!widget.pangeaMessageEvent.isAudioMessage) {
return const SizedBox.shrink();
}
return Tooltip(
message: mode.tooltip(context),
child: IconButton(
icon: Icon(mode.icon),
color: mode.iconColor(
widget.pangeaMessageEvent,
currentMode,
context,
),
onPressed: () => updateMode(mode),
),
);
}).toList() +
[
Tooltip(
message: L10n.of(context)!.more,
child: IconButton(
icon: const Icon(Icons.add_reaction_outlined),
onPressed: showMore,
),
Row(
mainAxisSize: MainAxisSize.min,
children: MessageMode.values.map((mode) {
if ([
MessageMode.definition,
MessageMode.textToSpeech,
MessageMode.translation,
].contains(mode) &&
widget.pangeaMessageEvent.isAudioMessage) {
return const SizedBox.shrink();
}
if (mode == MessageMode.speechToText &&
!widget.pangeaMessageEvent.isAudioMessage) {
return const SizedBox.shrink();
}
return Tooltip(
message: mode.tooltip(context),
child: IconButton(
icon: Icon(mode.icon),
color: mode.iconColor(
widget.pangeaMessageEvent,
currentMode,
context,
),
onPressed: () => updateMode(mode),
),
],
),
],
),
);
}).toList() +
[
Tooltip(
message: L10n.of(context)!.more,
child: IconButton(
icon: const Icon(Icons.add_reaction_outlined),
onPressed: showMore,
),
),
],
),
],
),
),
);

@ -118,81 +118,85 @@ class OverlayMessage extends StatelessWidget {
ownMessage: ownMessage,
);
return Material(
color: noBubble ? Colors.transparent : color,
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: borderRadius,
),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(
AppConfig.borderRadius,
),
),
padding: noBubble || noPadding
? EdgeInsets.zero
: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
constraints: BoxConstraints(
maxWidth: width ?? FluffyThemes.columnWidth * 1.25,
return Flexible(
child: Material(
color: noBubble ? Colors.transparent : color,
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: borderRadius,
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MessageContent(
event.getDisplayEvent(timeline),
textColor: textColor,
borderRadius: borderRadius,
selected: selected,
pangeaMessageEvent: pangeaMessageEvent,
immersionMode: immersionMode,
toolbarController: toolbarController,
isOverlay: true,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(
AppConfig.borderRadius,
),
if (event.hasAggregatedEvents(
timeline,
RelationshipTypes.edit,
) ||
(pangeaMessageEvent.showUseType))
Padding(
padding: const EdgeInsets.only(
top: 4.0,
),
padding: noBubble || noPadding
? EdgeInsets.zero
: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (pangeaMessageEvent.showUseType) ...[
pangeaMessageEvent.msgUseType.iconView(
context,
textColor.withAlpha(164),
),
const SizedBox(width: 4),
],
if (event.hasAggregatedEvents(
timeline,
RelationshipTypes.edit,
)) ...[
Icon(
Icons.edit_outlined,
color: textColor.withAlpha(164),
size: 14,
),
Text(
' - ${event.getDisplayEvent(timeline).originServerTs.localizedTimeShort(context)}',
style: TextStyle(
constraints: BoxConstraints(
maxWidth: width ?? FluffyThemes.columnWidth * 1.25,
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Flexible(
child: MessageContent(
event.getDisplayEvent(timeline),
textColor: textColor,
borderRadius: borderRadius,
selected: selected,
pangeaMessageEvent: pangeaMessageEvent,
immersionMode: immersionMode,
toolbarController: toolbarController,
isOverlay: true,
),
),
if (event.hasAggregatedEvents(
timeline,
RelationshipTypes.edit,
) ||
(pangeaMessageEvent.showUseType))
Padding(
padding: const EdgeInsets.only(
top: 4.0,
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (pangeaMessageEvent.showUseType) ...[
pangeaMessageEvent.msgUseType.iconView(
context,
textColor.withAlpha(164),
),
const SizedBox(width: 4),
],
if (event.hasAggregatedEvents(
timeline,
RelationshipTypes.edit,
)) ...[
Icon(
Icons.edit_outlined,
color: textColor.withAlpha(164),
fontSize: 12,
size: 14,
),
),
Text(
' - ${event.getDisplayEvent(timeline).originServerTs.localizedTimeShort(context)}',
style: TextStyle(
color: textColor.withAlpha(164),
fontSize: 12,
),
),
],
],
],
),
),
),
],
],
),
),
),
);

@ -25,6 +25,10 @@ class PangeaTextController extends TextEditingController {
text ??= '';
this.text = text;
}
static const int maxLength = 1000;
bool get isMaxLength => text.length == 1000;
bool forceKeepOpen = false;
setSystemText(String text, EditType type) {

Loading…
Cancel
Save