💄 Optimized featured post

This commit is contained in:
2025-12-21 13:07:44 +08:00
parent 7a56e7882e
commit cb7eef943c
6 changed files with 102 additions and 171 deletions

View File

@@ -1508,7 +1508,7 @@
"createAccountAgreeTerms": "I've read these terms and agree to the terms of service.", "createAccountAgreeTerms": "I've read these terms and agree to the terms of service.",
"createAccountProfile": "Create your profile", "createAccountProfile": "Create your profile",
"createAccountToS": "Review Terms & Conditions", "createAccountToS": "Review Terms & Conditions",
"accountActivationAlert": "Remember to activate your account", "accountActivationAlert": "Activate your account",
"accountActivationAlertHint": "Unactivated account may leads to various of permission issues, activate your account by clicking the link we sent to your email inbox.", "accountActivationAlertHint": "Unactivated account may leads to various of permission issues, activate your account by clicking the link we sent to your email inbox.",
"accountActivationResendHint": "Didn't see it? Try click the button below to resend one. If you need to update your email while your account was unactivated, feel free to contact our customer service.", "accountActivationResendHint": "Didn't see it? Try click the button below to resend one. If you need to update your email while your account was unactivated, feel free to contact our customer service.",
"accountActivationResend": "Resend", "accountActivationResend": "Resend",

View File

@@ -1486,7 +1486,7 @@
"createAccountAgreeTerms": "我已阅读并同意服务条款。", "createAccountAgreeTerms": "我已阅读并同意服务条款。",
"createAccountProfile": "创建您的个人资料", "createAccountProfile": "创建您的个人资料",
"createAccountToS": "查看条款与条件", "createAccountToS": "查看条款与条件",
"accountActivationAlert": "请记住激活您的账户", "accountActivationAlert": "激活您的账户",
"accountActivationAlertHint": "未激活的账户可能会导致各种权限问题,请点击我们发送到您邮箱收件箱的链接来激活您的账户。", "accountActivationAlertHint": "未激活的账户可能会导致各种权限问题,请点击我们发送到您邮箱收件箱的链接来激活您的账户。",
"accountActivationResendHint": "没收到?请尝试点击下方按钮重新发送。如果您在账户未激活期间需要更新邮箱,请随时联系我们的客服。", "accountActivationResendHint": "没收到?请尝试点击下方按钮重新发送。如果您在账户未激活期间需要更新邮箱,请随时联系我们的客服。",
"accountActivationResend": "重新发送", "accountActivationResend": "重新发送",

View File

@@ -13,12 +13,12 @@ import 'package:island/pods/userinfo.dart';
import 'package:island/screens/chat/chat.dart'; import 'package:island/screens/chat/chat.dart';
import 'package:island/services/event_bus.dart'; import 'package:island/services/event_bus.dart';
import 'package:island/services/responsive.dart'; import 'package:island/services/responsive.dart';
import 'package:island/widgets/account/account_name.dart';
import 'package:island/widgets/account/fortune_graph.dart'; import 'package:island/widgets/account/fortune_graph.dart';
import 'package:island/widgets/account/friends_overview.dart'; import 'package:island/widgets/account/friends_overview.dart';
import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/app_scaffold.dart';
import 'package:island/widgets/notification_tile.dart'; import 'package:island/widgets/notification_tile.dart';
import 'package:island/widgets/post/post_featured.dart'; import 'package:island/widgets/post/post_featured.dart';
import 'package:island/widgets/post/post_item.dart';
import 'package:island/widgets/check_in.dart'; import 'package:island/widgets/check_in.dart';
import 'package:island/screens/notification.dart'; import 'package:island/screens/notification.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart'; import 'package:material_symbols_icons/material_symbols_icons.dart';
@@ -124,9 +124,13 @@ class _DashboardGridWide extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final userInfo = ref.watch(userInfoProvider);
return Row( return Row(
spacing: 16, spacing: 16,
children: [ children: [
if (userInfo.value != null && userInfo.value?.activatedAt == null)
SizedBox(width: 400, child: AccountUnactivatedCard()),
SizedBox( SizedBox(
width: 400, width: 400,
child: Column( child: Column(
@@ -151,7 +155,7 @@ class _DashboardGridWide extends HookConsumerWidget {
], ],
), ),
), ),
SizedBox(width: 400, child: FeaturedPostCard()), SizedBox(width: 400, child: PostFeaturedList(collapsable: false)),
SizedBox( SizedBox(
width: 400, width: 400,
child: Column( child: Column(
@@ -179,12 +183,19 @@ class _DashboardGridNarrow extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final userInfo = ref.watch(userInfoProvider);
return Column( return Column(
spacing: 16, spacing: 16,
children: [ children: [
if (userInfo.value != null && userInfo.value?.activatedAt == null)
AccountUnactivatedCard(),
CheckInWidget(margin: EdgeInsets.zero, checkInOnly: true), CheckInWidget(margin: EdgeInsets.zero, checkInOnly: true),
FortuneCard(), FortuneCard(),
SizedBox(height: 400, child: FeaturedPostCard()), ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 400),
child: PostFeaturedList(),
),
FriendsOverviewWidget(), FriendsOverviewWidget(),
NotificationsCard(), NotificationsCard(),
ChatListCard(), ChatListCard(),
@@ -318,65 +329,6 @@ class ClockCard extends HookConsumerWidget {
} }
} }
class FeaturedPostCard extends HookConsumerWidget {
const FeaturedPostCard({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final featuredPostsAsync = ref.watch(featuredPostsProvider);
return ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(8)),
child: Card(
color: Theme.of(context).colorScheme.surfaceContainerHigh,
margin: EdgeInsets.zero,
child: Column(
children: [
SizedBox(
height: 48,
child: Row(
spacing: 8,
children: [
const Icon(Symbols.highlight),
Text('highlightPost').tr(),
],
).padding(horizontal: 16, vertical: 8),
),
Expanded(
child: featuredPostsAsync.when(
loading: () => const Center(child: CircularProgressIndicator()),
error: (error, stack) => Center(child: Text('Error: $error')),
data: (posts) {
if (posts.isEmpty) {
return Padding(
padding: EdgeInsets.all(16),
child: Center(
child: Text('noFeaturedPostsAvailable').tr(),
),
);
}
return PageView.builder(
scrollDirection: Axis.horizontal,
itemCount: posts.length,
itemBuilder: (context, index) {
return SingleChildScrollView(
child: PostActionableItem(
item: posts[index],
borderRadius: 8,
),
);
},
);
},
),
),
],
),
),
);
}
}
class NotificationsCard extends HookConsumerWidget { class NotificationsCard extends HookConsumerWidget {
const NotificationsCard({super.key}); const NotificationsCard({super.key});

View File

@@ -346,29 +346,7 @@ class ExploreScreen extends HookConsumerWidget {
child: Align( child: Align(
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(spacing: 8, children: [const Gap(4)]),
spacing: 8,
children: [
const Gap(4),
if (user.value?.activatedAt == null)
AccountUnactivatedCard(),
CheckInWidget(
margin: EdgeInsets.zero,
onChecked: () {
ref.invalidate(eventCalendarProvider(query.value));
},
),
if (notificationCount.value != null &&
notificationCount.value! > 0)
notificationIndicatorWidget(
context,
count: notificationCount.value ?? 0,
margin: EdgeInsets.zero,
),
PostFeaturedList(),
FriendsOverviewWidget(),
],
),
), ),
), ),
) )

View File

@@ -219,20 +219,20 @@ class AccountName extends StatelessWidget {
if (account.automatedId != null) if (account.automatedId != null)
hideOverlay hideOverlay
? Icon( ? Icon(
Symbols.smart_toy,
size: 16,
color: nameStyle.color,
fill: 1,
)
: Tooltip(
message: 'accountAutomated'.tr(),
child: Icon(
Symbols.smart_toy, Symbols.smart_toy,
size: 16, size: 16,
color: nameStyle.color, color: nameStyle.color,
fill: 1, fill: 1,
)
: Tooltip(
message: 'accountAutomated'.tr(),
child: Icon(
Symbols.smart_toy,
size: 16,
color: nameStyle.color,
fill: 1,
),
), ),
),
], ],
); );
} }
@@ -275,20 +275,20 @@ class AccountName extends StatelessWidget {
if (account.automatedId != null) if (account.automatedId != null)
hideOverlay hideOverlay
? Icon( ? Icon(
Symbols.smart_toy,
size: 16,
color: nameStyle.color,
fill: 1,
)
: Tooltip(
message: 'accountAutomated'.tr(),
child: Icon(
Symbols.smart_toy, Symbols.smart_toy,
size: 16, size: 16,
color: nameStyle.color, color: nameStyle.color,
fill: 1, fill: 1,
)
: Tooltip(
message: 'accountAutomated'.tr(),
child: Icon(
Symbols.smart_toy,
size: 16,
color: nameStyle.color,
fill: 1,
),
), ),
),
], ],
); );
} }
@@ -310,29 +310,28 @@ class VerificationMark extends StatelessWidget {
? kVerificationMarkIcons[mark.type] ? kVerificationMarkIcons[mark.type]
: Symbols.verified, : Symbols.verified,
size: 16, size: 16,
color: color: (kVerificationMarkColors.length > mark.type && mark.type >= 0)
(kVerificationMarkColors.length > mark.type && mark.type >= 0) ? kVerificationMarkColors[mark.type]
? kVerificationMarkColors[mark.type] : Colors.blue,
: Colors.blue,
fill: 1, fill: 1,
); );
return hideOverlay return hideOverlay
? icon ? icon
: Tooltip( : Tooltip(
richMessage: TextSpan( richMessage: TextSpan(
text: mark.title ?? 'No title', text: mark.title ?? 'No title',
children: [ children: [
TextSpan(text: '\n'), TextSpan(text: '\n'),
TextSpan( TextSpan(
text: mark.description ?? 'descriptionNone'.tr(), text: mark.description ?? 'descriptionNone'.tr(),
style: TextStyle(fontWeight: FontWeight.normal), style: TextStyle(fontWeight: FontWeight.normal),
), ),
], ],
style: TextStyle(fontWeight: FontWeight.bold), style: TextStyle(fontWeight: FontWeight.bold),
), ),
child: icon, child: icon,
); );
} }
} }
@@ -384,19 +383,19 @@ class StellarMembershipMark extends StatelessWidget {
return hideOverlay return hideOverlay
? icon ? icon
: Tooltip( : Tooltip(
richMessage: TextSpan( richMessage: TextSpan(
text: 'stellarMembership'.tr(), text: 'stellarMembership'.tr(),
children: [ children: [
TextSpan(text: '\n'), TextSpan(text: '\n'),
TextSpan( TextSpan(
text: 'currentMembershipMember'.tr(args: [tierName]), text: 'currentMembershipMember'.tr(args: [tierName]),
style: TextStyle(fontWeight: FontWeight.normal), style: TextStyle(fontWeight: FontWeight.normal),
), ),
], ],
style: TextStyle(fontWeight: FontWeight.bold), style: TextStyle(fontWeight: FontWeight.bold),
), ),
child: icon, child: icon,
); );
} }
} }
@@ -414,10 +413,9 @@ class VerificationStatusCard extends StatelessWidget {
? kVerificationMarkIcons[mark.type] ? kVerificationMarkIcons[mark.type]
: Symbols.verified, : Symbols.verified,
size: 32, size: 32,
color: color: (kVerificationMarkColors.length > mark.type && mark.type >= 0)
(kVerificationMarkColors.length > mark.type && mark.type >= 0) ? kVerificationMarkColors[mark.type]
? kVerificationMarkColors[mark.type] : Colors.blue,
: Colors.blue,
fill: 1, fill: 1,
).alignment(Alignment.centerLeft), ).alignment(Alignment.centerLeft),
const Gap(8), const Gap(8),

View File

@@ -21,7 +21,8 @@ Future<List<SnPost>> featuredPosts(Ref ref) async {
} }
class PostFeaturedList extends HookConsumerWidget { class PostFeaturedList extends HookConsumerWidget {
const PostFeaturedList({super.key}); final bool collapsable;
const PostFeaturedList({super.key, this.collapsable = true});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -86,6 +87,7 @@ class PostFeaturedList extends HookConsumerWidget {
color: Theme.of(context).colorScheme.surfaceContainerHigh, color: Theme.of(context).colorScheme.surfaceContainerHigh,
margin: EdgeInsets.zero, margin: EdgeInsets.zero,
child: Column( child: Column(
mainAxisSize: MainAxisSize.min,
children: [ children: [
SizedBox( SizedBox(
height: 48, height: 48,
@@ -121,36 +123,37 @@ class PostFeaturedList extends HookConsumerWidget {
}, },
icon: const Icon(Symbols.arrow_right), icon: const Icon(Symbols.arrow_right),
), ),
IconButton( if (collapsable)
padding: EdgeInsets.zero, IconButton(
visualDensity: VisualDensity.compact, padding: EdgeInsets.zero,
constraints: const BoxConstraints(), visualDensity: VisualDensity.compact,
onPressed: () { constraints: const BoxConstraints(),
isCollapsed.value = !isCollapsed.value; onPressed: () {
talker.info( isCollapsed.value = !isCollapsed.value;
'Manual toggle. isCollapsed set to ${isCollapsed.value}',
);
if (isCollapsed.value &&
featuredPostsAsync.hasValue &&
featuredPostsAsync.value!.isNotEmpty) {
prefs.setString(
kFeaturedPostsCollapsedId,
featuredPostsAsync.value!.first.id,
);
talker.info( talker.info(
'Stored collapsed ID: ${featuredPostsAsync.value!.first.id}', 'Manual toggle. isCollapsed set to ${isCollapsed.value}',
); );
} else { if (isCollapsed.value &&
prefs.remove(kFeaturedPostsCollapsedId); featuredPostsAsync.hasValue &&
talker.info('Removed stored collapsed ID.'); featuredPostsAsync.value!.isNotEmpty) {
} prefs.setString(
}, kFeaturedPostsCollapsedId,
icon: Icon( featuredPostsAsync.value!.first.id,
isCollapsed.value );
? Symbols.expand_more talker.info(
: Symbols.expand_less, 'Stored collapsed ID: ${featuredPostsAsync.value!.first.id}',
);
} else {
prefs.remove(kFeaturedPostsCollapsedId);
talker.info('Removed stored collapsed ID.');
}
},
icon: Icon(
isCollapsed.value
? Symbols.expand_more
: Symbols.expand_less,
),
), ),
),
], ],
).padding(horizontal: 16, vertical: 8), ).padding(horizontal: 16, vertical: 8),
), ),
@@ -158,14 +161,14 @@ class PostFeaturedList extends HookConsumerWidget {
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut, curve: Curves.easeInOut,
child: Visibility( child: Visibility(
visible: !isCollapsed.value, visible: collapsable ? !isCollapsed.value : true,
child: featuredPostsAsync.when( child: featuredPostsAsync.when(
loading: loading: () =>
() => const Center(child: CircularProgressIndicator()), const Center(child: CircularProgressIndicator()),
error: (error, stack) => Center(child: Text('Error: $error')), error: (error, stack) => Center(child: Text('Error: $error')),
data: (posts) { data: (posts) {
return SizedBox( return SizedBox(
height: 320, height: 344,
child: PageView.builder( child: PageView.builder(
controller: pageViewController, controller: pageViewController,
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,