diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 240a86437..6dd25ea21 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -5230,5 +5230,6 @@ "myActivities": "My activities", "openToJoin": "Open to join", "results": "Results", - "activityDone": "Activity Done!" + "activityDone": "Activity Done!", + "moreLabel": "more" } diff --git a/lib/pangea/activity_sessions/activity_summary_widget.dart b/lib/pangea/activity_sessions/activity_summary_widget.dart index 2c0025841..ae78e6bed 100644 --- a/lib/pangea/activity_sessions/activity_summary_widget.dart +++ b/lib/pangea/activity_sessions/activity_summary_widget.dart @@ -69,37 +69,43 @@ class ActivitySummary extends StatelessWidget { spacing: 4.0, mainAxisSize: MainAxisSize.min, children: [ - Stack( - alignment: Alignment.bottomRight, - children: [ - Text( - activity.description, - style: const TextStyle( - fontSize: 12.0, + InlineEllipsisText( + text: activity.description, + maxLines: showInstructions ? null : 2, + trailingWidth: 50.0, + style: DefaultTextStyle.of(context) + .style + .copyWith(fontSize: 12.0), + trailing: WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, ), - ), - TextButton( - onPressed: toggleInstructions, - style: TextButton.styleFrom( - minimumSize: Size.zero, - padding: EdgeInsets.zero, - tapTargetSize: MaterialTapTargetSize.shrinkWrap, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(0.0), - ), - backgroundColor: theme.colorScheme.surface, + padding: const EdgeInsets.symmetric( + horizontal: 4.0, ), - child: Text( - showInstructions - ? L10n.of(context).less - : L10n.of(context).more, - style: TextStyle( - fontSize: 12.0, - color: theme.colorScheme.primary, + child: TextButton( + onPressed: toggleInstructions, + style: TextButton.styleFrom( + minimumSize: Size.zero, + padding: EdgeInsets.zero, + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + backgroundColor: + Theme.of(context).colorScheme.surface, + ), + child: Text( + showInstructions + ? L10n.of(context).less + : L10n.of(context).moreLabel, + style: TextStyle( + fontSize: 12.0, + color: Theme.of(context).colorScheme.primary, + ), ), ), ), - ], + ), ), if (showInstructions) ...[ Row( @@ -179,3 +185,62 @@ class ActivitySummary extends StatelessWidget { ); } } + +class InlineEllipsisText extends StatelessWidget { + final String text; + final int? maxLines; + final TextStyle? style; + final WidgetSpan trailing; + final double trailingWidth; + + const InlineEllipsisText({ + super.key, + required this.text, + required this.trailing, + required this.trailingWidth, + this.maxLines, + this.style, + }); + + @override + Widget build(BuildContext context) { + final effectiveStyle = style ?? DefaultTextStyle.of(context).style; + final span = TextSpan(text: text, style: effectiveStyle); + return LayoutBuilder( + builder: (context, constraints) { + final tp = TextPainter( + text: span, + maxLines: maxLines, + textDirection: TextDirection.ltr, + ellipsis: '…', + ); + + tp.layout(maxWidth: constraints.maxWidth); + String truncated = text; + if (tp.didExceedMaxLines && maxLines != null) { + // Find cutoff point where text fits + final pos = tp.getPositionForOffset( + Offset( + constraints.maxWidth - trailingWidth, + tp.preferredLineHeight * maxLines!, + ), + ); + final endIndex = tp.getOffsetBefore(pos.offset) ?? text.length; + truncated = '${text.substring(0, endIndex).trimRight()}…'; + } + + tp.dispose(); + return RichText( + text: TextSpan( + children: [ + TextSpan(text: truncated, style: effectiveStyle), + trailing, // always visible + ], + ), + maxLines: maxLines, + overflow: TextOverflow.clip, // prevent extra wrapping + ); + }, + ); + } +} diff --git a/lib/pangea/chat_settings/pages/space_details_content.dart b/lib/pangea/chat_settings/pages/space_details_content.dart index 0d13558e3..bc69b4084 100644 --- a/lib/pangea/chat_settings/pages/space_details_content.dart +++ b/lib/pangea/chat_settings/pages/space_details_content.dart @@ -17,6 +17,7 @@ import 'package:fluffychat/pangea/course_chats/course_chats_page.dart'; import 'package:fluffychat/pangea/course_creation/course_info_chip_widget.dart'; import 'package:fluffychat/pangea/course_plans/course_plan_builder.dart'; import 'package:fluffychat/pangea/course_plans/course_plan_room_extension.dart'; +import 'package:fluffychat/pangea/course_plans/map_clipper.dart'; import 'package:fluffychat/pangea/course_settings/course_settings.dart'; import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; @@ -221,13 +222,15 @@ class SpaceDetailsContent extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ if (isColumnMode) ...[ - Avatar( - mxContent: room.avatar, - name: displayname, - userId: room.directChatMatrixID, - size: 80.0, - borderRadius: - room.isSpace ? BorderRadius.circular(24.0) : null, + ClipPath( + clipper: MapClipper(), + child: Avatar( + mxContent: room.avatar, + name: displayname, + userId: room.directChatMatrixID, + size: 80.0, + borderRadius: BorderRadius.circular(0.0), + ), ), const SizedBox(width: 16.0), ],