diff --git a/lib/pangea/chat_settings/pages/room_details_buttons.dart b/lib/pangea/chat_settings/pages/room_details_buttons.dart index 39bb17af1..70c2ad6e3 100644 --- a/lib/pangea/chat_settings/pages/room_details_buttons.dart +++ b/lib/pangea/chat_settings/pages/room_details_buttons.dart @@ -11,7 +11,6 @@ class ButtonDetails { final bool visible; final bool enabled; final bool showInMainView; - final bool desctructive; final SpaceSettingsTabs? tab; const ButtonDetails({ @@ -22,7 +21,6 @@ class ButtonDetails { this.enabled = true, this.onPressed, this.showInMainView = true, - this.desctructive = false, this.tab, }); } diff --git a/lib/pangea/chat_settings/pages/space_details_content.dart b/lib/pangea/chat_settings/pages/space_details_content.dart index 73e4b646e..8babaf772 100644 --- a/lib/pangea/chat_settings/pages/space_details_content.dart +++ b/lib/pangea/chat_settings/pages/space_details_content.dart @@ -190,10 +190,9 @@ class SpaceDetailsContentState extends State { ButtonDetails( title: l10n.delete, description: l10n.deleteDesc, - icon: Icon( + icon: const Icon( Icons.delete_outline, size: 30.0, - color: Theme.of(context).colorScheme.error, ), onPressed: () async { final resp = await showDialog( @@ -207,7 +206,6 @@ class SpaceDetailsContentState extends State { }, enabled: widget.room.isRoomAdmin && !widget.room.isDirectChat, showInMainView: false, - desctructive: true, ), ]; } @@ -235,7 +233,7 @@ class SpaceDetailsContentState extends State { mxContent: widget.room.avatar, name: displayname, userId: widget.room.directChatMatrixID, - size: Avatar.defaultSize * 2.5, + size: 80.0, borderRadius: widget.room.isSpace ? BorderRadius.circular(24.0) : null, @@ -380,25 +378,15 @@ class SpaceDetailsContentState extends State { child: ListTile( title: Text( b.title, - style: TextStyle( + style: const TextStyle( fontSize: 12.0, - color: b.desctructive - ? Theme.of(context) - .colorScheme - .error - : null, ), ), subtitle: b.description != null ? Text( b.description!, - style: TextStyle( + style: const TextStyle( fontSize: 8.0, - color: b.desctructive - ? Theme.of(context) - .colorScheme - .error - : null, ), ) : null, diff --git a/lib/pangea/course_settings/course_settings.dart b/lib/pangea/course_settings/course_settings.dart index f2e70f422..d92b6cec5 100644 --- a/lib/pangea/course_settings/course_settings.dart +++ b/lib/pangea/course_settings/course_settings.dart @@ -1,5 +1,3 @@ -import 'dart:math'; - import 'package:flutter/material.dart'; import 'package:cached_network_image/cached_network_image.dart'; @@ -13,10 +11,10 @@ import 'package:fluffychat/pangea/activity_suggestions/activity_suggestion_card. import 'package:fluffychat/pangea/activity_suggestions/activity_suggestion_dialog.dart'; import 'package:fluffychat/pangea/common/widgets/error_indicator.dart'; import 'package:fluffychat/pangea/course_creation/course_info_chip_widget.dart'; +import 'package:fluffychat/pangea/course_settings/pin_clipper.dart'; +import 'package:fluffychat/pangea/course_settings/topic_participant_list.dart'; import 'package:fluffychat/pangea/courses/course_plan_builder.dart'; import 'package:fluffychat/pangea/courses/course_plan_room_extension.dart'; -import 'package:fluffychat/pangea/spaces/utils/load_participants_util.dart'; -import 'package:fluffychat/widgets/avatar.dart'; class CourseSettings extends StatelessWidget { final Room room; @@ -45,7 +43,7 @@ class CourseSettings extends StatelessWidget { final theme = Theme.of(context); final isColumnMode = FluffyThemes.isColumnMode(context); - final double titleFontSize = isColumnMode ? 32.0 : 12.0; + final double titleFontSize = isColumnMode ? 24.0 : 12.0; final double descFontSize = isColumnMode ? 12.0 : 8.0; final double iconSize = isColumnMode ? 16.0 : 12.0; @@ -57,7 +55,7 @@ class CourseSettings extends StatelessWidget { final topicsToUsers = room.topicsToUsers(course); return Column( - spacing: isColumnMode ? 30.0 : 12.0, + spacing: isColumnMode ? 40.0 : 36.0, mainAxisSize: MainAxisSize.min, children: course.topics.mapIndexed((index, topic) { final unlocked = index <= currentTopicIndex; @@ -84,8 +82,8 @@ class CourseSettings extends StatelessWidget { children: [ Stack( children: [ - ClipRRect( - borderRadius: BorderRadius.circular(80), + ClipPath( + clipper: PinClipper(), child: topic.imageUrl != null ? CachedNetworkImage( width: 54.0, @@ -224,103 +222,3 @@ class CourseSettings extends StatelessWidget { ); } } - -class TopicParticipantList extends StatelessWidget { - final Room room; - final List users; - final double avatarSize; - final int maxVisible; - final double overlap; - - const TopicParticipantList({ - super.key, - required this.room, - required this.users, - this.avatarSize = 50.0, - this.maxVisible = 6, - this.overlap = 20.0, - }); - - @override - Widget build(BuildContext context) { - final maxWidth = - (avatarSize - overlap) * min(users.length, maxVisible) + overlap; - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( - width: maxWidth, - height: avatarSize, - child: LoadParticipantsUtil( - space: room, - builder: (participantsLoader) { - final publicProfiles = Map.fromEntries( - users.map( - (u) => MapEntry( - u.id, - participantsLoader.getAnalyticsProfile(u.id)?.level, - ), - ), - ); - - users.sort((a, b) { - final aLevel = publicProfiles[a.id]; - final bLevel = publicProfiles[b.id]; - if (aLevel != null && bLevel != null) { - return bLevel.compareTo(aLevel); - } - return 0; - }); - - return Stack( - children: users.take(maxVisible).mapIndexed((index, user) { - final level = publicProfiles[user.id]; - final LinearGradient? gradient = - level != null ? index.leaderboardGradient : null; - return Positioned( - left: index * (avatarSize - overlap), - child: Stack( - alignment: Alignment.center, - children: [ - if (gradient != null) - CircleAvatar( - radius: avatarSize / 2, - child: Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - gradient: gradient, - ), - ), - ) - else - SizedBox( - height: avatarSize, - width: avatarSize, - ), - Center( - child: Avatar( - mxContent: user.avatarUrl, - name: user.calcDisplayname(), - size: avatarSize - 6.0, - userId: user.id, - ), - ), - ], - ), - ); - }).toList(), - ); - }, - ), - ), - if (users.length > maxVisible) - Text( - L10n.of(context).additionalParticipants(users.length - maxVisible), - style: const TextStyle( - fontSize: 12.0, - ), - ), - ], - ); - } -} diff --git a/lib/pangea/course_settings/pin_clipper.dart b/lib/pangea/course_settings/pin_clipper.dart new file mode 100644 index 000000000..93c879a4f --- /dev/null +++ b/lib/pangea/course_settings/pin_clipper.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; + +class PinClipper extends CustomClipper { + @override + Path getClip(Size size) { + final double w = size.width; + final double h = size.height; + + final Path path = Path(); + path.moveTo(w * 0.1, h * 0.4); + path.arcToPoint( + Offset(w * 0.9, h * 0.4), + radius: const Radius.circular(20), + ); + path.quadraticBezierTo(w * 0.9, h * 0.75, w / 2, h); + path.quadraticBezierTo(w * 0.1, h * 0.75, w * 0.1, h * 0.4); + + path.close(); + return path; + } + + @override + bool shouldReclip(CustomClipper oldClipper) => false; +} diff --git a/lib/pangea/course_settings/topic_participant_list.dart b/lib/pangea/course_settings/topic_participant_list.dart new file mode 100644 index 000000000..328cc31b3 --- /dev/null +++ b/lib/pangea/course_settings/topic_participant_list.dart @@ -0,0 +1,110 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; + +import 'package:collection/collection.dart'; +import 'package:matrix/matrix.dart'; + +import 'package:fluffychat/l10n/l10n.dart'; +import 'package:fluffychat/pangea/spaces/utils/load_participants_util.dart'; +import 'package:fluffychat/widgets/avatar.dart'; + +class TopicParticipantList extends StatelessWidget { + final Room room; + final List users; + final double avatarSize; + final int maxVisible; + final double overlap; + + const TopicParticipantList({ + super.key, + required this.room, + required this.users, + this.avatarSize = 50.0, + this.maxVisible = 6, + this.overlap = 20.0, + }); + + @override + Widget build(BuildContext context) { + final maxWidth = + (avatarSize - overlap) * min(users.length, maxVisible) + overlap; + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: maxWidth, + height: avatarSize, + child: LoadParticipantsUtil( + space: room, + builder: (participantsLoader) { + final publicProfiles = Map.fromEntries( + users.map( + (u) => MapEntry( + u.id, + participantsLoader.getAnalyticsProfile(u.id)?.level, + ), + ), + ); + + users.sort((a, b) { + final aLevel = publicProfiles[a.id]; + final bLevel = publicProfiles[b.id]; + if (aLevel != null && bLevel != null) { + return bLevel.compareTo(aLevel); + } + return 0; + }); + + return Stack( + children: users.take(maxVisible).mapIndexed((index, user) { + final level = publicProfiles[user.id]; + final LinearGradient? gradient = + level != null ? index.leaderboardGradient : null; + return Positioned( + left: index * (avatarSize - overlap), + child: Stack( + alignment: Alignment.center, + children: [ + if (gradient != null) + CircleAvatar( + radius: avatarSize / 2, + child: Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + gradient: gradient, + ), + ), + ) + else + SizedBox( + height: avatarSize, + width: avatarSize, + ), + Center( + child: Avatar( + mxContent: user.avatarUrl, + name: user.calcDisplayname(), + size: avatarSize - 6.0, + userId: user.id, + ), + ), + ], + ), + ); + }).toList(), + ); + }, + ), + ), + if (users.length > maxVisible) + Text( + L10n.of(context).additionalParticipants(users.length - maxVisible), + style: const TextStyle( + fontSize: 12.0, + ), + ), + ], + ); + } +}