Compare commits
3 Commits
9e9fbc5d6a
...
fec28f6223
| Author | SHA1 | Date | |
|---|---|---|---|
| fec28f6223 | |||
| 85005ff9c3 | |||
| e3c92a3c55 |
@@ -344,7 +344,7 @@
|
||||
"accountSettingsHelpContent": "此页面允许您管理您的帐户安全性、隐私和其他设置。如果您需要帮助,请联系管理员。",
|
||||
"unauthorized": "未授权",
|
||||
"unauthorizedHint": "您未登录或会话已过期,请重新登录。",
|
||||
"publisherBelongsTo": "属于",
|
||||
"publisherBelongsTo": "属于 {}",
|
||||
"postContent": "内容",
|
||||
"postSettings": "设置",
|
||||
"postPublisherUnselected": "未指定发布者",
|
||||
|
||||
@@ -54,56 +54,134 @@ class _AccountBasicInfo extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 24, 24, 8),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ProfilePictureWidget(file: data.profile.picture, radius: 32),
|
||||
const Gap(20),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Row(
|
||||
return Card(
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
final hasBackground = data.profile.background?.id != null;
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (isWideScreen(context) && hasBackground)
|
||||
Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
AccountName(account: data, style: TextStyle(fontSize: 20)),
|
||||
const Gap(6),
|
||||
Flexible(
|
||||
child: Text(
|
||||
'@${data.name}',
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
).fontSize(14).opacity(0.85),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(8),
|
||||
topRight: Radius.circular(8),
|
||||
),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 16 / 7,
|
||||
child: CloudImageWidget(
|
||||
file: data.profile.background,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: -24,
|
||||
left: 16,
|
||||
child: ProfilePictureWidget(
|
||||
file: data.profile.picture,
|
||||
radius: 32,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (accountDeveloper.value != null)
|
||||
Row(
|
||||
spacing: 7,
|
||||
Builder(
|
||||
builder: (context) {
|
||||
final showBackground = isWideScreen(context) && hasBackground;
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
spacing: showBackground ? 0 : 20,
|
||||
children: [
|
||||
const Icon(Symbols.smart_toy, size: 18),
|
||||
Text(
|
||||
'botAutomatedBy'.tr(
|
||||
args: [accountDeveloper.value!.publisher!.nick],
|
||||
if (!showBackground)
|
||||
ProfilePictureWidget(
|
||||
file: data.profile.picture,
|
||||
radius: 32,
|
||||
),
|
||||
).fontSize(13),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
spacing: 4,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Flexible(
|
||||
child: AccountName(
|
||||
account: data,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (isWideScreen(context))
|
||||
Flexible(
|
||||
child: Text(
|
||||
'@${data.name}',
|
||||
).fontSize(11).padding(bottom: 2.5),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (!isWideScreen(context))
|
||||
Text(
|
||||
'@${data.name}',
|
||||
).fontSize(11).padding(bottom: 2.5),
|
||||
Text(
|
||||
(data.profile.bio.isNotEmpty)
|
||||
? data.profile.bio
|
||||
: 'descriptionNone'.tr(),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
if (accountDeveloper.value != null)
|
||||
Row(
|
||||
spacing: 7,
|
||||
children: [
|
||||
const Icon(Symbols.smart_toy, size: 18),
|
||||
Text(
|
||||
'botAutomatedBy'.tr(
|
||||
args: [
|
||||
accountDeveloper.value!.publisher!.nick,
|
||||
],
|
||||
),
|
||||
).fontSize(13),
|
||||
],
|
||||
).opacity(0.75).padding(top: 4),
|
||||
const Gap(4),
|
||||
AccountStatusWidget(
|
||||
uname: uname,
|
||||
padding: EdgeInsets.zero,
|
||||
),
|
||||
const Gap(8),
|
||||
],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
SharePlus.instance.share(
|
||||
ShareParams(
|
||||
uri: Uri.parse(
|
||||
'https://solian.app/@${data.name}',
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
icon: const Icon(Symbols.share),
|
||||
),
|
||||
],
|
||||
).opacity(0.75),
|
||||
const Gap(4),
|
||||
AccountStatusWidget(uname: uname, padding: EdgeInsets.zero),
|
||||
],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
SharePlus.instance.share(
|
||||
ShareParams(uri: Uri.parse('https://solian.app/@${data.name}')),
|
||||
);
|
||||
},
|
||||
icon: const Icon(Symbols.share),
|
||||
),
|
||||
],
|
||||
).padding(
|
||||
left: 16,
|
||||
right: 16,
|
||||
top: 16 + (showBackground ? 16 : 0),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -764,33 +842,14 @@ class AccountProfileScreen extends HookConsumerWidget {
|
||||
color: appbarColor.value,
|
||||
shadows: [appbarShadow],
|
||||
),
|
||||
flexibleSpace: Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child:
|
||||
data.profile.background?.id != null
|
||||
? CloudImageWidget(
|
||||
file: data.profile.background,
|
||||
)
|
||||
: Container(
|
||||
color:
|
||||
Theme.of(
|
||||
context,
|
||||
).appBarTheme.backgroundColor,
|
||||
),
|
||||
),
|
||||
FlexibleSpaceBar(
|
||||
title: Text(
|
||||
data.nick,
|
||||
style: TextStyle(
|
||||
color:
|
||||
appbarColor.value ??
|
||||
Theme.of(context).appBarTheme.foregroundColor,
|
||||
shadows: [appbarShadow],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
title: Text(
|
||||
data.nick,
|
||||
style: TextStyle(
|
||||
color:
|
||||
appbarColor.value ??
|
||||
Theme.of(context).appBarTheme.foregroundColor,
|
||||
shadows: [appbarShadow],
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
@@ -806,7 +865,7 @@ class AccountProfileScreen extends HookConsumerWidget {
|
||||
data: data,
|
||||
uname: name,
|
||||
accountDeveloper: accountDeveloper,
|
||||
),
|
||||
).padding(horizontal: 4, top: 20),
|
||||
),
|
||||
if (data.badges.isNotEmpty)
|
||||
SliverToBoxAdapter(
|
||||
@@ -857,7 +916,12 @@ class AccountProfileScreen extends HookConsumerWidget {
|
||||
Flexible(
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
SliverGap(24),
|
||||
SliverGap(18),
|
||||
SliverToBoxAdapter(
|
||||
child: ActivityPresenceWidget(
|
||||
uname: name,
|
||||
).padding(horizontal: 4, top: 4, bottom: 4),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountPublisherList(
|
||||
publishers: accountPublishers.value ?? [],
|
||||
@@ -883,9 +947,6 @@ class AccountProfileScreen extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: ActivityPresenceWidget(uname: name),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -937,7 +998,7 @@ class AccountProfileScreen extends HookConsumerWidget {
|
||||
data: data,
|
||||
uname: name,
|
||||
accountDeveloper: accountDeveloper,
|
||||
),
|
||||
).padding(horizontal: 4, top: 8),
|
||||
),
|
||||
if (data.badges.isNotEmpty)
|
||||
SliverToBoxAdapter(
|
||||
@@ -981,6 +1042,11 @@ class AccountProfileScreen extends HookConsumerWidget {
|
||||
data: data,
|
||||
).padding(horizontal: 4),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: ActivityPresenceWidget(
|
||||
uname: name,
|
||||
).padding(horizontal: 8, top: 4, bottom: 4),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: _AccountPublisherList(
|
||||
publishers: accountPublishers.value ?? [],
|
||||
@@ -1010,11 +1076,6 @@ class AccountProfileScreen extends HookConsumerWidget {
|
||||
),
|
||||
).padding(horizontal: 4),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: ActivityPresenceWidget(
|
||||
uname: name,
|
||||
).padding(horizontal: 8, top: 4, bottom: 8),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -46,121 +46,178 @@ class _PublisherBasisWidget extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
spacing: 20,
|
||||
children: [
|
||||
GestureDetector(
|
||||
child: Badge(
|
||||
isLabelVisible: data.type == 0,
|
||||
padding: EdgeInsets.all(4),
|
||||
label: Icon(
|
||||
Symbols.launch,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onPrimary,
|
||||
),
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
offset: Offset(0, 48),
|
||||
child: ProfilePictureWidget(
|
||||
file: data.picture,
|
||||
radius: 32,
|
||||
borderRadius: data.type == 0 ? null : 12,
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
if (data.account?.name != null) {
|
||||
Navigator.pop(context, true);
|
||||
context.pushNamed(
|
||||
'accountProfile',
|
||||
pathParameters: {'name': data.account!.name},
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
return Card(
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
final hasBackground = data.background?.id != null;
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
spacing: 6,
|
||||
children: [
|
||||
Text(data.nick).fontSize(20),
|
||||
if (data.verification != null)
|
||||
VerificationMark(mark: data.verification!),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'@${data.name}',
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
).fontSize(14).opacity(0.85),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (data.type == 0 && data.account != null)
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
spacing: 6,
|
||||
if (isWideScreen(context) && hasBackground)
|
||||
Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Icon(
|
||||
data.type == 0 ? Symbols.person : Symbols.workspaces,
|
||||
fill: 1,
|
||||
size: 17,
|
||||
),
|
||||
Text(
|
||||
'publisherBelongsTo'.tr(args: ['@${data.account!.name}']),
|
||||
).fontSize(14),
|
||||
],
|
||||
).opacity(0.85),
|
||||
const Gap(4),
|
||||
if (data.type == 0 && data.account != null)
|
||||
AccountStatusWidget(
|
||||
uname: data.account!.name,
|
||||
padding: EdgeInsets.zero,
|
||||
),
|
||||
subStatus
|
||||
.when(
|
||||
data:
|
||||
(status) => FilledButton.icon(
|
||||
onPressed:
|
||||
subscribing.value
|
||||
? null
|
||||
: (status.isSubscribed
|
||||
? unsubscribe
|
||||
: subscribe),
|
||||
icon: Icon(
|
||||
status.isSubscribed
|
||||
? Symbols.remove_circle
|
||||
: Symbols.add_circle,
|
||||
),
|
||||
label:
|
||||
Text(
|
||||
status.isSubscribed
|
||||
? 'unsubscribe'
|
||||
: 'subscribe',
|
||||
).tr(),
|
||||
style: ButtonStyle(
|
||||
visualDensity: VisualDensity(vertical: -2),
|
||||
),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(8),
|
||||
topRight: Radius.circular(8),
|
||||
),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 16 / 7,
|
||||
child: CloudImageWidget(
|
||||
file: data.background,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
error: (_, _) => const SizedBox(),
|
||||
loading:
|
||||
() => const SizedBox(
|
||||
height: 36,
|
||||
child: Center(
|
||||
child: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: -24,
|
||||
left: 16,
|
||||
child: ProfilePictureWidget(
|
||||
file: data.picture,
|
||||
radius: 32,
|
||||
borderRadius: data.type == 0 ? null : 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Builder(
|
||||
builder: (context) {
|
||||
final showBackground = isWideScreen(context) && hasBackground;
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
spacing: showBackground ? 0 : 20,
|
||||
children: [
|
||||
if (!showBackground)
|
||||
GestureDetector(
|
||||
child: Badge(
|
||||
isLabelVisible: data.type == 0,
|
||||
padding: EdgeInsets.all(4),
|
||||
label: Icon(
|
||||
Symbols.launch,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.onPrimary,
|
||||
),
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
offset: Offset(0, 48),
|
||||
child: ProfilePictureWidget(
|
||||
file: data.picture,
|
||||
radius: 32,
|
||||
borderRadius: data.type == 0 ? null : 12,
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
if (data.account?.name != null) {
|
||||
Navigator.pop(context, true);
|
||||
context.pushNamed(
|
||||
'accountProfile',
|
||||
pathParameters: {'name': data.account!.name},
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
.padding(top: 8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Row(
|
||||
spacing: 6,
|
||||
children: [
|
||||
Text(data.nick).fontSize(20),
|
||||
if (data.verification != null)
|
||||
VerificationMark(mark: data.verification!),
|
||||
if (isWideScreen(context))
|
||||
Expanded(
|
||||
child: Text(
|
||||
'@${data.name}',
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
).fontSize(14).opacity(0.85),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (!isWideScreen(context))
|
||||
Text(
|
||||
'@${data.name}',
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
).fontSize(14).opacity(0.85).padding(top: 4),
|
||||
if (data.type == 0 && data.account != null)
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
spacing: 6,
|
||||
children: [
|
||||
Icon(
|
||||
data.type == 0 ? Symbols.person : Symbols.workspaces,
|
||||
fill: 1,
|
||||
size: 17,
|
||||
),
|
||||
Text(
|
||||
'publisherBelongsTo'.tr(args: ['@${data.account!.name}']),
|
||||
).fontSize(14),
|
||||
],
|
||||
).opacity(0.85),
|
||||
const Gap(4),
|
||||
if (data.type == 0 && data.account != null)
|
||||
AccountStatusWidget(
|
||||
uname: data.account!.name,
|
||||
padding: EdgeInsets.zero,
|
||||
),
|
||||
subStatus
|
||||
.when(
|
||||
data:
|
||||
(status) => FilledButton.icon(
|
||||
onPressed:
|
||||
subscribing.value
|
||||
? null
|
||||
: (status.isSubscribed
|
||||
? unsubscribe
|
||||
: subscribe),
|
||||
icon: Icon(
|
||||
status.isSubscribed
|
||||
? Symbols.remove_circle
|
||||
: Symbols.add_circle,
|
||||
),
|
||||
label:
|
||||
Text(
|
||||
status.isSubscribed
|
||||
? 'unsubscribe'
|
||||
: 'subscribe',
|
||||
).tr(),
|
||||
style: ButtonStyle(
|
||||
visualDensity: VisualDensity(vertical: -2),
|
||||
),
|
||||
),
|
||||
error: (_, _) => const SizedBox(),
|
||||
loading:
|
||||
() => const SizedBox(
|
||||
height: 36,
|
||||
child: Center(
|
||||
child: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
.padding(vertical: 8),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
).padding(
|
||||
left: 16,
|
||||
right: 16,
|
||||
top: 16 + (showBackground ? 16 : 0),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
).padding(horizontal: 24, top: 24);
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,35 +457,14 @@ class PublisherProfileScreen extends HookConsumerWidget {
|
||||
color: appbarColor.value,
|
||||
shadows: [appbarShadow],
|
||||
),
|
||||
flexibleSpace: Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child:
|
||||
data.background?.id != null
|
||||
? CloudImageWidget(file: data.background)
|
||||
: Container(
|
||||
color:
|
||||
Theme.of(
|
||||
context,
|
||||
).appBarTheme.backgroundColor,
|
||||
),
|
||||
),
|
||||
FlexibleSpaceBar(
|
||||
title: Text(
|
||||
data.nick,
|
||||
style: TextStyle(
|
||||
color:
|
||||
appbarColor.value ??
|
||||
Theme.of(
|
||||
context,
|
||||
).appBarTheme.foregroundColor,
|
||||
shadows: [appbarShadow],
|
||||
),
|
||||
),
|
||||
background:
|
||||
Container(), // Empty container since background is handled by Stack
|
||||
),
|
||||
],
|
||||
title: Text(
|
||||
data.nick,
|
||||
style: TextStyle(
|
||||
color:
|
||||
appbarColor.value ??
|
||||
Theme.of(context).appBarTheme.foregroundColor,
|
||||
shadows: [appbarShadow],
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
@@ -477,7 +513,7 @@ class PublisherProfileScreen extends HookConsumerWidget {
|
||||
subscribing: subscribing,
|
||||
subscribe: subscribe,
|
||||
unsubscribe: unsubscribe,
|
||||
).padding(bottom: 8),
|
||||
).padding(horizontal: 4, top: 20),
|
||||
_PublisherBadgesWidget(
|
||||
data: data,
|
||||
badges: badges,
|
||||
@@ -487,7 +523,7 @@ class PublisherProfileScreen extends HookConsumerWidget {
|
||||
_PublisherHeatmapWidget(
|
||||
heatmap: heatmap,
|
||||
forceDense: true,
|
||||
),
|
||||
).padding(vertical: 4),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -545,7 +581,7 @@ class PublisherProfileScreen extends HookConsumerWidget {
|
||||
subscribing: subscribing,
|
||||
subscribe: subscribe,
|
||||
unsubscribe: unsubscribe,
|
||||
).padding(bottom: 8),
|
||||
).padding(horizontal: 4, top: 8),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: _PublisherBadgesWidget(
|
||||
@@ -560,7 +596,7 @@ class PublisherProfileScreen extends HookConsumerWidget {
|
||||
child: _PublisherBioWidget(data: data),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: _PublisherHeatmapWidget(heatmap: heatmap),
|
||||
child: _PublisherHeatmapWidget(heatmap: heatmap).padding(vertical: 4),
|
||||
),
|
||||
SliverPostList(pubName: name, pinned: true),
|
||||
SliverToBoxAdapter(
|
||||
|
||||
@@ -256,7 +256,7 @@ class ActivityPresenceWidget extends ConsumerWidget {
|
||||
children: [
|
||||
Text(
|
||||
'activities',
|
||||
).tr().bold().padding(horizontal: 8, vertical: 4),
|
||||
).tr().bold().padding(horizontal: 16, vertical: 4),
|
||||
if (activities.isEmpty)
|
||||
Row(
|
||||
spacing: 4,
|
||||
@@ -264,7 +264,7 @@ class ActivityPresenceWidget extends ConsumerWidget {
|
||||
const Icon(Symbols.inbox, size: 16),
|
||||
Text('dataEmpty').tr().fontSize(13),
|
||||
],
|
||||
).opacity(0.75).padding(horizontal: 8),
|
||||
).opacity(0.75).padding(horizontal: 16, bottom: 8),
|
||||
...activities.map((activity) {
|
||||
final dcImages = _buildDiscordImages(ref, activity);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user