💄 Experimental new attachment layout

This commit is contained in:
LittleSheep 2024-12-29 12:02:26 +08:00
parent e503c3f02f
commit f6cf6d0440
7 changed files with 88 additions and 78 deletions

View File

@ -458,6 +458,7 @@
"accountJoinedAt": "Joined at {}", "accountJoinedAt": "Joined at {}",
"accountBirthday": "Born on {}", "accountBirthday": "Born on {}",
"accountBadge": "Badge", "accountBadge": "Badge",
"accountCheckInNoRecords": "No check-in records",
"badgeCompanyStaff": "Solsynth Staff", "badgeCompanyStaff": "Solsynth Staff",
"badgeSiteMigration": "Solar Network Native", "badgeSiteMigration": "Solar Network Native",
"accountStatus": "Status", "accountStatus": "Status",

View File

@ -456,6 +456,7 @@
"accountJoinedAt": "加入于 {}", "accountJoinedAt": "加入于 {}",
"accountBirthday": "出生于 {}", "accountBirthday": "出生于 {}",
"accountBadge": "徽章", "accountBadge": "徽章",
"accountCheckInNoRecords": "暂无运势记录",
"badgeCompanyStaff": "索尔辛茨士大夫 · 员工", "badgeCompanyStaff": "索尔辛茨士大夫 · 员工",
"badgeSiteMigration": "Solar Network 原住民", "badgeSiteMigration": "Solar Network 原住民",
"accountStatus": "状态", "accountStatus": "状态",

View File

@ -517,6 +517,12 @@ class _UserScreenState extends State<UserScreen> with SingleTickerProviderStateM
future: _getCheckInRecords(), future: _getCheckInRecords(),
builder: (context, snapshot) { builder: (context, snapshot) {
if (!snapshot.hasData) return const SizedBox.shrink(); if (!snapshot.hasData) return const SizedBox.shrink();
if (snapshot.data!.length <= 1) {
return Text(
'accountCheckInNoRecords',
textAlign: TextAlign.center,
).tr().fontWeight(FontWeight.bold).center().padding(horizontal: 20, vertical: 8);
}
final records = snapshot.data!; final records = snapshot.data!;
return SizedBox( return SizedBox(
width: double.infinity, width: double.infinity,

View File

@ -20,9 +20,11 @@ import 'package:uuid/uuid.dart';
class AttachmentItem extends StatelessWidget { class AttachmentItem extends StatelessWidget {
final SnAttachment? data; final SnAttachment? data;
final String? heroTag; final String? heroTag;
final BoxFit fit;
const AttachmentItem({ const AttachmentItem({
super.key, super.key,
this.fit = BoxFit.cover,
required this.data, required this.data,
required this.heroTag, required this.heroTag,
}); });
@ -43,7 +45,7 @@ class AttachmentItem extends StatelessWidget {
child: AutoResizeUniversalImage( child: AutoResizeUniversalImage(
sn.getAttachmentUrl(data!.rid), sn.getAttachmentUrl(data!.rid),
key: Key('attachment-${data!.rid}-$tag'), key: Key('attachment-${data!.rid}-$tag'),
fit: BoxFit.cover, fit: fit,
), ),
); );
case 'video': case 'video':

View File

@ -4,8 +4,8 @@ import 'package:collection/collection.dart';
import 'package:dismissible_page/dismissible_page.dart'; import 'package:dismissible_page/dismissible_page.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:responsive_framework/responsive_framework.dart';
import 'package:surface/types/attachment.dart'; import 'package:surface/types/attachment.dart';
import 'package:surface/widgets/attachment/attachment_zoom.dart'; import 'package:surface/widgets/attachment/attachment_zoom.dart';
import 'package:surface/widgets/attachment/attachment_item.dart'; import 'package:surface/widgets/attachment/attachment_item.dart';
@ -14,8 +14,9 @@ import 'package:uuid/uuid.dart';
class AttachmentList extends StatefulWidget { class AttachmentList extends StatefulWidget {
final List<SnAttachment?> data; final List<SnAttachment?> data;
final bool bordered; final bool bordered;
final bool gridded;
final bool noGrow; final bool noGrow;
final bool isFlatted; final BoxFit fit;
final double? maxHeight; final double? maxHeight;
final EdgeInsets? listPadding; final EdgeInsets? listPadding;
@ -23,8 +24,9 @@ class AttachmentList extends StatefulWidget {
super.key, super.key,
required this.data, required this.data,
this.bordered = false, this.bordered = false,
this.gridded = false,
this.noGrow = false, this.noGrow = false,
this.isFlatted = false, this.fit = BoxFit.cover,
this.maxHeight, this.maxHeight,
this.listPadding, this.listPadding,
}); });
@ -53,7 +55,6 @@ class _AttachmentListState extends State<AttachmentList> {
final constraints = BoxConstraints( final constraints = BoxConstraints(
minWidth: 80, minWidth: 80,
maxHeight: widget.maxHeight ?? double.infinity, maxHeight: widget.maxHeight ?? double.infinity,
maxWidth: layoutConstraints.maxWidth - 20,
); );
if (widget.data.isEmpty) return const SizedBox.shrink(); if (widget.data.isEmpty) return const SizedBox.shrink();
@ -66,52 +67,29 @@ class _AttachmentListState extends State<AttachmentList> {
} }
.toDouble(); .toDouble();
return Container( return Padding(
constraints: ResponsiveBreakpoints.of(context).largerThan(MOBILE) padding: widget.listPadding ?? EdgeInsets.zero,
? constraints.copyWith( child: Container(
maxWidth: math.min( constraints: constraints,
constraints.maxWidth, width: double.infinity,
kAttachmentMaxWidth,
),
)
: null,
child: AspectRatio(
aspectRatio: singleAspectRatio,
child: GestureDetector( child: GestureDetector(
child: Builder( child: AspectRatio(
builder: (context) { aspectRatio: singleAspectRatio,
if (ResponsiveBreakpoints.of(context).largerThan(MOBILE) || widget.noGrow) { child: Container(
return Padding( decoration: BoxDecoration(
// Single child list-like displaying color: backgroundColor,
padding: widget.listPadding ?? EdgeInsets.zero, border: Border.fromBorderSide(borderSide),
child: Container( borderRadius: AttachmentList.kDefaultRadius,
decoration: BoxDecoration( ),
color: backgroundColor, child: ClipRRect(
border: Border(top: borderSide, bottom: borderSide), borderRadius: AttachmentList.kDefaultRadius,
borderRadius: AttachmentList.kDefaultRadius,
),
child: ClipRRect(
borderRadius: AttachmentList.kDefaultRadius,
child: AttachmentItem(
data: widget.data[0],
heroTag: heroTags[0],
),
),
),
);
}
return Container(
decoration: BoxDecoration(
color: backgroundColor,
border: Border(top: borderSide, bottom: borderSide),
),
child: AttachmentItem( child: AttachmentItem(
data: widget.data[0], data: widget.data[0],
heroTag: heroTags.first, heroTag: heroTags[0],
fit: widget.fit,
), ),
); ),
}, ),
), ),
onTap: () { onTap: () {
if (widget.data.firstOrNull?.mediaType != SnMediaType.image) return; if (widget.data.firstOrNull?.mediaType != SnMediaType.image) return;
@ -130,34 +108,53 @@ class _AttachmentListState extends State<AttachmentList> {
); );
} }
if (widget.isFlatted) { if (widget.gridded) {
return Wrap( return Padding(
spacing: 4, padding: widget.listPadding ?? EdgeInsets.zero,
runSpacing: 4, child: Container(
children: widget.data decoration: BoxDecoration(
.mapIndexed( color: backgroundColor,
(idx, ele) => AspectRatio( border: Border(
aspectRatio: (ele?.data['ratio'] ?? 1).toDouble(), top: borderSide,
child: Container( bottom: borderSide,
decoration: BoxDecoration( ),
color: backgroundColor, borderRadius: AttachmentList.kDefaultRadius,
border: Border( ),
top: borderSide, child: ClipRRect(
bottom: borderSide, borderRadius: AttachmentList.kDefaultRadius,
child: StaggeredGrid.count(
crossAxisCount: math.min(widget.data.length, 2),
crossAxisSpacing: 4,
mainAxisSpacing: 4,
children: widget.data
.mapIndexed(
(idx, ele) => GestureDetector(
child: Container(
constraints: constraints,
child: AttachmentItem(
data: ele,
heroTag: heroTags[idx],
fit: widget.fit,
),
),
onTap: () {
if (widget.data[idx]!.mediaType != SnMediaType.image) return;
context.pushTransparentRoute(
AttachmentZoomView(
data: widget.data.where((ele) => ele != null).cast(),
initialIndex: idx,
heroTags: heroTags,
),
backgroundColor: Colors.black.withOpacity(0.7),
rootNavigator: true,
);
},
), ),
borderRadius: AttachmentList.kDefaultRadius, )
), .toList(),
child: ClipRRect( ),
borderRadius: AttachmentList.kDefaultRadius, ),
child: AttachmentItem( ),
data: ele,
heroTag: heroTags[idx],
),
),
),
),
)
.toList(),
); );
} }

View File

@ -159,6 +159,7 @@ class ChatMessage extends StatelessWidget {
AttachmentList( AttachmentList(
data: data.preload!.attachments!, data: data.preload!.attachments!,
bordered: true, bordered: true,
gridded: true,
noGrow: true, noGrow: true,
maxHeight: 520, maxHeight: 520,
listPadding: const EdgeInsets.only(top: 8), listPadding: const EdgeInsets.only(top: 8),

View File

@ -251,7 +251,9 @@ class PostItem extends StatelessWidget {
AttachmentList( AttachmentList(
data: data.preload!.attachments!, data: data.preload!.attachments!,
bordered: true, bordered: true,
maxHeight: 560, gridded: true,
maxHeight: showFullPost ? null : 480,
fit: showFullPost ? BoxFit.cover : BoxFit.contain,
listPadding: const EdgeInsets.symmetric(horizontal: 12), listPadding: const EdgeInsets.symmetric(horizontal: 12),
), ),
if (data.body['content'] != null) if (data.body['content'] != null)
@ -337,7 +339,7 @@ class PostShareImageWidget extends StatelessWidget {
if (data.type != 'article' && (data.preload?.attachments?.isNotEmpty ?? false)) if (data.type != 'article' && (data.preload?.attachments?.isNotEmpty ?? false))
AttachmentList( AttachmentList(
data: data.preload!.attachments!, data: data.preload!.attachments!,
isFlatted: true, gridded: true,
).padding(horizontal: 16, bottom: 8), ).padding(horizontal: 16, bottom: 8),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -930,12 +932,12 @@ class _PostQuoteContent extends StatelessWidget {
), ),
child: AttachmentList( child: AttachmentList(
data: child.preload!.attachments!, data: child.preload!.attachments!,
isFlatted: isFlatted, gridded: isFlatted,
listPadding: const EdgeInsets.symmetric(horizontal: 12), listPadding: const EdgeInsets.symmetric(horizontal: 12),
), ),
).padding( ).padding(
top: 8, top: 8,
bottom: (child.preload?.attachments?.length ?? 0) > 1 ? 12 : 0, bottom: 12,
) )
else else
const Gap(8), const Gap(8),