fix: wrap long badge displays
This commit is contained in:
parent
d5653afa4f
commit
c2b5ef9e16
@ -436,6 +436,29 @@ class _PersonDetailPageState extends State<PersonDetailPage> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHeaderLongBadgeStrip(SocialChatUserProfileManager ref) {
|
||||
return SizedBox(
|
||||
width: ScreenUtil().screenWidth - 40.w,
|
||||
child: SCUserBadgeStrip(
|
||||
userId: ref.userProfile?.id ?? widget.tageId,
|
||||
fallbackBadges:
|
||||
ref.userProfile?.wearBadge
|
||||
?.where((item) => item.use ?? false)
|
||||
.toList() ??
|
||||
const <WearBadge>[],
|
||||
displayScope: SCUserBadgeDisplayScope.long,
|
||||
height: 45.w,
|
||||
badgeHeight: 20.w,
|
||||
longBadgeWidth: 62.w,
|
||||
spacing: 4.w,
|
||||
wrap: true,
|
||||
maxWrapRows: 2,
|
||||
scrollLastWrapRow: true,
|
||||
reserveSpace: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHeaderIntroduction(SocialChatUserProfileManager ref) {
|
||||
final intro = (ref.userProfile?.autograph ?? "").trim();
|
||||
return Container(
|
||||
@ -674,6 +697,8 @@ class _PersonDetailPageState extends State<PersonDetailPage> {
|
||||
SizedBox(height: 5.w),
|
||||
_buildHeaderMeta(ref),
|
||||
SizedBox(height: 4.w),
|
||||
_buildHeaderLongBadgeStrip(ref),
|
||||
SizedBox(height: 4.w),
|
||||
_buildHeaderBadgeStrip(ref),
|
||||
SizedBox(height: 6.w),
|
||||
_buildHeaderIntroduction(ref),
|
||||
|
||||
@ -20,6 +20,8 @@ class SCUserBadgeStrip extends StatefulWidget {
|
||||
this.spacing,
|
||||
this.maxBadges,
|
||||
this.wrap = false,
|
||||
this.maxWrapRows,
|
||||
this.scrollLastWrapRow = false,
|
||||
this.reserveSpace = false,
|
||||
this.alignment = WrapAlignment.center,
|
||||
});
|
||||
@ -33,6 +35,8 @@ class SCUserBadgeStrip extends StatefulWidget {
|
||||
final double? spacing;
|
||||
final int? maxBadges;
|
||||
final bool wrap;
|
||||
final int? maxWrapRows;
|
||||
final bool scrollLastWrapRow;
|
||||
final bool reserveSpace;
|
||||
final WrapAlignment alignment;
|
||||
|
||||
@ -164,6 +168,14 @@ class _SCUserBadgeStripState extends State<SCUserBadgeStrip> {
|
||||
.toList();
|
||||
|
||||
if (widget.wrap) {
|
||||
if (widget.maxWrapRows != null) {
|
||||
return _buildLimitedWrapBadges(
|
||||
badges,
|
||||
stripHeight: stripHeight,
|
||||
badgeHeight: badgeHeight,
|
||||
spacing: spacing,
|
||||
);
|
||||
}
|
||||
return SizedBox(
|
||||
height: stripHeight,
|
||||
child: Center(
|
||||
@ -187,14 +199,137 @@ class _SCUserBadgeStripState extends State<SCUserBadgeStrip> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLimitedWrapBadges(
|
||||
List<WearBadge> badges, {
|
||||
required double stripHeight,
|
||||
required double badgeHeight,
|
||||
required double spacing,
|
||||
}) {
|
||||
final maxRows = widget.maxWrapRows ?? 1;
|
||||
if (maxRows <= 1) {
|
||||
return _buildScrollableBadgeRow(
|
||||
badges,
|
||||
stripHeight: stripHeight,
|
||||
badgeHeight: badgeHeight,
|
||||
spacing: spacing,
|
||||
);
|
||||
}
|
||||
|
||||
return SizedBox(
|
||||
height: stripHeight,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final maxWidth =
|
||||
constraints.maxWidth.isFinite
|
||||
? constraints.maxWidth
|
||||
: _badgesTotalWidth(badges, badgeHeight, spacing);
|
||||
final widestBadge = badges
|
||||
.map((badge) => _badgeWidth(badge, badgeHeight))
|
||||
.fold<double>(
|
||||
0,
|
||||
(current, width) => width > current ? width : current,
|
||||
);
|
||||
final perRow =
|
||||
widestBadge <= 0
|
||||
? badges.length
|
||||
: ((maxWidth + spacing) / (widestBadge + spacing))
|
||||
.floor()
|
||||
.clamp(1, badges.length);
|
||||
final firstRows = maxRows - 1;
|
||||
final fixedCount = (perRow * firstRows).clamp(0, badges.length);
|
||||
final fixedBadges = badges.take(fixedCount).toList();
|
||||
final lastRowBadges = badges.skip(fixedCount).toList();
|
||||
final rows = <Widget>[];
|
||||
|
||||
for (var start = 0; start < fixedBadges.length; start += perRow) {
|
||||
final end =
|
||||
start + perRow > fixedBadges.length
|
||||
? fixedBadges.length
|
||||
: start + perRow;
|
||||
rows.add(
|
||||
_buildBadgeRow(
|
||||
fixedBadges.sublist(start, end),
|
||||
badgeHeight: badgeHeight,
|
||||
spacing: spacing,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (lastRowBadges.isNotEmpty) {
|
||||
rows.add(
|
||||
widget.scrollLastWrapRow
|
||||
? _buildScrollableBadgeRow(
|
||||
lastRowBadges,
|
||||
stripHeight: badgeHeight,
|
||||
badgeHeight: badgeHeight,
|
||||
spacing: spacing,
|
||||
)
|
||||
: _buildBadgeRow(
|
||||
lastRowBadges.take(perRow).toList(),
|
||||
badgeHeight: badgeHeight,
|
||||
spacing: spacing,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (rows.isEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: _withVerticalSpacing(rows, 5.w),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBadgeRow(
|
||||
List<WearBadge> badges, {
|
||||
required double badgeHeight,
|
||||
required double spacing,
|
||||
}) {
|
||||
return SizedBox(
|
||||
height: badgeHeight,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: _rowAlignment,
|
||||
children: _withSpacing(
|
||||
badges
|
||||
.map((badge) => _buildBadge(badge, badgeHeight: badgeHeight))
|
||||
.toList(),
|
||||
spacing,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildScrollableBadgeRow(
|
||||
List<WearBadge> badges, {
|
||||
required double stripHeight,
|
||||
required double badgeHeight,
|
||||
required double spacing,
|
||||
}) {
|
||||
return SizedBox(
|
||||
height: stripHeight,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
physics: const BouncingScrollPhysics(),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: _withSpacing(
|
||||
badges
|
||||
.map((badge) => _buildBadge(badge, badgeHeight: badgeHeight))
|
||||
.toList(),
|
||||
spacing,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBadge(WearBadge badge, {required double badgeHeight}) {
|
||||
final type = badge.type?.trim().toUpperCase() ?? "";
|
||||
final sourceType = badge.sourceType?.trim().toUpperCase() ?? "";
|
||||
final isLongBadge = type == "LONG" || type == "VIP" || sourceType == "VIP";
|
||||
final width =
|
||||
isLongBadge
|
||||
? (widget.longBadgeWidth ?? badgeHeight * 2.2)
|
||||
: badgeHeight;
|
||||
final width = _badgeWidth(badge, badgeHeight);
|
||||
return netImage(
|
||||
url: _badgeUrl(badge),
|
||||
width: width,
|
||||
@ -206,6 +341,47 @@ class _SCUserBadgeStripState extends State<SCUserBadgeStrip> {
|
||||
);
|
||||
}
|
||||
|
||||
double _badgeWidth(WearBadge badge, double badgeHeight) {
|
||||
final type = badge.type?.trim().toUpperCase() ?? "";
|
||||
final sourceType = badge.sourceType?.trim().toUpperCase() ?? "";
|
||||
final isLongBadge = type == "LONG" || type == "VIP" || sourceType == "VIP";
|
||||
return isLongBadge
|
||||
? (widget.longBadgeWidth ?? badgeHeight * 2.2)
|
||||
: badgeHeight;
|
||||
}
|
||||
|
||||
double _badgesTotalWidth(
|
||||
List<WearBadge> badges,
|
||||
double badgeHeight,
|
||||
double spacing,
|
||||
) {
|
||||
if (badges.isEmpty) {
|
||||
return 0;
|
||||
}
|
||||
final badgeWidth = badges.fold<double>(
|
||||
0,
|
||||
(sum, badge) => sum + _badgeWidth(badge, badgeHeight),
|
||||
);
|
||||
return badgeWidth + spacing * (badges.length - 1);
|
||||
}
|
||||
|
||||
MainAxisAlignment get _rowAlignment {
|
||||
switch (widget.alignment) {
|
||||
case WrapAlignment.start:
|
||||
return MainAxisAlignment.start;
|
||||
case WrapAlignment.end:
|
||||
return MainAxisAlignment.end;
|
||||
case WrapAlignment.spaceBetween:
|
||||
return MainAxisAlignment.spaceBetween;
|
||||
case WrapAlignment.spaceAround:
|
||||
return MainAxisAlignment.spaceAround;
|
||||
case WrapAlignment.spaceEvenly:
|
||||
return MainAxisAlignment.spaceEvenly;
|
||||
case WrapAlignment.center:
|
||||
return MainAxisAlignment.center;
|
||||
}
|
||||
}
|
||||
|
||||
String _badgeUrl(WearBadge badge) {
|
||||
return (badge.selectUrl ?? "").trim();
|
||||
}
|
||||
@ -223,6 +399,20 @@ class _SCUserBadgeStripState extends State<SCUserBadgeStrip> {
|
||||
}
|
||||
return spaced;
|
||||
}
|
||||
|
||||
List<Widget> _withVerticalSpacing(List<Widget> children, double spacing) {
|
||||
if (children.length < 2) {
|
||||
return children;
|
||||
}
|
||||
final spaced = <Widget>[];
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
if (i > 0) {
|
||||
spaced.add(SizedBox(height: spacing));
|
||||
}
|
||||
spaced.add(children[i]);
|
||||
}
|
||||
return spaced;
|
||||
}
|
||||
}
|
||||
|
||||
class _BadgeFutureCacheEntry {
|
||||
|
||||
@ -562,16 +562,18 @@ class _RoomUserInfoCardState extends State<RoomUserInfoCard> {
|
||||
SocialChatUserProfile? profile,
|
||||
) {
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: 64.w),
|
||||
constraints: BoxConstraints(maxWidth: 140.w),
|
||||
child: SCUserBadgeStrip(
|
||||
userId: userId,
|
||||
fallbackBadges: _roomCardFallbackBadges(ref, profile),
|
||||
displayScope: SCUserBadgeDisplayScope.long,
|
||||
height: 22.w,
|
||||
height: 45.w,
|
||||
badgeHeight: 20.w,
|
||||
longBadgeWidth: 62.w,
|
||||
spacing: 0,
|
||||
maxBadges: 1,
|
||||
spacing: 4.w,
|
||||
wrap: true,
|
||||
maxWrapRows: 2,
|
||||
scrollLastWrapRow: true,
|
||||
reserveSpace: false,
|
||||
),
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user