From f494249aeb86f95d7d9b55a3c053159b78f8bcb1 Mon Sep 17 00:00:00 2001 From: Micah Morrison Date: Thu, 21 Mar 2024 10:52:40 -0400 Subject: [PATCH] Add support for user/community styles (#1201) --- lib/community/pages/create_post_page.dart | 2 +- .../utils/post_card_action_helpers.dart | 2 +- lib/community/widgets/community_drawer.dart | 2 +- lib/community/widgets/community_header.dart | 2 +- .../widgets/community_list_entry.dart | 2 +- lib/community/widgets/community_sidebar.dart | 2 +- lib/community/widgets/post_card_metadata.dart | 2 +- lib/core/enums/full_name.dart | 245 +++++++++++++++ lib/core/enums/full_name_separator.dart | 39 --- lib/core/enums/local_settings.dart | 23 +- lib/feed/utils/community_share.dart | 2 +- lib/feed/utils/user_share.dart | 2 +- lib/feed/widgets/feed_fab.dart | 2 +- lib/feed/widgets/feed_page_app_bar.dart | 6 +- lib/inbox/widgets/inbox_mentions_view.dart | 2 +- lib/l10n/app_en.arb | 40 ++- .../widgets/modlog_feed_page_app_bar.dart | 4 +- .../widgets/modlog_item_context_card.dart | 2 +- lib/post/pages/post_page.dart | 2 +- lib/post/utils/comment_action_helpers.dart | 2 +- lib/post/widgets/post_view.dart | 2 +- lib/search/pages/search_page.dart | 10 +- .../comment_appearance_settings_page.dart | 45 +-- lib/settings/pages/fab_settings_page.dart | 4 +- lib/settings/pages/general_settings_page.dart | 292 ++++++++++++++++-- .../pages/post_appearance_settings_page.dart | 6 +- lib/settings/pages/theme_settings_page.dart | 12 +- lib/settings/widgets/list_option.dart | 9 +- lib/settings/widgets/settings_list_tile.dart | 2 +- lib/settings/widgets/swipe_picker.dart | 8 +- lib/shared/comment_header.dart | 179 +++++------ lib/shared/comment_reference.dart | 2 +- lib/shared/cross_posts.dart | 2 +- lib/shared/input_dialogs.dart | 2 +- lib/shared/picker_item.dart | 21 +- lib/thunder/bloc/thunder_bloc.dart | 20 +- lib/thunder/bloc/thunder_state.dart | 45 ++- lib/user/pages/user_settings_page.dart | 2 +- lib/user/widgets/comment_card.dart | 2 +- lib/user/widgets/user_header.dart | 2 +- lib/user/widgets/user_indicator.dart | 2 +- lib/user/widgets/user_list_entry.dart | 2 +- lib/user/widgets/user_sidebar.dart | 2 +- lib/utils/bottom_sheet_list_picker.dart | 153 +++++---- lib/utils/links.dart | 2 +- lib/utils/notifications.dart | 2 +- lib/utils/preferences.dart | 7 + 47 files changed, 903 insertions(+), 319 deletions(-) create mode 100644 lib/core/enums/full_name.dart delete mode 100644 lib/core/enums/full_name_separator.dart diff --git a/lib/community/pages/create_post_page.dart b/lib/community/pages/create_post_page.dart index c8c3b2c68..876d3fe1f 100644 --- a/lib/community/pages/create_post_page.dart +++ b/lib/community/pages/create_post_page.dart @@ -20,7 +20,7 @@ import 'package:thunder/community/bloc/image_bloc.dart'; import 'package:thunder/community/utils/post_card_action_helpers.dart'; import 'package:thunder/core/auth/bloc/auth_bloc.dart'; import 'package:thunder/core/auth/helpers/fetch_account.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/core/enums/local_settings.dart'; import 'package:thunder/core/enums/view_mode.dart'; import 'package:thunder/core/models/post_view_media.dart'; diff --git a/lib/community/utils/post_card_action_helpers.dart b/lib/community/utils/post_card_action_helpers.dart index 7a0982539..b19082f0a 100644 --- a/lib/community/utils/post_card_action_helpers.dart +++ b/lib/community/utils/post_card_action_helpers.dart @@ -11,7 +11,7 @@ import 'package:thunder/account/bloc/account_bloc.dart'; import 'package:thunder/community/bloc/community_bloc.dart'; import 'package:thunder/community/enums/community_action.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/core/enums/media_type.dart'; import 'package:thunder/core/models/post_view_media.dart'; import 'package:thunder/core/singletons/lemmy_client.dart'; diff --git a/lib/community/widgets/community_drawer.dart b/lib/community/widgets/community_drawer.dart index d5e653c3a..5d76bada8 100644 --- a/lib/community/widgets/community_drawer.dart +++ b/lib/community/widgets/community_drawer.dart @@ -16,7 +16,7 @@ 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'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/feed/utils/community.dart'; class CommunityDrawer extends StatefulWidget { diff --git a/lib/community/widgets/community_header.dart b/lib/community/widgets/community_header.dart index efd62b28a..0a25d5445 100644 --- a/lib/community/widgets/community_header.dart +++ b/lib/community/widgets/community_header.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; 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/core/enums/full_name.dart'; import 'package:thunder/shared/avatars/community_avatar.dart'; import 'package:thunder/shared/icon_text.dart'; import 'package:thunder/utils/instance.dart'; diff --git a/lib/community/widgets/community_list_entry.dart b/lib/community/widgets/community_list_entry.dart index 108731b6a..822262f9f 100644 --- a/lib/community/widgets/community_list_entry.dart +++ b/lib/community/widgets/community_list_entry.dart @@ -3,7 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:lemmy_api_client/v3.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:thunder/account/bloc/account_bloc.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/core/singletons/lemmy_client.dart'; import 'package:thunder/feed/utils/utils.dart'; import 'package:thunder/feed/view/feed_page.dart'; diff --git a/lib/community/widgets/community_sidebar.dart b/lib/community/widgets/community_sidebar.dart index 37a2859d3..23a0f43cf 100644 --- a/lib/community/widgets/community_sidebar.dart +++ b/lib/community/widgets/community_sidebar.dart @@ -8,7 +8,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:thunder/community/bloc/community_bloc.dart'; import 'package:thunder/community/enums/community_action.dart'; import 'package:thunder/core/auth/bloc/auth_bloc.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/core/singletons/lemmy_client.dart'; import 'package:thunder/feed/bloc/feed_bloc.dart'; import 'package:thunder/feed/utils/utils.dart'; diff --git a/lib/community/widgets/post_card_metadata.dart b/lib/community/widgets/post_card_metadata.dart index ac5f8f5f2..2e58c45ea 100644 --- a/lib/community/widgets/post_card_metadata.dart +++ b/lib/community/widgets/post_card_metadata.dart @@ -6,7 +6,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:thunder/core/auth/bloc/auth_bloc.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/core/enums/view_mode.dart'; import 'package:thunder/feed/feed.dart'; import 'package:thunder/post/enums/post_card_metadata_item.dart'; diff --git a/lib/core/enums/full_name.dart b/lib/core/enums/full_name.dart new file mode 100644 index 000000000..a9320525d --- /dev/null +++ b/lib/core/enums/full_name.dart @@ -0,0 +1,245 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:thunder/core/enums/font_scale.dart'; +import 'package:thunder/shared/text/scalable_text.dart'; +import 'package:thunder/thunder/bloc/thunder_bloc.dart'; + +enum FullNameSeparator { + dot, // name · instance.tld + at, // name@instance.tld + lemmy; // '@name@instance.tld or !name@instance.tld' +} + +/// --- SAMPLES --- + +String generateSampleUserFullName(FullNameSeparator separator) => generateUserFullName(null, 'name', 'instance.tld', userSeparator: separator); + +Widget generateSampleUserFullNameWidget( + FullNameSeparator separator, { + bool? weightUserName, + bool? weightInstanceName, + bool? colorizeUserName, + bool? colorizeInstanceName, + TextStyle? textStyle, + ColorScheme? colorScheme, +}) => + generateUserFullNameWidget( + null, + 'name', + 'instance.tld', + userSeparator: separator, + weightUserName: weightUserName, + weightInstanceName: weightInstanceName, + colorizeUserName: colorizeUserName, + colorizeInstanceName: colorizeInstanceName, + textStyle: textStyle, + colorScheme: colorScheme, + ); + +String generateSampleCommunityFullName(FullNameSeparator separator) => generateCommunityFullName(null, 'name', 'instance.tld', communitySeparator: separator); + +Widget generateSampleCommunityFullNameWidget( + FullNameSeparator separator, { + bool? weightCommunityName, + bool? weightInstanceName, + bool? colorizeCommunityName, + bool? colorizeInstanceName, + TextStyle? textStyle, + ColorScheme? colorScheme, +}) => + generateCommunityFullNameWidget( + null, + 'name', + 'instance.tld', + communitySeparator: separator, + weightCommunityName: weightCommunityName, + weightInstanceName: weightInstanceName, + colorizeCommunityName: colorizeCommunityName, + colorizeInstanceName: colorizeInstanceName, + textStyle: textStyle, + colorScheme: colorScheme, + ); + +/// --- USERS --- + +String generateUserFullNamePrefix(BuildContext? context, name, {FullNameSeparator? userSeparator}) { + assert(context != null || userSeparator != null); + userSeparator ??= context!.read().state.userSeparator; + return switch (userSeparator) { + FullNameSeparator.dot => '$name', + FullNameSeparator.at => '$name', + FullNameSeparator.lemmy => '@$name', + }; +} + +String generateUserFullNameSuffix(BuildContext? context, instance, {FullNameSeparator? userSeparator}) { + assert(context != null || userSeparator != null); + userSeparator ??= context!.read().state.userSeparator; + return switch (userSeparator) { + FullNameSeparator.dot => ' · $instance', + FullNameSeparator.at => '@$instance', + FullNameSeparator.lemmy => '@$instance', + }; +} + +String generateUserFullName(BuildContext? context, name, instance, {FullNameSeparator? userSeparator}) { + assert(context != null || userSeparator != null); + userSeparator ??= context!.read().state.userSeparator; + String prefix = generateUserFullNamePrefix(context, name, userSeparator: userSeparator); + String suffix = generateUserFullNameSuffix(context, instance, userSeparator: userSeparator); + return '$prefix$suffix'; +} + +Text generateUserFullNameWidget( + BuildContext? context, + name, + instance, { + FullNameSeparator? userSeparator, + bool? weightUserName, + bool? weightInstanceName, + bool? colorizeUserName, + bool? colorizeInstanceName, + TextStyle? textStyle, + ColorScheme? colorScheme, + bool includeInstance = true, + FontScale? fontScale, +}) { + assert(context != null || (userSeparator != null && weightUserName != null && weightInstanceName != null && colorizeUserName != null && colorizeInstanceName != null)); + assert(context != null || (textStyle != null && colorScheme != null)); + String prefix = generateUserFullNamePrefix(context, name, userSeparator: userSeparator); + String suffix = generateUserFullNameSuffix(context, instance, userSeparator: userSeparator); + weightUserName ??= context!.read().state.userFullNameWeightUserName; + weightInstanceName ??= context!.read().state.userFullNameWeightInstanceName; + colorizeUserName ??= context!.read().state.userFullNameColorizeUserName; + colorizeInstanceName ??= context!.read().state.userFullNameColorizeInstanceName; + textStyle ??= Theme.of(context!).textTheme.bodyMedium; + colorScheme ??= Theme.of(context!).colorScheme; + + return Text.rich( + softWrap: false, + overflow: TextOverflow.fade, + style: textStyle, + textScaler: TextScaler.noScaling, + TextSpan( + children: [ + TextSpan( + text: prefix, + style: textStyle!.copyWith( + fontWeight: weightUserName + ? FontWeight.w500 + : weightInstanceName + ? FontWeight.w300 + : null, + color: colorizeUserName ? colorScheme.primary : null, + fontSize: context == null ? null : MediaQuery.textScalerOf(context).scale((textStyle.fontSize ?? textStyle.fontSize!) * (fontScale?.textScaleFactor ?? FontScale.base.textScaleFactor)), + ), + ), + if (includeInstance == true) + TextSpan( + text: suffix, + style: textStyle.copyWith( + fontWeight: weightInstanceName + ? FontWeight.w500 + : weightUserName + ? FontWeight.w300 + : null, + color: colorizeInstanceName ? colorScheme.primary : null, + fontSize: context == null ? null : MediaQuery.textScalerOf(context).scale((textStyle.fontSize ?? textStyle.fontSize!) * (fontScale?.textScaleFactor ?? FontScale.base.textScaleFactor)), + ), + ), + ], + ), + ); +} + +/// --- COMMUNITIES --- + +String generateCommunityFullNamePrefix(BuildContext? context, name, {FullNameSeparator? communitySeparator}) { + assert(context != null || communitySeparator != null); + communitySeparator ??= context!.read().state.communitySeparator; + return switch (communitySeparator) { + FullNameSeparator.dot => '$name', + FullNameSeparator.at => '$name', + FullNameSeparator.lemmy => '!$name', + }; +} + +String generateCommunityFullNameSuffix(BuildContext? context, instance, {FullNameSeparator? communitySeparator}) { + assert(context != null || communitySeparator != null); + communitySeparator ??= context!.read().state.communitySeparator; + return switch (communitySeparator) { + FullNameSeparator.dot => ' · $instance', + FullNameSeparator.at => '@$instance', + FullNameSeparator.lemmy => '@$instance', + }; +} + +String generateCommunityFullName(BuildContext? context, name, instance, {FullNameSeparator? communitySeparator}) { + assert(context != null || communitySeparator != null); + communitySeparator ??= context!.read().state.communitySeparator; + String prefix = generateCommunityFullNamePrefix(context, name, communitySeparator: communitySeparator); + String suffix = generateCommunityFullNameSuffix(context, instance, communitySeparator: communitySeparator); + return '$prefix$suffix'; +} + +Text generateCommunityFullNameWidget( + BuildContext? context, + name, + instance, { + FullNameSeparator? communitySeparator, + bool? weightCommunityName, + bool? weightInstanceName, + bool? colorizeCommunityName, + bool? colorizeInstanceName, + TextStyle? textStyle, + ColorScheme? colorScheme, + bool includeInstance = true, + FontScale? fontScale, +}) { + assert(context != null || (communitySeparator != null && weightCommunityName != null && weightInstanceName != null && colorizeCommunityName != null && colorizeInstanceName != null)); + assert(context != null || (textStyle != null && colorScheme != null)); + String prefix = generateCommunityFullNamePrefix(context, name, communitySeparator: communitySeparator); + String suffix = generateCommunityFullNameSuffix(context, instance, communitySeparator: communitySeparator); + weightCommunityName ??= context!.read().state.communityFullNameWeightCommunityName; + weightInstanceName ??= context!.read().state.communityFullNameWeightInstanceName; + colorizeCommunityName ??= context!.read().state.communityFullNameColorizeCommunityName; + colorizeInstanceName ??= context!.read().state.communityFullNameColorizeInstanceName; + textStyle ??= Theme.of(context!).textTheme.bodyMedium; + colorScheme ??= Theme.of(context!).colorScheme; + + return Text.rich( + softWrap: false, + overflow: TextOverflow.fade, + style: textStyle, + textScaler: TextScaler.noScaling, + TextSpan( + children: [ + TextSpan( + text: prefix, + style: textStyle!.copyWith( + fontWeight: weightCommunityName + ? FontWeight.w500 + : weightInstanceName + ? FontWeight.w300 + : null, + color: colorizeCommunityName ? colorScheme.primary : null, + fontSize: context == null ? null : MediaQuery.textScalerOf(context).scale((textStyle.fontSize ?? textStyle.fontSize!) * (fontScale?.textScaleFactor ?? FontScale.base.textScaleFactor)), + ), + ), + if (includeInstance == true) + TextSpan( + text: suffix, + style: textStyle.copyWith( + fontWeight: weightInstanceName + ? FontWeight.w500 + : weightCommunityName + ? FontWeight.w300 + : null, + color: colorizeInstanceName ? colorScheme.primary : null, + fontSize: context == null ? null : MediaQuery.textScalerOf(context).scale((textStyle.fontSize ?? textStyle.fontSize!) * (fontScale?.textScaleFactor ?? FontScale.base.textScaleFactor)), + ), + ), + ], + ), + ); +} diff --git a/lib/core/enums/full_name_separator.dart b/lib/core/enums/full_name_separator.dart deleted file mode 100644 index 449758fb7..000000000 --- a/lib/core/enums/full_name_separator.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:thunder/thunder/bloc/thunder_bloc.dart'; - -enum FullNameSeparator { - dot, // name · instance.tld - at, // name@instance.tld - lemmy; // '@name@instance.tld or !name@instance.tld' -} - -String generateUserFullName(BuildContext? context, name, instance, {FullNameSeparator? userSeparator}) { - assert(context != null || userSeparator != null); - userSeparator ??= context!.read().state.userSeparator; - return switch (userSeparator) { - FullNameSeparator.dot => '$name · $instance', - FullNameSeparator.at => '$name@$instance', - FullNameSeparator.lemmy => '@$name@$instance', - }; -} - -String generateUserFullNameSuffix(BuildContext? context, instance, {FullNameSeparator? userSeparator}) { - assert(context != null || userSeparator != null); - userSeparator ??= context!.read().state.userSeparator; - return switch (userSeparator) { - FullNameSeparator.dot => ' · $instance', - FullNameSeparator.at => '@$instance', - FullNameSeparator.lemmy => '@$instance', - }; -} - -String generateCommunityFullName(BuildContext? context, name, instance, {FullNameSeparator? communitySeparator}) { - assert(context != null || communitySeparator != null); - communitySeparator ??= context!.read().state.communitySeparator; - return switch (communitySeparator) { - FullNameSeparator.dot => '$name · $instance', - FullNameSeparator.at => '$name@$instance', - FullNameSeparator.lemmy => '!$name@$instance', - }; -} diff --git a/lib/core/enums/local_settings.dart b/lib/core/enums/local_settings.dart index c88e0f9e6..134ce734d 100644 --- a/lib/core/enums/local_settings.dart +++ b/lib/core/enums/local_settings.dart @@ -129,7 +129,19 @@ enum LocalSettings { // Advanced Settings userFormat(name: 'user_format', key: 'userFormat', category: LocalSettingsCategories.general, subCategory: LocalSettingsSubCategories.advanced), + // This setting exists purely for the searching function + userStyle(name: '', key: 'userStyle', category: LocalSettingsCategories.general, subCategory: LocalSettingsSubCategories.advanced), + userFullNameWeightUserName(name: 'user_fullname_weight_user_name', key: '', category: LocalSettingsCategories.general, subCategory: LocalSettingsSubCategories.advanced), + userFullNameWeightInstanceName(name: 'user_fullname_instance_name', key: '', category: LocalSettingsCategories.general, subCategory: LocalSettingsSubCategories.advanced), + userFullNameColorizeUserName(name: 'user_fullname_colorize_user_name', key: '', category: LocalSettingsCategories.general, subCategory: LocalSettingsSubCategories.advanced), + userFullNameColorizeInstanceName(name: 'user_fullname_colorize_instance_name', key: '', category: LocalSettingsCategories.general, subCategory: LocalSettingsSubCategories.advanced), + // This setting exists purely for the searching function + communityStyle(name: '', key: 'communityStyle', category: LocalSettingsCategories.general, subCategory: LocalSettingsSubCategories.advanced), communityFormat(name: 'community_format', key: 'communityFormat', category: LocalSettingsCategories.general, subCategory: LocalSettingsSubCategories.advanced), + communityFullNameWeightCommunityName(name: 'community_fullname_weight_user_name', key: '', category: LocalSettingsCategories.general, subCategory: LocalSettingsSubCategories.advanced), + communityFullNameWeightInstanceName(name: 'community_fullname_instance_name', key: '', category: LocalSettingsCategories.general, subCategory: LocalSettingsSubCategories.advanced), + communityFullNameColorizeCommunityName(name: 'community_fullname_colorize_user_name', key: '', category: LocalSettingsCategories.general, subCategory: LocalSettingsSubCategories.advanced), + communityFullNameColorizeInstanceName(name: 'community_fullname_colorize_instance_name', key: '', category: LocalSettingsCategories.general, subCategory: LocalSettingsSubCategories.advanced), imageCachingMode(name: 'setting_advanced_image_caching_mode', key: 'imageCachingMode', category: LocalSettingsCategories.general, subCategory: LocalSettingsSubCategories.advanced), /// -------------------------- Post Page Related Settings -------------------------- @@ -149,8 +161,14 @@ enum LocalSettings { name: 'setting_general_nested_comment_indicator_style', key: 'nestedCommentIndicatorStyle', category: LocalSettingsCategories.comments, subCategory: LocalSettingsSubCategories.comments), nestedCommentIndicatorColor( name: 'setting_general_nested_comment_indicator_color', key: 'nestedCommentIndicatorColor', category: LocalSettingsCategories.comments, subCategory: LocalSettingsSubCategories.comments), + // Deprecated, use userFullNameColorizeUserName commentUseColorizedUsername( - name: 'settings_general_comments_colorized_usernames', key: 'commentUseColorizedUsername', category: LocalSettingsCategories.comments, subCategory: LocalSettingsSubCategories.comments), + name: 'settings_general_comments_colorized_usernames', + key: 'commentUseColorizedUsername', + category: LocalSettingsCategories.comments, + subCategory: LocalSettingsSubCategories.comments, + searchable: false, + ), /// -------------------------- Accessibility Related Settings -------------------------- reduceAnimations(name: 'setting_accessibility_reduce_animations', key: 'reduceAnimations', category: LocalSettingsCategories.accessibility, subCategory: LocalSettingsSubCategories.animations), @@ -302,7 +320,9 @@ extension LocalizationExt on AppLocalizations { 'compactPostCardMetadataItems': compactPostCardMetadataItems, 'cardPostCardMetadataItems': cardPostCardMetadataItems, 'userFormat': userFormat, + 'userStyle': userStyle, 'communityFormat': communityFormat, + 'communityStyle': communityStyle, 'imageCachingMode': imageCachingMode, 'defaultCommentSortType': defaultCommentSortType, 'collapseParentCommentBodyOnGesture': collapseParentCommentBodyOnGesture, @@ -358,7 +378,6 @@ extension LocalizationExt on AppLocalizations { 'feedTypeAndSorts': feedTypeAndSorts, 'profiles': profiles, 'animations': animations, - 'commentUseColorizedUsername': commentUseColorizedUsername }; if (localizationMap.containsKey(key)) { diff --git a/lib/feed/utils/community_share.dart b/lib/feed/utils/community_share.dart index 3e8878f38..2d0578503 100644 --- a/lib/feed/utils/community_share.dart +++ b/lib/feed/utils/community_share.dart @@ -48,7 +48,7 @@ Future showCommunityShareSheet(BuildContext context, CommunityView communi icon: Icons.share_rounded, ), ], - onSelect: (selection) { + onSelect: (selection) async { switch (selection.payload) { case CommunityShareOptions.link: Share.share(communityView.community.actorId); diff --git a/lib/feed/utils/user_share.dart b/lib/feed/utils/user_share.dart index f7977d3a6..6a7d3d6a4 100644 --- a/lib/feed/utils/user_share.dart +++ b/lib/feed/utils/user_share.dart @@ -48,7 +48,7 @@ Future showUserShareSheet(BuildContext context, PersonView personView) asy icon: Icons.share_rounded, ), ], - onSelect: (selection) { + onSelect: (selection) async { switch (selection.payload) { case UserShareOptions.link: Share.share(personView.person.actorId); diff --git a/lib/feed/widgets/feed_fab.dart b/lib/feed/widgets/feed_fab.dart index bc195450a..adfe341ac 100644 --- a/lib/feed/widgets/feed_fab.dart +++ b/lib/feed/widgets/feed_fab.dart @@ -285,7 +285,7 @@ class FeedFAB extends StatelessWidget { isScrollControlled: true, builder: (builderContext) => SortPicker( title: l10n.sortOptions, - onSelect: (selected) => context.read().add(FeedChangeSortTypeEvent(selected.payload)), + onSelect: (selected) async => context.read().add(FeedChangeSortTypeEvent(selected.payload)), previouslySelected: context.read().state.sortType, ), ); diff --git a/lib/feed/widgets/feed_page_app_bar.dart b/lib/feed/widgets/feed_page_app_bar.dart index fb9b73455..23437661c 100644 --- a/lib/feed/widgets/feed_page_app_bar.dart +++ b/lib/feed/widgets/feed_page_app_bar.dart @@ -166,7 +166,7 @@ class FeedAppBarCommunityActions extends StatelessWidget { isScrollControlled: true, builder: (builderContext) => SortPicker( title: l10n.sortOptions, - onSelect: (selected) => feedBloc.add(FeedChangeSortTypeEvent(selected.payload)), + onSelect: (selected) async => feedBloc.add(FeedChangeSortTypeEvent(selected.payload)), previouslySelected: feedBloc.state.sortType, ), ); @@ -273,7 +273,7 @@ class FeedAppBarUserActions extends StatelessWidget { isScrollControlled: true, builder: (builderContext) => SortPicker( title: l10n.sortOptions, - onSelect: (selected) => feedBloc.add(FeedChangeSortTypeEvent(selected.payload)), + onSelect: (selected) async => feedBloc.add(FeedChangeSortTypeEvent(selected.payload)), previouslySelected: feedBloc.state.sortType, ), ); @@ -328,7 +328,7 @@ class FeedAppBarGeneralActions extends StatelessWidget { isScrollControlled: true, builder: (builderContext) => SortPicker( title: l10n.sortOptions, - onSelect: (selected) => feedBloc.add(FeedChangeSortTypeEvent(selected.payload)), + onSelect: (selected) async => feedBloc.add(FeedChangeSortTypeEvent(selected.payload)), previouslySelected: feedBloc.state.sortType, ), ); diff --git a/lib/inbox/widgets/inbox_mentions_view.dart b/lib/inbox/widgets/inbox_mentions_view.dart index 573428ab5..902873bdb 100644 --- a/lib/inbox/widgets/inbox_mentions_view.dart +++ b/lib/inbox/widgets/inbox_mentions_view.dart @@ -10,7 +10,7 @@ import 'package:swipeable_page_route/swipeable_page_route.dart'; import 'package:thunder/account/bloc/account_bloc.dart'; import 'package:thunder/core/auth/bloc/auth_bloc.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/core/enums/local_settings.dart'; import 'package:thunder/core/models/post_view_media.dart'; import 'package:thunder/core/singletons/preferences.dart'; diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index eb3373924..b516a1ce2 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -113,6 +113,18 @@ "@blockedInstances": {}, "blockedUsers": "Blocked Users", "@blockedUsers": {}, + "boldCommunityName": "Bold Community Name", + "@boldCommunityName": { + "description": "Setting for bolding the community name" + }, + "boldInstanceName": "Bold Instance Name", + "@boldInstanceName": { + "description": "Setting for bolding the instance name" + }, + "boldUserName": "Bold User Name", + "@boldUserName": { + "description": "Setting for bolding the username" + }, "browserMode": "Link handling", "@browserMode": { "description": "Title for link handling setting (called browserMode internally)" @@ -199,6 +211,18 @@ "@collapseSpoiler": { "description": "Label for collapsing spoiler" }, + "colorizeCommunityName": "Colorize Community Name", + "@colorizeCommunityName": { + "description": "Setting for colorizing community name" + }, + "colorizeInstanceName": "Colorize Instance Name", + "@colorizeInstanceName": { + "description": "Setting for colorizing instance name" + }, + "colorizeUserName": "Colorize User Name", + "@colorizeUserName": { + "description": "Setting for colorizing username" + }, "combineCommentScores": "Combine Comment Scores", "@combineCommentScores": { "description": "Toggle to combine comment scores." @@ -241,10 +265,6 @@ }, "commentSwipeGesturesHint": "Looking to use buttons instead? Enable them in the comments section in general settings.", "@commentSwipeGesturesHint": {}, - "commentUseColorizedUsername": "Colorized Usernames", - "@commentUseColorizedUsername": { - "description": "Setting used to toggle colorized comments creator display name." - }, "comments": "Comments", "@comments": {}, "communities": "Communities", @@ -263,6 +283,10 @@ "@communityFormat": { "description": "Setting for community full name format" }, + "communityStyle": "Community Style", + "@communityStyle": { + "description": "Heading for community style setting" + }, "compactPostCardMetadataItems": "Compact View Metadata", "@compactPostCardMetadataItems": { "description": "Name of setting for compact post card metadata items" @@ -1775,8 +1799,16 @@ "@userSettingDescription": { "description": "Description which explains that the settings are applied globally to the current user." }, + "userStyle": "User Style", + "@userStyle": { + "description": "Heading for user style setting" + }, "username": "Username", "@username": {}, + "usernameFormattingRedirect": "Looking for username formatting?", + "@usernameFormattingRedirect": { + "description": "Setting title for sending the user to the new formatting options" + }, "users": "Users", "@users": {}, "versionNumber": "Version {version}", diff --git a/lib/modlog/widgets/modlog_feed_page_app_bar.dart b/lib/modlog/widgets/modlog_feed_page_app_bar.dart index b5f82843a..af6645f0d 100644 --- a/lib/modlog/widgets/modlog_feed_page_app_bar.dart +++ b/lib/modlog/widgets/modlog_feed_page_app_bar.dart @@ -7,7 +7,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:thunder/core/auth/bloc/auth_bloc.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/core/singletons/lemmy_client.dart'; import 'package:thunder/feed/bloc/feed_bloc.dart'; import 'package:thunder/modlog/bloc/modlog_bloc.dart'; @@ -61,7 +61,7 @@ class ModlogFeedPageAppBar extends StatelessWidget { isScrollControlled: true, builder: (builderContext) => ModlogActionTypePicker( title: l10n.filters, - onSelect: (selected) => context.read().add(ModlogFeedChangeFilterTypeEvent(modlogActionType: selected.payload)), + onSelect: (selected) async => context.read().add(ModlogFeedChangeFilterTypeEvent(modlogActionType: selected.payload)), previouslySelected: context.read().state.modlogActionType, ), ); diff --git a/lib/modlog/widgets/modlog_item_context_card.dart b/lib/modlog/widgets/modlog_item_context_card.dart index fc89f6b29..439be6039 100644 --- a/lib/modlog/widgets/modlog_item_context_card.dart +++ b/lib/modlog/widgets/modlog_item_context_card.dart @@ -6,7 +6,7 @@ import 'package:html_unescape/html_unescape_small.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:thunder/core/enums/font_scale.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/feed/utils/utils.dart'; import 'package:thunder/feed/view/feed_page.dart'; import 'package:thunder/post/utils/navigate_post.dart'; diff --git a/lib/post/pages/post_page.dart b/lib/post/pages/post_page.dart index 3af80a1a3..892e2a2dd 100644 --- a/lib/post/pages/post_page.dart +++ b/lib/post/pages/post_page.dart @@ -543,7 +543,7 @@ class _PostPageState extends State { context: context, builder: (builderContext) => CommentSortPicker( title: l10n.sortOptions, - onSelect: (selected) { + onSelect: (selected) async { setState(() { sortType = selected.payload; sortTypeLabel = selected.label; diff --git a/lib/post/utils/comment_action_helpers.dart b/lib/post/utils/comment_action_helpers.dart index 4bf740d82..43e21b04a 100644 --- a/lib/post/utils/comment_action_helpers.dart +++ b/lib/post/utils/comment_action_helpers.dart @@ -6,7 +6,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:lemmy_api_client/v3.dart'; import 'package:share_plus/share_plus.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/core/singletons/lemmy_client.dart'; import 'package:thunder/feed/utils/utils.dart'; import 'package:thunder/feed/view/feed_page.dart'; diff --git a/lib/post/widgets/post_view.dart b/lib/post/widgets/post_view.dart index 106f70549..04bcd05a1 100644 --- a/lib/post/widgets/post_view.dart +++ b/lib/post/widgets/post_view.dart @@ -22,7 +22,7 @@ import 'package:thunder/community/widgets/post_card_metadata.dart'; import 'package:thunder/community/widgets/post_card_type_badge.dart'; import 'package:thunder/core/auth/helpers/fetch_account.dart'; import 'package:thunder/core/enums/font_scale.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/core/enums/local_settings.dart'; import 'package:thunder/core/enums/media_type.dart'; import 'package:thunder/core/enums/post_body_view_type.dart'; diff --git a/lib/search/pages/search_page.dart b/lib/search/pages/search_page.dart index 3adcd9fef..6e0db8dec 100644 --- a/lib/search/pages/search_page.dart +++ b/lib/search/pages/search_page.dart @@ -18,7 +18,7 @@ import 'package:thunder/community/bloc/anonymous_subscriptions_bloc.dart'; import 'package:thunder/community/widgets/community_list_entry.dart'; import 'package:thunder/core/auth/bloc/auth_bloc.dart'; import 'package:thunder/core/auth/helpers/fetch_account.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/core/enums/meta_search_type.dart'; import 'package:thunder/core/singletons/lemmy_client.dart'; import 'package:thunder/core/singletons/preferences.dart'; @@ -293,7 +293,7 @@ class _SearchPageState extends State with AutomaticKeepAliveClientMi ListPickerItem(label: l10n.comments, payload: MetaSearchType.comments, icon: Icons.chat_rounded), if (widget.communityToSearch == null) ListPickerItem(label: l10n.instance(2), payload: MetaSearchType.instances, icon: Icons.language), ], - onSelect: (value) => _setCurrentSearchType(value.payload), + onSelect: (value) async => _setCurrentSearchType(value.payload), previouslySelected: _currentSearchType, ), ); @@ -318,7 +318,7 @@ class _SearchPageState extends State with AutomaticKeepAliveClientMi ListPickerItem(label: l10n.searchByText, payload: 'text', icon: Icons.wysiwyg_rounded), ListPickerItem(label: l10n.searchByUrl, payload: 'url', icon: Icons.link_rounded), ], - onSelect: (value) { + onSelect: (value) async { setState(() { _searchByUrl = value.payload == 'url'; _searchUrlLabel = value.payload == 'url' ? l10n.url : l10n.text; @@ -362,7 +362,7 @@ class _SearchPageState extends State with AutomaticKeepAliveClientMi ListPickerItem(label: l10n.local, payload: ListingType.local, icon: Icons.home_rounded), ListPickerItem(label: l10n.all, payload: ListingType.all, icon: Icons.grid_view_rounded) ], - onSelect: (value) { + onSelect: (value) async { setState(() { if (value.payload == ListingType.subscribed) { _feedTypeLabel = l10n.subscribed; @@ -804,7 +804,7 @@ class _SearchPageState extends State with AutomaticKeepAliveClientMi isScrollControlled: true, builder: (builderContext) => SortPicker( title: l10n.sortOptions, - onSelect: (selected) { + onSelect: (selected) async { setState(() { sortType = selected.payload; sortTypeIcon = selected.icon; diff --git a/lib/settings/pages/comment_appearance_settings_page.dart b/lib/settings/pages/comment_appearance_settings_page.dart index c11f94bcc..7e05149e9 100644 --- a/lib/settings/pages/comment_appearance_settings_page.dart +++ b/lib/settings/pages/comment_appearance_settings_page.dart @@ -5,8 +5,8 @@ import 'package:flutter/material.dart'; import 'package:expandable/expandable.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:go_router/go_router.dart'; import 'package:lemmy_api_client/v3.dart'; -import 'package:smooth_highlight/smooth_highlight.dart'; import 'package:thunder/core/enums/local_settings.dart'; import 'package:thunder/core/enums/nested_comment_indicator.dart'; @@ -15,6 +15,7 @@ import 'package:thunder/core/singletons/preferences.dart'; import 'package:thunder/post/bloc/post_bloc.dart'; import 'package:thunder/post/widgets/comment_card.dart'; import 'package:thunder/settings/widgets/list_option.dart'; +import 'package:thunder/settings/widgets/settings_list_tile.dart'; import 'package:thunder/settings/widgets/toggle_option.dart'; import 'package:thunder/shared/dialogs.dart'; import 'package:thunder/thunder/bloc/thunder_bloc.dart'; @@ -41,9 +42,6 @@ class _CommentAppearanceSettingsPageState extends State nestedIndicatorColor = NestedCommentIndicatorColor.values.byName(value ?? DEFAULT_NESTED_COMMENT_INDICATOR_COLOR.name)); break; - case LocalSettings.commentUseColorizedUsername: - await prefs.setBool(LocalSettings.commentUseColorizedUsername.name, value); - setState(() => commentUseColorizedUsername = value); } if (context.mounted) { @@ -118,7 +112,6 @@ class _CommentAppearanceSettingsPageState extends State setPreferences(LocalSettings.commentUseColorizedUsername, value), - highlightKey: settingToHighlight == LocalSettings.commentUseColorizedUsername ? settingToHighlightKey : null, - ), - ), + SliverToBoxAdapter( child: ListOption( description: l10n.nestedCommentIndicatorStyle, @@ -374,7 +358,7 @@ class _CommentAppearanceSettingsPageState extends State setPreferences(LocalSettings.nestedCommentIndicatorStyle, value.payload.name), + onChanged: (value) async => setPreferences(LocalSettings.nestedCommentIndicatorStyle, value.payload.name), highlightKey: settingToHighlight == LocalSettings.nestedCommentIndicatorStyle ? settingToHighlightKey : null, ), ), @@ -387,10 +371,29 @@ class _CommentAppearanceSettingsPageState extends State setPreferences(LocalSettings.nestedCommentIndicatorColor, value.payload.name), + onChanged: (value) async => setPreferences(LocalSettings.nestedCommentIndicatorColor, value.payload.name), highlightKey: settingToHighlight == LocalSettings.nestedCommentIndicatorColor ? settingToHighlightKey : null, ), ), + SliverToBoxAdapter( + child: SettingsListTile( + icon: Icons.alternate_email_rounded, + description: l10n.usernameFormattingRedirect, + widget: const SizedBox( + height: 42.0, + child: Icon(Icons.chevron_right_rounded), + ), + onTap: () { + GoRouter.of(context).push( + SETTINGS_GENERAL_PAGE, + extra: [ + context.read(), + LocalSettings.userStyle, + ], + ); + }, + ), + ), const SliverToBoxAdapter(child: SizedBox(height: 128.0)), ], ), diff --git a/lib/settings/pages/fab_settings_page.dart b/lib/settings/pages/fab_settings_page.dart index afb7f84fd..0f115b8bb 100644 --- a/lib/settings/pages/fab_settings_page.dart +++ b/lib/settings/pages/fab_settings_page.dart @@ -615,7 +615,7 @@ class _FabSettingsPage extends State with TickerProviderStateMi ListPickerItem(label: l10n.setShortPress, payload: 'short', icon: Icons.touch_app_outlined), ListPickerItem(label: l10n.setLongPress, payload: 'long', icon: Icons.touch_app_rounded), ], - onSelect: (value) { + onSelect: (value) async { if (value.payload == 'short') { setPreferences(LocalSettings.feedFabSinglePressAction, action); } @@ -639,7 +639,7 @@ class _FabSettingsPage extends State with TickerProviderStateMi ListPickerItem(label: l10n.setShortPress, payload: 'short', icon: Icons.touch_app_outlined), ListPickerItem(label: l10n.setLongPress, payload: 'long', icon: Icons.touch_app_rounded), ], - onSelect: (value) { + onSelect: (value) async { if (value.payload == 'short') { setPreferences(LocalSettings.postFabSinglePressAction, action); } diff --git a/lib/settings/pages/general_settings_page.dart b/lib/settings/pages/general_settings_page.dart index 252ce05d2..6cbdcb623 100644 --- a/lib/settings/pages/general_settings_page.dart +++ b/lib/settings/pages/general_settings_page.dart @@ -11,8 +11,7 @@ import 'package:permission_handler/permission_handler.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:thunder/core/enums/browser_mode.dart'; -import 'package:smooth_highlight/smooth_highlight.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/core/enums/image_caching_mode.dart'; import 'package:thunder/core/enums/local_settings.dart'; @@ -107,9 +106,21 @@ class _GeneralSettingsPageState extends State with SingleTi /// Defines the separator used to denote full usernames FullNameSeparator userSeparator = FullNameSeparator.at; + /// Defines the style used to denote full usernames + bool userFullNameWeightUserName = true; + bool userFullNameWeightInstanceName = false; + bool userFullNameColorizeUserName = false; + bool userFullNameColorizeInstanceName = false; + /// Defines the separator used to denote full commuity names FullNameSeparator communitySeparator = FullNameSeparator.dot; + /// Defines the style used to denote full community names + bool communityFullNameWeightCommunityName = false; + bool communityFullNameWeightInstanceName = false; + bool communityFullNameColorizeCommunityName = false; + bool communityFullNameColorizeInstanceName = false; + /// Defines the image caching mode ImageCachingMode imageCachingMode = ImageCachingMode.relaxed; @@ -118,7 +129,7 @@ class _GeneralSettingsPageState extends State with SingleTi GlobalKey settingToHighlightKey = GlobalKey(); LocalSettings? settingToHighlight; - void setPreferences(attribute, value) async { + Future setPreferences(attribute, value) async { final prefs = (await UserPreferences.instance).sharedPreferences; switch (attribute) { @@ -206,10 +217,42 @@ class _GeneralSettingsPageState extends State with SingleTi await prefs.setString(LocalSettings.userFormat.name, value); setState(() => userSeparator = FullNameSeparator.values.byName(value ?? FullNameSeparator.at)); break; + case LocalSettings.userFullNameWeightUserName: + await prefs.setBool(LocalSettings.userFullNameWeightUserName.name, value); + setState(() => userFullNameWeightUserName = value); + break; + case LocalSettings.userFullNameWeightInstanceName: + await prefs.setBool(LocalSettings.userFullNameWeightInstanceName.name, value); + setState(() => userFullNameWeightInstanceName = value); + break; + case LocalSettings.userFullNameColorizeUserName: + await prefs.setBool(LocalSettings.userFullNameColorizeUserName.name, value); + setState(() => userFullNameColorizeUserName = value); + break; + case LocalSettings.userFullNameColorizeInstanceName: + await prefs.setBool(LocalSettings.userFullNameColorizeInstanceName.name, value); + setState(() => userFullNameColorizeInstanceName = value); + break; case LocalSettings.communityFormat: await prefs.setString(LocalSettings.communityFormat.name, value); setState(() => communitySeparator = FullNameSeparator.values.byName(value ?? FullNameSeparator.dot)); break; + case LocalSettings.communityFullNameWeightCommunityName: + await prefs.setBool(LocalSettings.communityFullNameWeightCommunityName.name, value); + setState(() => communityFullNameWeightCommunityName = value); + break; + case LocalSettings.communityFullNameWeightInstanceName: + await prefs.setBool(LocalSettings.communityFullNameWeightInstanceName.name, value); + setState(() => communityFullNameWeightInstanceName = value); + break; + case LocalSettings.communityFullNameColorizeCommunityName: + await prefs.setBool(LocalSettings.communityFullNameColorizeCommunityName.name, value); + setState(() => communityFullNameColorizeCommunityName = value); + break; + case LocalSettings.communityFullNameColorizeInstanceName: + await prefs.setBool(LocalSettings.communityFullNameColorizeInstanceName.name, value); + setState(() => communityFullNameColorizeInstanceName = value); + break; case LocalSettings.imageCachingMode: await prefs.setString(LocalSettings.imageCachingMode.name, value); setState(() => imageCachingMode = ImageCachingMode.values.byName(value ?? ImageCachingMode.relaxed)); @@ -254,7 +297,15 @@ class _GeneralSettingsPageState extends State with SingleTi scrapeMissingPreviews = prefs.getBool(LocalSettings.scrapeMissingPreviews.name) ?? false; userSeparator = FullNameSeparator.values.byName(prefs.getString(LocalSettings.userFormat.name) ?? FullNameSeparator.at.name); + userFullNameWeightUserName = prefs.getBool(LocalSettings.userFullNameWeightUserName.name) ?? true; + userFullNameWeightInstanceName = prefs.getBool(LocalSettings.userFullNameWeightInstanceName.name) ?? false; + userFullNameColorizeUserName = prefs.getBool(LocalSettings.userFullNameColorizeUserName.name) ?? false; + userFullNameColorizeInstanceName = prefs.getBool(LocalSettings.userFullNameColorizeInstanceName.name) ?? false; communitySeparator = FullNameSeparator.values.byName(prefs.getString(LocalSettings.communityFormat.name) ?? FullNameSeparator.dot.name); + communityFullNameWeightCommunityName = prefs.getBool(LocalSettings.communityFullNameWeightCommunityName.name) ?? false; + communityFullNameWeightInstanceName = prefs.getBool(LocalSettings.communityFullNameWeightInstanceName.name) ?? false; + communityFullNameColorizeCommunityName = prefs.getBool(LocalSettings.communityFullNameColorizeCommunityName.name) ?? false; + communityFullNameColorizeInstanceName = prefs.getBool(LocalSettings.communityFullNameColorizeInstanceName.name) ?? false; imageCachingMode = ImageCachingMode.values.byName(prefs.getString(LocalSettings.imageCachingMode.name) ?? ImageCachingMode.relaxed.name); showInAppUpdateNotification = prefs.getBool(LocalSettings.showInAppUpdateNotification.name) ?? false; @@ -341,12 +392,12 @@ class _GeneralSettingsPageState extends State with SingleTi value: ListPickerItem(label: defaultSortType.value, icon: Icons.local_fire_department_rounded, payload: defaultSortType), options: [...SortPicker.getDefaultSortTypeItems(includeVersionSpecificFeature: IncludeVersionSpecificFeature.never), ...topSortTypeItems], icon: Icons.sort_rounded, - onChanged: (_) {}, + onChanged: (_) async {}, isBottomModalScrollControlled: true, customListPicker: SortPicker( includeVersionSpecificFeature: IncludeVersionSpecificFeature.never, title: l10n.defaultFeedSortType, - onSelect: (value) { + onSelect: (value) async { setPreferences(LocalSettings.defaultFeedSortType, value.payload.name); }, previouslySelected: defaultSortType, @@ -370,11 +421,11 @@ class _GeneralSettingsPageState extends State with SingleTi value: ListPickerItem(label: defaultCommentSortType.value, icon: Icons.local_fire_department_rounded, payload: defaultCommentSortType), options: CommentSortPicker.getCommentSortTypeItems(includeVersionSpecificFeature: IncludeVersionSpecificFeature.never), icon: Icons.comment_bank_rounded, - onChanged: (_) {}, + onChanged: (_) async {}, customListPicker: CommentSortPicker( includeVersionSpecificFeature: IncludeVersionSpecificFeature.never, title: l10n.commentSortType, - onSelect: (value) { + onSelect: (value) async { setPreferences(LocalSettings.defaultCommentSortType, value.payload.name); }, previouslySelected: defaultCommentSortType, @@ -405,7 +456,7 @@ class _GeneralSettingsPageState extends State with SingleTi value: ListPickerItem(label: currentLocale.languageCode, icon: Icons.language_rounded, payload: currentLocale), options: supportedLocales.map((e) => ListPickerItem(label: LanguageLocal.getDisplayLanguage(e.languageCode, e.toLanguageTag()), icon: Icons.language_rounded, payload: e)).toList(), icon: Icons.language_rounded, - onChanged: (ListPickerItem value) { + onChanged: (ListPickerItem value) async { setPreferences(LocalSettings.appLanguageCode, value.payload); }, valueDisplay: Row( @@ -603,7 +654,6 @@ class _GeneralSettingsPageState extends State with SingleTi highlightKey: settingToHighlight == LocalSettings.scrapeMissingPreviews ? settingToHighlightKey : null, ), ), - const SliverToBoxAdapter(child: SizedBox(height: 16.0)), SliverToBoxAdapter( child: Padding( @@ -615,7 +665,16 @@ class _GeneralSettingsPageState extends State with SingleTi child: ListOption( description: l10n.userFormat, value: ListPickerItem( - label: generateUserFullName(null, 'name', 'instance.tld', userSeparator: userSeparator), + label: generateSampleUserFullName(userSeparator), + labelWidget: generateSampleUserFullNameWidget( + userSeparator, + weightUserName: userFullNameWeightUserName, + weightInstanceName: userFullNameWeightInstanceName, + colorizeUserName: userFullNameColorizeUserName, + colorizeInstanceName: userFullNameColorizeInstanceName, + textStyle: theme.textTheme.bodyMedium, + colorScheme: theme.colorScheme, + ), icon: Icons.person_rounded, payload: userSeparator, capitalizeLabel: false, @@ -623,19 +682,46 @@ class _GeneralSettingsPageState extends State with SingleTi options: [ ListPickerItem( icon: const IconData(0x2022), - label: generateUserFullName(null, 'name', 'instance.tld', userSeparator: FullNameSeparator.dot), + label: generateSampleUserFullName(FullNameSeparator.dot), + labelWidget: generateSampleUserFullNameWidget( + FullNameSeparator.dot, + weightUserName: userFullNameWeightUserName, + weightInstanceName: userFullNameWeightInstanceName, + colorizeUserName: userFullNameColorizeUserName, + colorizeInstanceName: userFullNameColorizeInstanceName, + textStyle: theme.textTheme.bodyMedium, + colorScheme: theme.colorScheme, + ), payload: FullNameSeparator.dot, capitalizeLabel: false, ), ListPickerItem( icon: Icons.alternate_email_rounded, - label: generateUserFullName(null, 'name', 'instance.tld', userSeparator: FullNameSeparator.at), + label: generateSampleUserFullName(FullNameSeparator.at), + labelWidget: generateSampleUserFullNameWidget( + FullNameSeparator.at, + weightUserName: userFullNameWeightUserName, + weightInstanceName: userFullNameWeightInstanceName, + colorizeUserName: userFullNameColorizeUserName, + colorizeInstanceName: userFullNameColorizeInstanceName, + textStyle: theme.textTheme.bodyMedium, + colorScheme: theme.colorScheme, + ), payload: FullNameSeparator.at, capitalizeLabel: false, ), ListPickerItem( icon: Icons.alternate_email_rounded, - label: generateUserFullName(null, 'name', 'instance.tld', userSeparator: FullNameSeparator.lemmy), + label: generateSampleUserFullName(FullNameSeparator.lemmy), + labelWidget: generateSampleUserFullNameWidget( + FullNameSeparator.lemmy, + weightUserName: userFullNameWeightUserName, + weightInstanceName: userFullNameWeightInstanceName, + colorizeUserName: userFullNameColorizeUserName, + colorizeInstanceName: userFullNameColorizeInstanceName, + textStyle: theme.textTheme.bodyMedium, + colorScheme: theme.colorScheme, + ), payload: FullNameSeparator.lemmy, capitalizeLabel: false, ), @@ -645,31 +731,133 @@ class _GeneralSettingsPageState extends State with SingleTi highlightKey: settingToHighlight == LocalSettings.userFormat ? settingToHighlightKey : null, ), ), + SliverToBoxAdapter( + child: ListOption( + closeOnSelect: false, + description: l10n.userStyle, + value: const ListPickerItem(label: '', payload: null), + bottomSheetHeading: generateSampleUserFullNameWidget( + userSeparator, + weightUserName: userFullNameWeightUserName, + weightInstanceName: userFullNameWeightInstanceName, + colorizeUserName: userFullNameColorizeUserName, + colorizeInstanceName: userFullNameColorizeInstanceName, + textStyle: theme.textTheme.bodyMedium, + colorScheme: theme.colorScheme, + ), + onUpdateHeading: () => generateSampleUserFullNameWidget( + userSeparator, + weightUserName: userFullNameWeightUserName, + weightInstanceName: userFullNameWeightInstanceName, + colorizeUserName: userFullNameColorizeUserName, + colorizeInstanceName: userFullNameColorizeInstanceName, + textStyle: theme.textTheme.bodyMedium, + colorScheme: theme.colorScheme, + ), + options: [ + ListPickerItem( + icon: Icons.format_bold_rounded, + label: l10n.boldUserName, + payload: LocalSettings.userFullNameWeightUserName, + isChecked: userFullNameWeightUserName, + ), + ListPickerItem( + icon: Icons.format_bold_rounded, + label: l10n.boldInstanceName, + payload: LocalSettings.userFullNameWeightInstanceName, + isChecked: userFullNameWeightInstanceName, + ), + ListPickerItem( + icon: Icons.color_lens_rounded, + label: l10n.colorizeUserName, + payload: LocalSettings.userFullNameColorizeUserName, + isChecked: userFullNameColorizeUserName, + ), + ListPickerItem( + icon: Icons.color_lens_rounded, + label: l10n.colorizeInstanceName, + payload: LocalSettings.userFullNameColorizeInstanceName, + isChecked: userFullNameColorizeInstanceName, + ), + ], + icon: Icons.person_rounded, + onChanged: (value) async { + bool? newValue = switch (value.payload) { + LocalSettings.userFullNameWeightUserName => !userFullNameWeightUserName, + LocalSettings.userFullNameWeightInstanceName => !userFullNameWeightInstanceName, + LocalSettings.userFullNameColorizeUserName => !userFullNameColorizeUserName, + LocalSettings.userFullNameColorizeInstanceName => !userFullNameColorizeInstanceName, + _ => null, + }; + + if (newValue != null) { + await setPreferences(value.payload, newValue); + } + }, + highlightKey: settingToHighlight == LocalSettings.userStyle ? settingToHighlightKey : null, + ), + ), SliverToBoxAdapter( child: ListOption( description: l10n.communityFormat, value: ListPickerItem( - label: generateCommunityFullName(null, 'name', 'instance.tld', communitySeparator: communitySeparator), - icon: Icons.person_rounded, + label: generateSampleCommunityFullName(communitySeparator), + labelWidget: generateSampleCommunityFullNameWidget( + communitySeparator, + weightCommunityName: communityFullNameWeightCommunityName, + weightInstanceName: communityFullNameWeightInstanceName, + colorizeCommunityName: communityFullNameColorizeCommunityName, + colorizeInstanceName: communityFullNameColorizeInstanceName, + textStyle: theme.textTheme.bodyMedium, + colorScheme: theme.colorScheme, + ), + icon: Icons.people_rounded, payload: communitySeparator, capitalizeLabel: false, ), options: [ ListPickerItem( icon: const IconData(0x2022), - label: generateCommunityFullName(null, 'name', 'instance.tld', communitySeparator: FullNameSeparator.dot), + label: generateSampleCommunityFullName(FullNameSeparator.dot), + labelWidget: generateSampleCommunityFullNameWidget( + FullNameSeparator.dot, + weightCommunityName: communityFullNameWeightCommunityName, + weightInstanceName: communityFullNameWeightInstanceName, + colorizeCommunityName: communityFullNameColorizeCommunityName, + colorizeInstanceName: communityFullNameColorizeInstanceName, + textStyle: theme.textTheme.bodyMedium, + colorScheme: theme.colorScheme, + ), payload: FullNameSeparator.dot, capitalizeLabel: false, ), ListPickerItem( icon: Icons.alternate_email_rounded, - label: generateCommunityFullName(null, 'name', 'instance.tld', communitySeparator: FullNameSeparator.at), + label: generateSampleCommunityFullName(FullNameSeparator.at), + labelWidget: generateSampleCommunityFullNameWidget( + FullNameSeparator.at, + weightCommunityName: communityFullNameWeightCommunityName, + weightInstanceName: communityFullNameWeightInstanceName, + colorizeCommunityName: communityFullNameColorizeCommunityName, + colorizeInstanceName: communityFullNameColorizeInstanceName, + textStyle: theme.textTheme.bodyMedium, + colorScheme: theme.colorScheme, + ), payload: FullNameSeparator.at, capitalizeLabel: false, ), ListPickerItem( - icon: Icons.priority_high_rounded, - label: generateCommunityFullName(null, 'name', 'instance.tld', communitySeparator: FullNameSeparator.lemmy), + icon: Icons.alternate_email_rounded, + label: generateSampleCommunityFullName(FullNameSeparator.lemmy), + labelWidget: generateSampleCommunityFullNameWidget( + FullNameSeparator.lemmy, + weightCommunityName: communityFullNameWeightCommunityName, + weightInstanceName: communityFullNameWeightInstanceName, + colorizeCommunityName: communityFullNameColorizeCommunityName, + colorizeInstanceName: communityFullNameColorizeInstanceName, + textStyle: theme.textTheme.bodyMedium, + colorScheme: theme.colorScheme, + ), payload: FullNameSeparator.lemmy, capitalizeLabel: false, ), @@ -679,6 +867,72 @@ class _GeneralSettingsPageState extends State with SingleTi highlightKey: settingToHighlight == LocalSettings.communityFormat ? settingToHighlightKey : null, ), ), + SliverToBoxAdapter( + child: ListOption( + closeOnSelect: false, + description: l10n.communityStyle, + value: const ListPickerItem(label: '', payload: null), + bottomSheetHeading: generateSampleCommunityFullNameWidget( + communitySeparator, + weightCommunityName: communityFullNameWeightCommunityName, + weightInstanceName: communityFullNameWeightInstanceName, + colorizeCommunityName: communityFullNameColorizeCommunityName, + colorizeInstanceName: communityFullNameColorizeInstanceName, + textStyle: theme.textTheme.bodyMedium, + colorScheme: theme.colorScheme, + ), + onUpdateHeading: () => generateSampleCommunityFullNameWidget( + communitySeparator, + weightCommunityName: communityFullNameWeightCommunityName, + weightInstanceName: communityFullNameWeightInstanceName, + colorizeCommunityName: communityFullNameColorizeCommunityName, + colorizeInstanceName: communityFullNameColorizeInstanceName, + textStyle: theme.textTheme.bodyMedium, + colorScheme: theme.colorScheme, + ), + options: [ + ListPickerItem( + icon: Icons.format_bold_rounded, + label: l10n.boldCommunityName, + payload: LocalSettings.communityFullNameWeightCommunityName, + isChecked: communityFullNameWeightCommunityName, + ), + ListPickerItem( + icon: Icons.format_bold_rounded, + label: l10n.boldInstanceName, + payload: LocalSettings.communityFullNameWeightInstanceName, + isChecked: communityFullNameWeightInstanceName, + ), + ListPickerItem( + icon: Icons.color_lens_rounded, + label: l10n.colorizeCommunityName, + payload: LocalSettings.communityFullNameColorizeCommunityName, + isChecked: communityFullNameColorizeCommunityName, + ), + ListPickerItem( + icon: Icons.color_lens_rounded, + label: l10n.colorizeInstanceName, + payload: LocalSettings.communityFullNameColorizeInstanceName, + isChecked: communityFullNameColorizeInstanceName, + ), + ], + icon: Icons.person_rounded, + onChanged: (value) async { + bool? newValue = switch (value.payload) { + LocalSettings.communityFullNameWeightCommunityName => !communityFullNameWeightCommunityName, + LocalSettings.communityFullNameWeightInstanceName => !communityFullNameWeightInstanceName, + LocalSettings.communityFullNameColorizeCommunityName => !communityFullNameColorizeCommunityName, + LocalSettings.communityFullNameColorizeInstanceName => !communityFullNameColorizeInstanceName, + _ => null, + }; + + if (newValue != null) { + await setPreferences(value.payload, newValue); + } + }, + highlightKey: settingToHighlight == LocalSettings.communityStyle ? settingToHighlightKey : null, + ), + ), if (!kIsWeb && Platform.isAndroid) SliverToBoxAdapter( child: ListOption( diff --git a/lib/settings/pages/post_appearance_settings_page.dart b/lib/settings/pages/post_appearance_settings_page.dart index 1e6af18b4..2a9ed80b8 100644 --- a/lib/settings/pages/post_appearance_settings_page.dart +++ b/lib/settings/pages/post_appearance_settings_page.dart @@ -505,7 +505,7 @@ class _PostAppearanceSettingsPageState extends State ListPickerItem(icon: Icons.crop_din_rounded, label: l10n.cardView, payload: false), ], icon: Icons.view_list_rounded, - onChanged: (value) => setPreferences(LocalSettings.useCompactView, value.payload), + onChanged: (value) async => setPreferences(LocalSettings.useCompactView, value.payload), highlightKey: settingToHighlight == LocalSettings.useCompactView ? settingToHighlightKey : null, ), ), @@ -582,7 +582,7 @@ class _PostAppearanceSettingsPageState extends State ) .toList(), icon: Icons.access_time_filled_rounded, - onChanged: (value) => setPreferences(LocalSettings.dateFormat, value.payload), + onChanged: (value) async => setPreferences(LocalSettings.dateFormat, value.payload), highlightKey: settingToHighlight == LocalSettings.dateFormat ? settingToHighlightKey : null, ), ), @@ -843,7 +843,7 @@ class _PostAppearanceSettingsPageState extends State ListPickerItem(icon: Icons.crop_din_rounded, label: l10n.expanded, payload: PostBodyViewType.expanded), ], icon: Icons.view_list_rounded, - onChanged: (value) => setPreferences(LocalSettings.postBodyViewType, value.payload), + onChanged: (value) async => setPreferences(LocalSettings.postBodyViewType, value.payload), highlightKey: settingToHighlight == LocalSettings.postBodyViewType ? settingToHighlightKey : null, ), ), diff --git a/lib/settings/pages/theme_settings_page.dart b/lib/settings/pages/theme_settings_page.dart index a8d277e03..da7321710 100644 --- a/lib/settings/pages/theme_settings_page.dart +++ b/lib/settings/pages/theme_settings_page.dart @@ -227,7 +227,7 @@ class _ThemeSettingsPageState extends State { value: ListPickerItem(label: themeType.name.capitalize, icon: Icons.wallpaper_rounded, payload: themeType), options: themeOptions, icon: Icons.wallpaper_rounded, - onChanged: (value) => setPreferences(LocalSettings.appTheme, value.payload.index), + onChanged: (value) async => setPreferences(LocalSettings.appTheme, value.payload.index), highlightKey: settingToHighlight == LocalSettings.appTheme ? settingToHighlightKey : null, ), ListOption( @@ -274,7 +274,7 @@ class _ThemeSettingsPageState extends State { ), options: customThemeOptions, icon: Icons.wallpaper_rounded, - onChanged: (value) => setPreferences(LocalSettings.appThemeAccentColor, value.payload), + onChanged: (value) async => setPreferences(LocalSettings.appThemeAccentColor, value.payload), closeOnSelect: false, highlightKey: settingToHighlight == LocalSettings.appThemeAccentColor ? settingToHighlightKey : null, ), @@ -307,7 +307,7 @@ class _ThemeSettingsPageState extends State { value: ListPickerItem(label: titleFontSizeScale.name.capitalize, icon: Icons.feed, payload: titleFontSizeScale), options: fontScaleOptions, icon: Icons.text_fields_rounded, - onChanged: (value) => setPreferences(LocalSettings.titleFontSizeScale, value.payload), + onChanged: (value) async => setPreferences(LocalSettings.titleFontSizeScale, value.payload), highlightKey: settingToHighlight == LocalSettings.titleFontSizeScale ? settingToHighlightKey : null, ), ListOption( @@ -315,7 +315,7 @@ class _ThemeSettingsPageState extends State { value: ListPickerItem(label: contentFontSizeScale.name.capitalize, icon: Icons.feed, payload: contentFontSizeScale), options: fontScaleOptions, icon: Icons.text_fields_rounded, - onChanged: (value) => setPreferences(LocalSettings.contentFontSizeScale, value.payload), + onChanged: (value) async => setPreferences(LocalSettings.contentFontSizeScale, value.payload), highlightKey: settingToHighlight == LocalSettings.contentFontSizeScale ? settingToHighlightKey : null, ), ListOption( @@ -323,7 +323,7 @@ class _ThemeSettingsPageState extends State { value: ListPickerItem(label: commentFontSizeScale.name.capitalize, icon: Icons.feed, payload: commentFontSizeScale), options: fontScaleOptions, icon: Icons.text_fields_rounded, - onChanged: (value) => setPreferences(LocalSettings.commentFontSizeScale, value.payload), + onChanged: (value) async => setPreferences(LocalSettings.commentFontSizeScale, value.payload), highlightKey: settingToHighlight == LocalSettings.commentFontSizeScale ? settingToHighlightKey : null, ), ListOption( @@ -331,7 +331,7 @@ class _ThemeSettingsPageState extends State { value: ListPickerItem(label: metadataFontSizeScale.name.capitalize, icon: Icons.feed, payload: metadataFontSizeScale), options: fontScaleOptions, icon: Icons.text_fields_rounded, - onChanged: (value) => setPreferences(LocalSettings.metadataFontSizeScale, value.payload), + onChanged: (value) async => setPreferences(LocalSettings.metadataFontSizeScale, value.payload), highlightKey: settingToHighlight == LocalSettings.metadataFontSizeScale ? settingToHighlightKey : null, ), ], diff --git a/lib/settings/widgets/list_option.dart b/lib/settings/widgets/list_option.dart index a4785ca9d..d26b3c1df 100644 --- a/lib/settings/widgets/list_option.dart +++ b/lib/settings/widgets/list_option.dart @@ -16,7 +16,7 @@ class ListOption extends StatelessWidget { final List> options; // Callback - final void Function(ListPickerItem) onChanged; + final Future Function(ListPickerItem) onChanged; final BottomSheetListPicker? customListPicker; final bool? isBottomModalScrollControlled; @@ -24,6 +24,7 @@ class ListOption extends StatelessWidget { final bool disabled; final Widget? valueDisplay; final bool closeOnSelect; + final Widget Function()? onUpdateHeading; /// A key to assign to this widget when it should be highlighted final GlobalKey? highlightKey; @@ -42,6 +43,7 @@ class ListOption extends StatelessWidget { this.valueDisplay, this.closeOnSelect = true, this.highlightKey, + this.onUpdateHeading, }); @override @@ -69,10 +71,9 @@ class ListOption extends StatelessWidget { BottomSheetListPicker( title: description, heading: bottomSheetHeading, + onUpdateHeading: onUpdateHeading, items: options, - onSelect: (value) { - onChanged(value); - }, + onSelect: onChanged, previouslySelected: value.payload, closeOnSelect: closeOnSelect, ), diff --git a/lib/settings/widgets/settings_list_tile.dart b/lib/settings/widgets/settings_list_tile.dart index 877de1679..d01bd066b 100644 --- a/lib/settings/widgets/settings_list_tile.dart +++ b/lib/settings/widgets/settings_list_tile.dart @@ -41,7 +41,7 @@ class SettingsListTile extends StatelessWidget { enabled: highlightKey != null, color: theme.colorScheme.primaryContainer, child: Padding( - padding: const EdgeInsets.fromLTRB(12.0, 0.0, 16.0, 0.0), + padding: const EdgeInsets.fromLTRB(16.0, 0.0, 16.0, 0.0), child: Semantics( label: semanticLabel ?? description, child: InkWell( diff --git a/lib/settings/widgets/swipe_picker.dart b/lib/settings/widgets/swipe_picker.dart index 5f48b3697..dcb25c0ed 100644 --- a/lib/settings/widgets/swipe_picker.dart +++ b/lib/settings/widgets/swipe_picker.dart @@ -60,7 +60,7 @@ class SwipePicker extends StatelessWidget { builder: (context) => BottomSheetListPicker( title: items[0].label, items: items[0].options, - onSelect: (value) { + onSelect: (value) async { items[0].onChanged(value); }, previouslySelected: items[0].value, @@ -88,7 +88,7 @@ class SwipePicker extends StatelessWidget { builder: (context) => BottomSheetListPicker( title: items[1].label, items: items[1].options, - onSelect: (value) { + onSelect: (value) async { items[1].onChanged(value); }, previouslySelected: items[1].value, @@ -123,7 +123,7 @@ class SwipePicker extends StatelessWidget { builder: (context) => BottomSheetListPicker( title: items[1].label, items: items[1].options, - onSelect: (value) { + onSelect: (value) async { items[1].onChanged(value); }, previouslySelected: items[1].value, @@ -159,7 +159,7 @@ class SwipePicker extends StatelessWidget { builder: (context) => BottomSheetListPicker( title: items[0].label, items: items[0].options, - onSelect: (value) { + onSelect: (value) async { items[0].onChanged(value); }, previouslySelected: items[0].value, diff --git a/lib/shared/comment_header.dart b/lib/shared/comment_header.dart index 9df22bfe4..eac83e82e 100644 --- a/lib/shared/comment_header.dart +++ b/lib/shared/comment_header.dart @@ -6,7 +6,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:thunder/core/auth/bloc/auth_bloc.dart'; import 'package:thunder/core/enums/font_scale.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/feed/utils/utils.dart'; import 'package:thunder/feed/view/feed_page.dart'; import 'package:thunder/shared/text/scalable_text.dart'; @@ -75,106 +75,87 @@ class CommentHeader extends StatelessWidget { navigateToFeedPage(context, feedType: FeedType.user, userId: comment.creator.id); }, child: Padding( - padding: const EdgeInsets.only(left: 5, right: 5), - child: isSpecialUser(context, isOwnComment, comment.post, comment.comment, comment.creator, moderators) - ? Row( - children: [ - ScalableText( - comment.creator.displayName != null && state.useDisplayNames ? comment.creator.displayName! : comment.creator.name, - fontScale: state.metadataFontSizeScale, - style: theme.textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w500, color: theme.colorScheme.onBackground), - ), - if (commentShowUserInstance) - ScalableText( - generateUserFullNameSuffix(context, fetchInstanceNameFromUrl(comment.creator.actorId)), - fontScale: state.metadataFontSizeScale, - style: theme.textTheme.bodyMedium?.copyWith( - fontWeight: FontWeight.w300, - ), - ), - const SizedBox(width: 2.0), - Container( - child: commentAuthorIsPostAuthor(comment.post, comment.comment) - ? Padding( - padding: const EdgeInsets.only(left: 1), - child: Icon( - Thunder.microphone_variant, - size: 15.0 * state.metadataFontSizeScale.textScaleFactor, - color: theme.colorScheme.onBackground, - ), - ) - : Container(), - ), - Container( - child: isOwnComment - ? Padding( - padding: const EdgeInsets.only(left: 1), - child: Icon( - Icons.person, - size: 15.0 * state.metadataFontSizeScale.textScaleFactor, - color: theme.colorScheme.onBackground, - )) - : Container(), - ), - Container( - child: isAdmin(comment.creator) - ? Padding( - padding: const EdgeInsets.only(left: 1), - child: Icon( - Thunder.shield_crown, - size: 14.0 * state.metadataFontSizeScale.textScaleFactor, - color: theme.colorScheme.onBackground, - ), - ) - : Container(), - ), - Container( - child: isModerator(comment.creator, moderators) - ? Padding( - padding: const EdgeInsets.only(left: 1), - child: Icon( - Thunder.shield, - size: 14.0 * state.metadataFontSizeScale.textScaleFactor, - color: theme.colorScheme.onBackground, - ), - ) - : Container(), - ), - Container( - child: isBot(comment.creator) - ? Padding( - padding: const EdgeInsets.only(left: 1, right: 2), - child: Icon( - Thunder.robot, - size: 13.0 * state.metadataFontSizeScale.textScaleFactor, - color: theme.colorScheme.onBackground, - ), - ) - : Container(), - ), - ], - ) - : Text.rich( - TextSpan( - style: theme.textTheme.bodyMedium?.copyWith( - fontWeight: FontWeight.w500, - color: state.commentUseColorizedUsername ? theme.colorScheme.secondary : theme.textTheme.bodyLarge?.color, - fontSize: MediaQuery.textScalerOf(context).scale(theme.textTheme.bodyMedium!.fontSize! * state.metadataFontSizeScale.textScaleFactor), - ), - text: comment.creator.displayName != null && state.useDisplayNames ? comment.creator.displayName! : comment.creator.name, - children: [ - if (commentShowUserInstance) - TextSpan( - text: generateUserFullNameSuffix(context, fetchInstanceNameFromUrl(comment.creator.actorId)), - style: theme.textTheme.bodyMedium?.copyWith( - fontWeight: FontWeight.w300, - color: state.commentUseColorizedUsername ? theme.colorScheme.secondary : theme.textTheme.bodyLarge?.color, - fontSize: MediaQuery.textScalerOf(context).scale(theme.textTheme.bodyMedium!.fontSize! * state.metadataFontSizeScale.textScaleFactor), + padding: const EdgeInsets.only(left: 5, right: 5), + child: isSpecialUser(context, isOwnComment, comment.post, comment.comment, comment.creator, moderators) + ? Row( + children: [ + generateUserFullNameWidget( + context, + comment.creator.displayName != null && state.useDisplayNames ? comment.creator.displayName! : comment.creator.name, + fetchInstanceNameFromUrl(comment.creator.actorId), + fontScale: state.metadataFontSizeScale, + includeInstance: commentShowUserInstance, + ), + const SizedBox(width: 2.0), + Container( + child: commentAuthorIsPostAuthor(comment.post, comment.comment) + ? Padding( + padding: const EdgeInsets.only(left: 1), + child: Icon( + Thunder.microphone_variant, + size: 15.0 * state.metadataFontSizeScale.textScaleFactor, + color: theme.colorScheme.onBackground, ), ) - ]), - textScaler: TextScaler.noScaling, - )), + : Container(), + ), + Container( + child: isOwnComment + ? Padding( + padding: const EdgeInsets.only(left: 1), + child: Icon( + Icons.person, + size: 15.0 * state.metadataFontSizeScale.textScaleFactor, + color: theme.colorScheme.onBackground, + )) + : Container(), + ), + Container( + child: isAdmin(comment.creator) + ? Padding( + padding: const EdgeInsets.only(left: 1), + child: Icon( + Thunder.shield_crown, + size: 14.0 * state.metadataFontSizeScale.textScaleFactor, + color: theme.colorScheme.onBackground, + ), + ) + : Container(), + ), + Container( + child: isModerator(comment.creator, moderators) + ? Padding( + padding: const EdgeInsets.only(left: 1), + child: Icon( + Thunder.shield, + size: 14.0 * state.metadataFontSizeScale.textScaleFactor, + color: theme.colorScheme.onBackground, + ), + ) + : Container(), + ), + Container( + child: isBot(comment.creator) + ? Padding( + padding: const EdgeInsets.only(left: 1, right: 2), + child: Icon( + Thunder.robot, + size: 13.0 * state.metadataFontSizeScale.textScaleFactor, + color: theme.colorScheme.onBackground, + ), + ) + : Container(), + ), + ], + ) + : generateUserFullNameWidget( + context, + comment.creator.displayName != null && state.useDisplayNames ? comment.creator.displayName! : comment.creator.name, + fetchInstanceNameFromUrl(comment.creator.actorId), + fontScale: state.metadataFontSizeScale, + includeInstance: commentShowUserInstance, + ), + ), ), ), const SizedBox(width: 8.0), diff --git a/lib/shared/comment_reference.dart b/lib/shared/comment_reference.dart index 5f1625fb2..20e093e93 100644 --- a/lib/shared/comment_reference.dart +++ b/lib/shared/comment_reference.dart @@ -6,7 +6,7 @@ import 'package:lemmy_api_client/v3.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:thunder/core/auth/bloc/auth_bloc.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/core/enums/swipe_action.dart'; import 'package:thunder/post/utils/comment_actions.dart'; import 'package:thunder/shared/comment_content.dart'; diff --git a/lib/shared/cross_posts.dart b/lib/shared/cross_posts.dart index b7f3dd22c..b3a5dae08 100644 --- a/lib/shared/cross_posts.dart +++ b/lib/shared/cross_posts.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:lemmy_api_client/v3.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/core/models/post_view_media.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; diff --git a/lib/shared/input_dialogs.dart b/lib/shared/input_dialogs.dart index 8a6bea042..838d50acd 100644 --- a/lib/shared/input_dialogs.dart +++ b/lib/shared/input_dialogs.dart @@ -12,7 +12,7 @@ import 'package:thunder/account/bloc/account_bloc.dart'; import 'package:thunder/account/models/account.dart'; import 'package:thunder/core/auth/bloc/auth_bloc.dart'; import 'package:thunder/core/auth/helpers/fetch_account.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/core/singletons/lemmy_client.dart'; import 'package:thunder/feed/utils/community.dart'; import 'package:thunder/shared/avatars/community_avatar.dart'; diff --git a/lib/shared/picker_item.dart b/lib/shared/picker_item.dart index f0dbc2bfc..4c3fb9ab1 100644 --- a/lib/shared/picker_item.dart +++ b/lib/shared/picker_item.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; class PickerItem extends StatelessWidget { final String label; final String? subtitle; + final Widget? labelWidget; final IconData? icon; final Widget? leading; final IconData? trailingIcon; @@ -14,6 +15,7 @@ class PickerItem extends StatelessWidget { super.key, required this.label, this.subtitle, + this.labelWidget, required this.icon, required this.onSelected, this.isSelected, @@ -34,15 +36,16 @@ class PickerItem extends StatelessWidget { borderRadius: BorderRadius.circular(50), onTap: onSelected, child: ListTile( - title: Text( - label, - softWrap: false, - overflow: TextOverflow.fade, - style: (textTheme?.bodyMedium ?? theme.textTheme.bodyMedium)?.copyWith( - color: (textTheme?.bodyMedium ?? theme.textTheme.bodyMedium)?.color?.withOpacity(onSelected == null ? 0.5 : 1), - ), - textScaler: TextScaler.noScaling, - ), + title: labelWidget ?? + Text( + label, + softWrap: false, + overflow: TextOverflow.fade, + style: (textTheme?.bodyMedium ?? theme.textTheme.bodyMedium)?.copyWith( + color: (textTheme?.bodyMedium ?? theme.textTheme.bodyMedium)?.color?.withOpacity(onSelected == null ? 0.5 : 1), + ), + textScaler: TextScaler.noScaling, + ), subtitle: subtitle != null ? Text( subtitle!, diff --git a/lib/thunder/bloc/thunder_bloc.dart b/lib/thunder/bloc/thunder_bloc.dart index dc0769ca9..81673b459 100644 --- a/lib/thunder/bloc/thunder_bloc.dart +++ b/lib/thunder/bloc/thunder_bloc.dart @@ -12,7 +12,7 @@ import 'package:thunder/core/enums/browser_mode.dart'; import 'package:thunder/core/enums/custom_theme_type.dart'; import 'package:thunder/core/enums/fab_action.dart'; import 'package:thunder/core/enums/font_scale.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/core/enums/image_caching_mode.dart'; import 'package:thunder/core/enums/local_settings.dart'; import 'package:thunder/core/enums/nested_comment_indicator.dart'; @@ -119,7 +119,15 @@ class ThunderBloc extends Bloc { bool enableInboxNotifications = prefs.getBool(LocalSettings.enableInboxNotifications.name) ?? false; String? appLanguageCode = prefs.getString(LocalSettings.appLanguageCode.name) ?? 'en'; FullNameSeparator userSeparator = FullNameSeparator.values.byName(prefs.getString(LocalSettings.userFormat.name) ?? FullNameSeparator.at.name); + bool userFullNameWeightUserName = prefs.getBool(LocalSettings.userFullNameWeightUserName.name) ?? true; + bool userFullNameWeightInstanceName = prefs.getBool(LocalSettings.userFullNameWeightInstanceName.name) ?? false; + bool userFullNameColorizeUserName = prefs.getBool(LocalSettings.userFullNameColorizeUserName.name) ?? false; + bool userFullNameColorizeInstanceName = prefs.getBool(LocalSettings.userFullNameColorizeInstanceName.name) ?? false; FullNameSeparator communitySeparator = FullNameSeparator.values.byName(prefs.getString(LocalSettings.communityFormat.name) ?? FullNameSeparator.dot.name); + bool communityFullNameWeightCommunityName = prefs.getBool(LocalSettings.communityFullNameWeightCommunityName.name) ?? true; + bool communityFullNameWeightInstanceName = prefs.getBool(LocalSettings.communityFullNameWeightInstanceName.name) ?? false; + bool communityFullNameColorizeCommunityName = prefs.getBool(LocalSettings.communityFullNameColorizeCommunityName.name) ?? false; + bool communityFullNameColorizeInstanceName = prefs.getBool(LocalSettings.communityFullNameColorizeInstanceName.name) ?? false; ImageCachingMode imageCachingMode = ImageCachingMode.values.byName(prefs.getString(LocalSettings.imageCachingMode.name) ?? ImageCachingMode.relaxed.name); bool hideTopBarOnScroll = prefs.getBool(LocalSettings.hideTopBarOnScroll.name) ?? false; @@ -161,7 +169,6 @@ class ThunderBloc extends Bloc { bool showCommentButtonActions = prefs.getBool(LocalSettings.showCommentActionButtons.name) ?? false; bool commentShowUserInstance = prefs.getBool(LocalSettings.commentShowUserInstance.name) ?? false; bool combineCommentScores = prefs.getBool(LocalSettings.combineCommentScores.name) ?? false; - bool commentUseColorizedUsername = prefs.getBool(LocalSettings.commentUseColorizedUsername.name) ?? false; NestedCommentIndicatorStyle nestedCommentIndicatorStyle = NestedCommentIndicatorStyle.values.byName(prefs.getString(LocalSettings.nestedCommentIndicatorStyle.name) ?? DEFAULT_NESTED_COMMENT_INDICATOR_STYLE.name); NestedCommentIndicatorColor nestedCommentIndicatorColor = @@ -260,7 +267,15 @@ class ThunderBloc extends Bloc { enableInboxNotifications: enableInboxNotifications, appLanguageCode: appLanguageCode, userSeparator: userSeparator, + userFullNameWeightUserName: userFullNameWeightUserName, + userFullNameWeightInstanceName: userFullNameWeightInstanceName, + userFullNameColorizeUserName: userFullNameColorizeUserName, + userFullNameColorizeInstanceName: userFullNameColorizeInstanceName, communitySeparator: communitySeparator, + communityFullNameWeightCommunityName: communityFullNameWeightCommunityName, + communityFullNameWeightInstanceName: communityFullNameWeightInstanceName, + communityFullNameColorizeCommunityName: communityFullNameColorizeCommunityName, + communityFullNameColorizeInstanceName: communityFullNameColorizeInstanceName, imageCachingMode: imageCachingMode, hideTopBarOnScroll: hideTopBarOnScroll, @@ -299,7 +314,6 @@ class ThunderBloc extends Bloc { combineCommentScores: combineCommentScores, nestedCommentIndicatorStyle: nestedCommentIndicatorStyle, nestedCommentIndicatorColor: nestedCommentIndicatorColor, - commentUseColorizedUsername: commentUseColorizedUsername, /// -------------------------- Theme Related Settings -------------------------- // Theme Settings diff --git a/lib/thunder/bloc/thunder_state.dart b/lib/thunder/bloc/thunder_state.dart index 569597c39..f8e18906e 100644 --- a/lib/thunder/bloc/thunder_state.dart +++ b/lib/thunder/bloc/thunder_state.dart @@ -35,7 +35,15 @@ class ThunderState extends Equatable { this.enableInboxNotifications = false, this.scoreCounters = false, this.userSeparator = FullNameSeparator.at, + this.userFullNameWeightUserName = true, + this.userFullNameWeightInstanceName = false, + this.userFullNameColorizeUserName = false, + this.userFullNameColorizeInstanceName = false, this.communitySeparator = FullNameSeparator.dot, + this.communityFullNameWeightCommunityName = false, + this.communityFullNameWeightInstanceName = false, + this.communityFullNameColorizeCommunityName = false, + this.communityFullNameColorizeInstanceName = false, this.imageCachingMode = ImageCachingMode.relaxed, this.hideTopBarOnScroll = false, @@ -74,7 +82,6 @@ class ThunderState extends Equatable { this.showCommentButtonActions = false, this.commentShowUserInstance = false, this.combineCommentScores = false, - this.commentUseColorizedUsername = false, this.nestedCommentIndicatorStyle = NestedCommentIndicatorStyle.thick, this.nestedCommentIndicatorColor = NestedCommentIndicatorColor.colorful, @@ -170,7 +177,15 @@ class ThunderState extends Equatable { final bool enableInboxNotifications; final String? appLanguageCode; final FullNameSeparator userSeparator; + final bool userFullNameWeightUserName; + final bool userFullNameWeightInstanceName; + final bool userFullNameColorizeUserName; + final bool userFullNameColorizeInstanceName; final FullNameSeparator communitySeparator; + final bool communityFullNameWeightCommunityName; + final bool communityFullNameWeightInstanceName; + final bool communityFullNameColorizeCommunityName; + final bool communityFullNameColorizeInstanceName; final ImageCachingMode imageCachingMode; final bool hideTopBarOnScroll; @@ -209,7 +224,6 @@ class ThunderState extends Equatable { final bool showCommentButtonActions; final bool commentShowUserInstance; final bool combineCommentScores; - final bool commentUseColorizedUsername; final NestedCommentIndicatorStyle nestedCommentIndicatorStyle; final NestedCommentIndicatorColor nestedCommentIndicatorColor; @@ -313,7 +327,15 @@ class ThunderState extends Equatable { bool? enableInboxNotifications, bool? scoreCounters, FullNameSeparator? userSeparator, + bool? userFullNameWeightUserName, + bool? userFullNameWeightInstanceName, + bool? userFullNameColorizeUserName, + bool? userFullNameColorizeInstanceName, FullNameSeparator? communitySeparator, + bool? communityFullNameWeightCommunityName, + bool? communityFullNameWeightInstanceName, + bool? communityFullNameColorizeCommunityName, + bool? communityFullNameColorizeInstanceName, ImageCachingMode? imageCachingMode, bool? hideTopBarOnScroll, @@ -350,7 +372,6 @@ class ThunderState extends Equatable { bool? showCommentButtonActions, bool? commentShowUserInstance, bool? combineCommentScores, - bool? commentUseColorizedUsername, NestedCommentIndicatorStyle? nestedCommentIndicatorStyle, NestedCommentIndicatorColor? nestedCommentIndicatorColor, @@ -449,7 +470,15 @@ class ThunderState extends Equatable { scoreCounters: scoreCounters ?? this.scoreCounters, appLanguageCode: appLanguageCode ?? this.appLanguageCode, userSeparator: userSeparator ?? this.userSeparator, + userFullNameWeightUserName: userFullNameWeightUserName ?? this.userFullNameWeightUserName, + userFullNameWeightInstanceName: userFullNameWeightInstanceName ?? this.userFullNameWeightInstanceName, + userFullNameColorizeUserName: userFullNameColorizeUserName ?? this.userFullNameColorizeUserName, + userFullNameColorizeInstanceName: userFullNameColorizeInstanceName ?? this.userFullNameColorizeInstanceName, communitySeparator: communitySeparator ?? this.communitySeparator, + communityFullNameWeightCommunityName: communityFullNameWeightCommunityName ?? this.communityFullNameWeightCommunityName, + communityFullNameWeightInstanceName: communityFullNameWeightInstanceName ?? this.communityFullNameWeightInstanceName, + communityFullNameColorizeCommunityName: communityFullNameColorizeCommunityName ?? this.communityFullNameColorizeCommunityName, + communityFullNameColorizeInstanceName: communityFullNameColorizeInstanceName ?? this.communityFullNameColorizeInstanceName, imageCachingMode: imageCachingMode ?? this.imageCachingMode, hideTopBarOnScroll: hideTopBarOnScroll ?? this.hideTopBarOnScroll, @@ -487,7 +516,6 @@ class ThunderState extends Equatable { showCommentButtonActions: showCommentButtonActions ?? this.showCommentButtonActions, commentShowUserInstance: commentShowUserInstance ?? this.commentShowUserInstance, combineCommentScores: combineCommentScores ?? this.combineCommentScores, - commentUseColorizedUsername: commentUseColorizedUsername ?? this.commentUseColorizedUsername, nestedCommentIndicatorStyle: nestedCommentIndicatorStyle ?? this.nestedCommentIndicatorStyle, nestedCommentIndicatorColor: nestedCommentIndicatorColor ?? this.nestedCommentIndicatorColor, @@ -590,7 +618,15 @@ class ThunderState extends Equatable { showUpdateChangelogs, enableInboxNotifications, userSeparator, + userFullNameWeightUserName, + userFullNameWeightInstanceName, + userFullNameColorizeUserName, + userFullNameColorizeInstanceName, communitySeparator, + communityFullNameWeightCommunityName, + communityFullNameWeightInstanceName, + communityFullNameColorizeCommunityName, + communityFullNameColorizeInstanceName, imageCachingMode, /// -------------------------- Feed Post Related Settings -------------------------- @@ -628,7 +664,6 @@ class ThunderState extends Equatable { showCommentButtonActions, commentShowUserInstance, combineCommentScores, - commentUseColorizedUsername, nestedCommentIndicatorStyle, nestedCommentIndicatorColor, diff --git a/lib/user/pages/user_settings_page.dart b/lib/user/pages/user_settings_page.dart index 2c5578cc4..deb501cdd 100644 --- a/lib/user/pages/user_settings_page.dart +++ b/lib/user/pages/user_settings_page.dart @@ -8,7 +8,7 @@ import 'package:thunder/account/bloc/account_bloc.dart'; import 'package:thunder/account/models/account.dart'; import 'package:thunder/account/widgets/account_placeholder.dart'; import 'package:thunder/core/auth/bloc/auth_bloc.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/core/enums/local_settings.dart'; import 'package:thunder/core/singletons/lemmy_client.dart'; import 'package:thunder/feed/feed.dart'; diff --git a/lib/user/widgets/comment_card.dart b/lib/user/widgets/comment_card.dart index ae16cfaa5..c1fa4c7c9 100644 --- a/lib/user/widgets/comment_card.dart +++ b/lib/user/widgets/comment_card.dart @@ -8,7 +8,7 @@ import 'package:swipeable_page_route/swipeable_page_route.dart'; import 'package:thunder/account/bloc/account_bloc.dart'; import 'package:thunder/core/auth/bloc/auth_bloc.dart'; import 'package:thunder/core/enums/font_scale.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/core/models/post_view_media.dart'; import 'package:thunder/feed/feed.dart'; import 'package:thunder/post/bloc/post_bloc.dart'; diff --git a/lib/user/widgets/user_header.dart b/lib/user/widgets/user_header.dart index 9ab8c45a1..e91571b00 100644 --- a/lib/user/widgets/user_header.dart +++ b/lib/user/widgets/user_header.dart @@ -4,7 +4,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:lemmy_api_client/v3.dart'; import 'package:auto_size_text/auto_size_text.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/shared/avatars/user_avatar.dart'; import 'package:thunder/shared/icon_text.dart'; import 'package:thunder/utils/instance.dart'; diff --git a/lib/user/widgets/user_indicator.dart b/lib/user/widgets/user_indicator.dart index 90b277974..ecfeb937c 100644 --- a/lib/user/widgets/user_indicator.dart +++ b/lib/user/widgets/user_indicator.dart @@ -4,7 +4,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 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/core/enums/full_name.dart'; import 'package:thunder/shared/avatars/user_avatar.dart'; import 'package:thunder/utils/instance.dart'; diff --git a/lib/user/widgets/user_list_entry.dart b/lib/user/widgets/user_list_entry.dart index 44112b719..ecab1d3a0 100644 --- a/lib/user/widgets/user_list_entry.dart +++ b/lib/user/widgets/user_list_entry.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:lemmy_api_client/v3.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/core/singletons/lemmy_client.dart'; import 'package:thunder/feed/utils/utils.dart'; import 'package:thunder/feed/view/feed_page.dart'; diff --git a/lib/user/widgets/user_sidebar.dart b/lib/user/widgets/user_sidebar.dart index 4b44d08d3..a8470205e 100644 --- a/lib/user/widgets/user_sidebar.dart +++ b/lib/user/widgets/user_sidebar.dart @@ -6,7 +6,7 @@ import 'package:lemmy_api_client/v3.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:thunder/core/auth/bloc/auth_bloc.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/core/singletons/lemmy_client.dart'; import 'package:thunder/feed/utils/utils.dart'; import 'package:thunder/feed/view/feed_page.dart'; diff --git a/lib/utils/bottom_sheet_list_picker.dart b/lib/utils/bottom_sheet_list_picker.dart index 2cbd31681..d3ddb2c8b 100644 --- a/lib/utils/bottom_sheet_list_picker.dart +++ b/lib/utils/bottom_sheet_list_picker.dart @@ -6,10 +6,11 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class BottomSheetListPicker extends StatefulWidget { final String title; final List> items; - final void Function(ListPickerItem) onSelect; + final Future Function(ListPickerItem) onSelect; final T? previouslySelected; final bool closeOnSelect; final Widget? heading; + final Widget Function()? onUpdateHeading; const BottomSheetListPicker({ super.key, @@ -19,6 +20,7 @@ class BottomSheetListPicker extends StatefulWidget { this.previouslySelected, this.closeOnSelect = true, this.heading, + this.onUpdateHeading, }); @override @@ -27,6 +29,15 @@ class BottomSheetListPicker extends StatefulWidget { class _BottomSheetListPickerState extends State> { T? currentlySelected; + late final Map, bool?> checkedItems; + Widget? heading; + + @override + void initState() { + super.initState(); + + checkedItems = Map.fromEntries(widget.items.map((item) => MapEntry(item, item.isChecked))); + } @override Widget build(BuildContext context) { @@ -41,84 +52,98 @@ class _BottomSheetListPickerState extends State> { mainAxisAlignment: MainAxisAlignment.start, mainAxisSize: MainAxisSize.max, children: [ - Padding( - padding: const EdgeInsets.only(bottom: 16.0, left: 26.0, right: 16.0), - child: Align( - alignment: Alignment.centerLeft, - child: Text( - widget.title, - style: theme.textTheme.titleLarge!.copyWith(), + if (widget.title.isNotEmpty) + Padding( + padding: const EdgeInsets.only(bottom: 16.0, left: 26.0, right: 16.0), + child: Align( + alignment: Alignment.centerLeft, + child: Text( + widget.title, + style: theme.textTheme.titleLarge!.copyWith(), + ), ), ), - ), - if (widget.heading != null) + if ((heading ?? widget.heading) != null) Padding( padding: const EdgeInsets.only(left: 24, right: 24, bottom: 10), - child: widget.heading!, + child: (heading ?? widget.heading)!, ), ListView( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - children: widget.items - .map( - (item) => PickerItem( - label: item.capitalizeLabel ? item.label.capitalize : item.label, - subtitle: item.subtitle, - icon: item.icon, - textTheme: item.textTheme, - onSelected: () { - if (widget.closeOnSelect) { - Navigator.of(context).pop(); - } else { - setState(() { + children: widget.items.map( + (item) { + return PickerItem( + label: item.capitalizeLabel ? item.label.capitalize : item.label, + labelWidget: item.labelWidget, + subtitle: item.subtitle, + icon: item.icon, + textTheme: item.textTheme, + onSelected: () async { + if (widget.closeOnSelect) { + Navigator.of(context).pop(); + } else { + setState(() { + if (checkedItems[item] == null) { currentlySelected = item.payload; - }); - } - widget.onSelect(item); - }, - isSelected: currentlySelected != null ? currentlySelected == item.payload : widget.previouslySelected == item.payload, - leading: Stack( - children: [ - Container( - height: 32, - width: 32, - decoration: BoxDecoration( - color: item.colors?[0], - borderRadius: BorderRadius.circular(100), - ), + } else { + setState(() { + checkedItems[item] = !checkedItems[item]!; + }); + } + }); + } + await widget.onSelect(item); + setState(() => heading = widget.onUpdateHeading?.call()); + }, + isSelected: currentlySelected != null ? currentlySelected == item.payload : widget.previouslySelected == item.payload, + leading: Stack( + children: [ + Container( + height: 32, + width: 32, + decoration: BoxDecoration( + color: item.colors?[0], + borderRadius: BorderRadius.circular(100), ), - Positioned( - bottom: 0, - child: Container( - height: 16, - width: 16, - decoration: BoxDecoration( - color: item.colors?[1], - borderRadius: const BorderRadius.only( - bottomLeft: Radius.circular(100), - ), + ), + Positioned( + bottom: 0, + child: Container( + height: 16, + width: 16, + decoration: BoxDecoration( + color: item.colors?[1], + borderRadius: const BorderRadius.only( + bottomLeft: Radius.circular(100), ), ), ), - Positioned( - bottom: 0, - right: 0, - child: Container( - height: 16, - width: 16, - decoration: BoxDecoration( - color: item.colors?[2], - borderRadius: const BorderRadius.only( - bottomRight: Radius.circular(100), - ), + ), + Positioned( + bottom: 0, + right: 0, + child: Container( + height: 16, + width: 16, + decoration: BoxDecoration( + color: item.colors?[2], + borderRadius: const BorderRadius.only( + bottomRight: Radius.circular(100), ), ), ), - ], - ), + ), + ], ), - ) - .toList(), + trailingIcon: switch (checkedItems[item]) { + true => Icons.check_box_rounded, + false => Icons.check_box_outline_blank_rounded, + null => null, + }, + ); + }, + ).toList(), ), const SizedBox(height: 16.0), ], @@ -155,17 +180,21 @@ class ListPickerItem { final List? colors; final String label; final String? subtitle; + final Widget? labelWidget; final T payload; final bool capitalizeLabel; final TextTheme? textTheme; + final bool? isChecked; const ListPickerItem({ this.icon, this.colors, required this.label, this.subtitle, + this.labelWidget, required this.payload, this.capitalizeLabel = true, this.textTheme, + this.isChecked, }); } diff --git a/lib/utils/links.dart b/lib/utils/links.dart index d2d8dcfee..cc3d99555 100644 --- a/lib/utils/links.dart +++ b/lib/utils/links.dart @@ -328,7 +328,7 @@ void handleLinkLongPress(BuildContext context, ThunderState state, String text, ListPickerItem(label: l10n.copy, payload: 'copy', icon: Icons.copy_rounded), ListPickerItem(label: l10n.share, payload: 'share', icon: Icons.share_rounded), ], - onSelect: (value) { + onSelect: (value) async { switch (value.payload) { case 'open': handleLinkTap(context, state, text, url); diff --git a/lib/utils/notifications.dart b/lib/utils/notifications.dart index 63c3c7826..a712b94ae 100644 --- a/lib/utils/notifications.dart +++ b/lib/utils/notifications.dart @@ -7,7 +7,7 @@ import 'package:markdown/markdown.dart'; import 'package:thunder/account/models/account.dart'; import 'package:thunder/core/auth/helpers/fetch_account.dart'; -import 'package:thunder/core/enums/full_name_separator.dart'; +import 'package:thunder/core/enums/full_name.dart'; import 'package:thunder/core/enums/local_settings.dart'; import 'package:thunder/core/singletons/lemmy_client.dart'; import 'package:thunder/core/singletons/preferences.dart'; diff --git a/lib/utils/preferences.dart b/lib/utils/preferences.dart index 1beef92ad..2082e7e2a 100644 --- a/lib/utils/preferences.dart +++ b/lib/utils/preferences.dart @@ -19,4 +19,11 @@ Future performSharedPreferencesMigration() async { if (browserMode != null && browserMode.contains("BrowserMode")) { await prefs.setString(LocalSettings.browserMode.name, browserMode.replaceAll('BrowserMode.', '')); } + + // Migrate the commentUseColorizedUsername setting, if found. + bool? legacyCommentUseColorizedUsername = prefs.getBool(LocalSettings.commentUseColorizedUsername.name); + if (legacyCommentUseColorizedUsername != null) { + await prefs.remove(LocalSettings.commentUseColorizedUsername.name); + await prefs.setBool(LocalSettings.userFullNameColorizeUserName.name, legacyCommentUseColorizedUsername); + } }