diff --git a/lib/community/pages/create_post_page.dart b/lib/community/pages/create_post_page.dart index 75d87a072..6b23c6263 100644 --- a/lib/community/pages/create_post_page.dart +++ b/lib/community/pages/create_post_page.dart @@ -26,7 +26,7 @@ import 'package:thunder/core/singletons/lemmy_client.dart'; import 'package:thunder/core/singletons/preferences.dart'; import 'package:thunder/post/cubit/create_post_cubit.dart'; import 'package:thunder/shared/common_markdown_body.dart'; -import 'package:thunder/shared/community_icon.dart'; +import 'package:thunder/shared/avatars/community_avatar.dart'; import 'package:thunder/shared/cross_posts.dart'; import 'package:thunder/shared/input_dialogs.dart'; import 'package:thunder/shared/link_preview_card.dart'; @@ -789,7 +789,7 @@ class _CommunitySelectorState extends State { padding: const EdgeInsets.only(left: 8, top: 12, bottom: 12), child: Row( children: [ - CommunityIcon(community: _communityView?.community, radius: 16), + CommunityAvatar(community: _communityView?.community, radius: 16), const SizedBox(width: 12), _communityId != null ? Column( diff --git a/lib/community/widgets/community_drawer.dart b/lib/community/widgets/community_drawer.dart index b8f830846..d5e653c3a 100644 --- a/lib/community/widgets/community_drawer.dart +++ b/lib/community/widgets/community_drawer.dart @@ -11,8 +11,8 @@ import 'package:thunder/account/utils/profiles.dart'; import 'package:thunder/community/bloc/anonymous_subscriptions_bloc.dart'; import 'package:thunder/core/auth/bloc/auth_bloc.dart'; import 'package:thunder/feed/feed.dart'; -import 'package:thunder/shared/community_icon.dart'; -import 'package:thunder/shared/user_avatar.dart'; +import 'package:thunder/shared/avatars/community_avatar.dart'; +import 'package:thunder/shared/avatars/user_avatar.dart'; import 'package:thunder/thunder/bloc/thunder_bloc.dart'; import 'package:thunder/utils/instance.dart'; import 'package:thunder/utils/global_context.dart'; @@ -475,7 +475,7 @@ class CommunityItem extends StatelessWidget { return Row( children: [ - CommunityIcon(community: community, radius: 16), + CommunityAvatar(community: community, radius: 16), const SizedBox(width: 16.0), Expanded( child: Tooltip( diff --git a/lib/community/widgets/community_header.dart b/lib/community/widgets/community_header.dart index 71a8f713f..941a028b8 100644 --- a/lib/community/widgets/community_header.dart +++ b/lib/community/widgets/community_header.dart @@ -4,7 +4,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:lemmy_api_client/v3.dart'; import 'package:thunder/core/enums/full_name_separator.dart'; -import 'package:thunder/shared/community_icon.dart'; +import 'package:thunder/shared/avatars/community_avatar.dart'; import 'package:thunder/shared/icon_text.dart'; import 'package:thunder/utils/instance.dart'; import 'package:thunder/utils/numbers.dart'; @@ -91,7 +91,7 @@ class _CommunityHeaderState extends State { children: [ Row( children: [ - CommunityIcon( + CommunityAvatar( community: widget.getCommunityResponse.communityView.community, radius: 45.0, ), diff --git a/lib/community/widgets/community_sidebar.dart b/lib/community/widgets/community_sidebar.dart index af1b41cf1..0cb3a71c6 100644 --- a/lib/community/widgets/community_sidebar.dart +++ b/lib/community/widgets/community_sidebar.dart @@ -17,7 +17,7 @@ import 'package:thunder/feed/bloc/feed_bloc.dart'; import 'package:thunder/instance/instance_view.dart'; import 'package:thunder/shared/common_markdown_body.dart'; import 'package:thunder/shared/snackbar.dart'; -import 'package:thunder/shared/user_avatar.dart'; +import 'package:thunder/shared/avatars/user_avatar.dart'; import 'package:thunder/thunder/bloc/thunder_bloc.dart'; import 'package:thunder/utils/date_time.dart'; import 'package:thunder/utils/instance.dart'; diff --git a/lib/community/widgets/post_card_metadata.dart b/lib/community/widgets/post_card_metadata.dart index e5f725795..4e18fa768 100644 --- a/lib/community/widgets/post_card_metadata.dart +++ b/lib/community/widgets/post_card_metadata.dart @@ -6,7 +6,7 @@ import 'package:lemmy_api_client/v3.dart'; import 'package:thunder/core/auth/bloc/auth_bloc.dart'; import 'package:thunder/core/enums/full_name_separator.dart'; import 'package:thunder/feed/feed.dart'; -import 'package:thunder/shared/community_icon.dart'; +import 'package:thunder/shared/avatars/community_avatar.dart'; import 'package:thunder/shared/icon_text.dart'; import 'package:thunder/shared/text/scalable_text.dart'; import 'package:thunder/thunder/bloc/thunder_bloc.dart'; @@ -203,7 +203,7 @@ class PostCommunityAndAuthor extends StatelessWidget { GestureDetector( child: Padding( padding: const EdgeInsets.only(right: 8.0), - child: CommunityIcon(community: postView.community, radius: 14), + child: CommunityAvatar(community: postView.community, radius: 14), ), onTap: () => navigateToFeedPage(context, communityId: postView.community.id, feedType: FeedType.community), ), diff --git a/lib/search/pages/search_page.dart b/lib/search/pages/search_page.dart index 0209a0d5a..789dd707f 100644 --- a/lib/search/pages/search_page.dart +++ b/lib/search/pages/search_page.dart @@ -34,8 +34,8 @@ import 'package:thunder/shared/error_message.dart'; import 'package:thunder/shared/input_dialogs.dart'; import 'package:thunder/shared/snackbar.dart'; import 'package:thunder/shared/sort_picker.dart'; -import 'package:thunder/shared/community_icon.dart'; -import 'package:thunder/shared/user_avatar.dart'; +import 'package:thunder/shared/avatars/community_avatar.dart'; +import 'package:thunder/shared/avatars/user_avatar.dart'; import 'package:thunder/thunder/bloc/thunder_bloc.dart'; import 'package:thunder/utils/bottom_sheet_list_picker.dart'; import 'package:thunder/utils/constants.dart'; @@ -713,7 +713,7 @@ class _SearchPageState extends State with AutomaticKeepAliveClientMi message: '${communityView.community.title}\n${generateCommunityFullName(context, communityView.community.name, fetchInstanceNameFromUrl(communityView.community.actorId))}', preferBelow: false, child: ListTile( - leading: CommunityIcon(community: communityView.community, radius: 25), + leading: CommunityAvatar(community: communityView.community, radius: 25), title: Text( communityView.community.title, overflow: TextOverflow.ellipsis, diff --git a/lib/shared/avatars/community_avatar.dart b/lib/shared/avatars/community_avatar.dart new file mode 100644 index 000000000..09ab0e800 --- /dev/null +++ b/lib/shared/avatars/community_avatar.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; + +import 'package:lemmy_api_client/v3.dart'; +import 'package:cached_network_image/cached_network_image.dart'; + +/// A community avatar. Displays the associated community icon if available. +/// +/// Otherwise, displays the first letter of the community title (display name). +/// If no title is available, displays the first letter of the community name. +class CommunityAvatar extends StatelessWidget { + /// The community information to display + final Community? community; + + /// The radius of the avatar. Defaults to 12 + final double radius; + + const CommunityAvatar({super.key, this.community, this.radius = 12.0}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + CircleAvatar placeholderIcon = CircleAvatar( + backgroundColor: theme.colorScheme.secondaryContainer, + maxRadius: radius, + child: Text( + community?.title.isNotEmpty == true + ? community!.title[0].toUpperCase() + : community?.name.isNotEmpty == true + ? community!.name[0].toUpperCase() + : '', + semanticsLabel: '', + style: TextStyle(fontWeight: FontWeight.bold, fontSize: radius), + ), + ); + + if (community?.icon?.isNotEmpty != true) return placeholderIcon; + + return CachedNetworkImage( + imageUrl: community!.icon!, + imageBuilder: (context, imageProvider) { + return CircleAvatar( + backgroundColor: Colors.transparent, + foregroundImage: imageProvider, + maxRadius: radius, + ); + }, + placeholder: (context, url) => placeholderIcon, + errorWidget: (context, url, error) => placeholderIcon, + ); + } +} diff --git a/lib/shared/avatars/user_avatar.dart b/lib/shared/avatars/user_avatar.dart new file mode 100644 index 000000000..d57c9acbf --- /dev/null +++ b/lib/shared/avatars/user_avatar.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; + +import 'package:lemmy_api_client/v3.dart'; +import 'package:cached_network_image/cached_network_image.dart'; + +/// A user avatar. Displays the associated user icon if available. +/// +/// Otherwise, displays the first letter of the user's display name. +/// If no display name is available, displays the first letter of the user's username. +class UserAvatar extends StatelessWidget { + /// The user information to display + final Person? person; + + /// The radius of the avatar. Defaults to 16 + final double radius; + + const UserAvatar({super.key, this.person, this.radius = 16.0}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + CircleAvatar placeholderIcon = CircleAvatar( + backgroundColor: theme.colorScheme.secondaryContainer, + maxRadius: radius, + child: Text( + person?.displayName?.isNotEmpty == true + ? person!.displayName![0].toUpperCase() + : person?.name.isNotEmpty == true + ? person!.name[0].toUpperCase() + : '', + semanticsLabel: '', + style: TextStyle(fontWeight: FontWeight.bold, fontSize: radius), + ), + ); + + if (person?.avatar?.isNotEmpty != true) return placeholderIcon; + + return CachedNetworkImage( + imageUrl: person!.avatar!, + imageBuilder: (context, imageProvider) { + return CircleAvatar( + backgroundColor: Colors.transparent, + foregroundImage: imageProvider, + maxRadius: radius, + ); + }, + placeholder: (context, url) => placeholderIcon, + errorWidget: (context, url, error) => placeholderIcon, + ); + } +} diff --git a/lib/shared/community_icon.dart b/lib/shared/community_icon.dart deleted file mode 100644 index 4096cd072..000000000 --- a/lib/shared/community_icon.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:flutter/material.dart'; -import 'package:lemmy_api_client/v3.dart'; - -class CommunityIcon extends StatelessWidget { - final Community? community; - final double radius; - - const CommunityIcon({super.key, required this.community, this.radius = 12.0}); - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - - CircleAvatar placeholderIcon = CircleAvatar( - backgroundColor: theme.colorScheme.secondaryContainer, - maxRadius: radius, - child: community?.name != null - ? Text( - community!.name[0].toUpperCase(), - semanticsLabel: '', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: radius, - ), - ) - : null); - - if (community?.icon?.isNotEmpty != true) return placeholderIcon; - - return CachedNetworkImage( - imageUrl: community!.icon!, - imageBuilder: (context, imageProvider) { - return CircleAvatar( - backgroundColor: Colors.transparent, - foregroundImage: imageProvider, - maxRadius: radius, - ); - }, - placeholder: (context, url) => placeholderIcon, - errorWidget: (context, url, error) => placeholderIcon, - ); - } -} diff --git a/lib/shared/input_dialogs.dart b/lib/shared/input_dialogs.dart index b28e4c9c2..c41727242 100644 --- a/lib/shared/input_dialogs.dart +++ b/lib/shared/input_dialogs.dart @@ -15,9 +15,9 @@ import 'package:thunder/core/auth/helpers/fetch_account.dart'; import 'package:thunder/core/enums/full_name_separator.dart'; import 'package:thunder/core/singletons/lemmy_client.dart'; import 'package:thunder/feed/utils/community.dart'; -import 'package:thunder/shared/community_icon.dart'; +import 'package:thunder/shared/avatars/community_avatar.dart'; import 'package:thunder/shared/dialogs.dart'; -import 'package:thunder/shared/user_avatar.dart'; +import 'package:thunder/shared/avatars/user_avatar.dart'; import 'package:thunder/utils/global_context.dart'; import 'package:thunder/utils/instance.dart'; import 'package:thunder/utils/numbers.dart'; @@ -185,7 +185,7 @@ Widget buildCommunitySuggestionWidget(BuildContext context, CommunityView payloa child: InkWell( onTap: onSelected == null ? null : () => onSelected(payload), child: ListTile( - leading: CommunityIcon(community: payload.community), + leading: CommunityAvatar(community: payload.community), title: Text( payload.community.title, maxLines: 1, diff --git a/lib/shared/user_avatar.dart b/lib/shared/user_avatar.dart deleted file mode 100644 index 614747afd..000000000 --- a/lib/shared/user_avatar.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:flutter/material.dart'; -import 'package:lemmy_api_client/v3.dart'; - -class UserAvatar extends StatelessWidget { - final Person? person; - final double radius; - - const UserAvatar({super.key, required this.person, this.radius = 16.0}); - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - - CircleAvatar placeholderIcon = CircleAvatar( - backgroundColor: theme.colorScheme.secondaryContainer, - maxRadius: radius, - child: Text( - person?.displayName?.isNotEmpty == true - ? person!.displayName![0].toUpperCase() - : person?.name.isNotEmpty == true - ? person!.name[0].toUpperCase() - : '', - semanticsLabel: '', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: radius, - ), - )); - - if (person?.avatar?.isNotEmpty != true) return placeholderIcon; - - return CachedNetworkImage( - imageUrl: person?.avatar ?? '', - imageBuilder: (context, imageProvider) { - return CircleAvatar( - backgroundColor: Colors.transparent, - foregroundImage: imageProvider, - maxRadius: radius, - ); - }, - placeholder: (context, url) => placeholderIcon, - errorWidget: (context, url, error) => placeholderIcon, - ); - } -} diff --git a/lib/user/pages/user_settings_page.dart b/lib/user/pages/user_settings_page.dart index 82e4cc63d..e1e0f155b 100644 --- a/lib/user/pages/user_settings_page.dart +++ b/lib/user/pages/user_settings_page.dart @@ -12,11 +12,11 @@ import 'package:thunder/core/singletons/lemmy_client.dart'; import 'package:thunder/feed/feed.dart'; import 'package:thunder/settings/widgets/settings_list_tile.dart'; import 'package:thunder/settings/widgets/toggle_option.dart'; -import 'package:thunder/shared/community_icon.dart'; +import 'package:thunder/shared/avatars/community_avatar.dart'; import 'package:thunder/shared/dialogs.dart'; import 'package:thunder/shared/input_dialogs.dart'; import 'package:thunder/shared/snackbar.dart'; -import 'package:thunder/shared/user_avatar.dart'; +import 'package:thunder/shared/avatars/user_avatar.dart'; import 'package:thunder/thunder/thunder_icons.dart'; import 'package:thunder/user/bloc/user_settings_bloc.dart'; import 'package:thunder/user/widgets/user_indicator.dart'; @@ -372,7 +372,7 @@ class _UserSettingsPageState extends State { navigateToFeedPage(context, feedType: FeedType.community, communityName: '${community.name}@${fetchInstanceNameFromUrl(community.actorId)}'); }, child: ListTile( - leading: CommunityIcon(community: community, radius: 16.0), + leading: CommunityAvatar(community: community, radius: 16.0), visualDensity: const VisualDensity(vertical: -2), title: Text( community.title, diff --git a/lib/user/widgets/user_header.dart b/lib/user/widgets/user_header.dart index 97693ca41..43158f68d 100644 --- a/lib/user/widgets/user_header.dart +++ b/lib/user/widgets/user_header.dart @@ -6,7 +6,7 @@ import 'package:lemmy_api_client/v3.dart'; import 'package:thunder/core/enums/full_name_separator.dart'; import 'package:thunder/shared/icon_text.dart'; -import 'package:thunder/shared/user_avatar.dart'; +import 'package:thunder/shared/avatars/user_avatar.dart'; import 'package:thunder/utils/instance.dart'; import 'package:thunder/utils/numbers.dart'; diff --git a/lib/user/widgets/user_indicator.dart b/lib/user/widgets/user_indicator.dart index 27ab846ef..90b277974 100644 --- a/lib/user/widgets/user_indicator.dart +++ b/lib/user/widgets/user_indicator.dart @@ -5,7 +5,7 @@ import 'package:lemmy_api_client/v3.dart'; import 'package:thunder/account/bloc/account_bloc.dart'; import 'package:thunder/core/enums/full_name_separator.dart'; -import 'package:thunder/shared/user_avatar.dart'; +import 'package:thunder/shared/avatars/user_avatar.dart'; import 'package:thunder/utils/instance.dart'; class UserIndicator extends StatefulWidget { diff --git a/lib/user/widgets/user_sidebar.dart b/lib/user/widgets/user_sidebar.dart index 7baa0694b..f9c094302 100644 --- a/lib/user/widgets/user_sidebar.dart +++ b/lib/user/widgets/user_sidebar.dart @@ -9,7 +9,7 @@ import 'package:thunder/core/auth/bloc/auth_bloc.dart'; import 'package:thunder/core/enums/full_name_separator.dart'; import 'package:thunder/feed/utils/utils.dart'; import 'package:thunder/feed/view/feed_page.dart'; -import 'package:thunder/shared/community_icon.dart'; +import 'package:thunder/shared/avatars/community_avatar.dart'; import 'package:thunder/shared/snackbar.dart'; import 'package:thunder/user/widgets/user_sidebar_activity.dart'; import 'package:thunder/user/widgets/user_sidebar_stats.dart'; @@ -362,7 +362,7 @@ class _UserSidebarState extends State { padding: const EdgeInsets.all(8.0), child: Row( children: [ - CommunityIcon(community: mods.community, radius: 20.0), + CommunityAvatar(community: mods.community, radius: 20.0), const SizedBox(width: 16.0), Expanded( child: Column(