Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-12-23 17:07:02 +08:00
parent 7da6f05a50
commit 259e7080f8
6 changed files with 130 additions and 131 deletions

View File

@@ -0,0 +1,54 @@
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
import 'package:PiliPlus/models/model_owner.dart';
import 'package:flutter/material.dart';
Widget avatars({
required ColorScheme colorScheme,
required Iterable<Owner> users,
}) {
const gap = 6.0;
const size = 22.0;
const offset = size - gap;
if (users.length == 1) {
return NetworkImgLayer(
src: users.first.face,
width: size,
height: size,
type: .avatar,
);
} else {
final decoration = BoxDecoration(
shape: .circle,
border: Border.all(color: colorScheme.surface),
);
return SizedBox(
height: size,
width: offset * users.length + gap,
child: Stack(
clipBehavior: .none,
children: users.indexed
.map(
(e) => Positioned(
top: 0,
bottom: 0,
width: size,
left: e.$1 * offset,
child: DecoratedBox(
decoration: decoration,
child: Padding(
padding: const .all(.8),
child: NetworkImgLayer(
src: e.$2.face,
width: size - .8,
height: size - .8,
type: .avatar,
),
),
),
),
)
.toList(),
),
);
}
}

View File

@@ -4,6 +4,7 @@ import 'package:PiliPlus/common/widgets/pendant_avatar.dart';
import 'package:PiliPlus/models/common/dynamic/dynamics_type.dart'; import 'package:PiliPlus/models/common/dynamic/dynamics_type.dart';
import 'package:PiliPlus/models/dynamics/article_content_model.dart'; import 'package:PiliPlus/models/dynamics/article_content_model.dart';
import 'package:PiliPlus/models/model_avatar.dart'; import 'package:PiliPlus/models/model_avatar.dart';
import 'package:PiliPlus/models/model_owner.dart';
import 'package:PiliPlus/models_new/live/live_feed_index/watched_show.dart'; import 'package:PiliPlus/models_new/live/live_feed_index/watched_show.dart';
import 'package:PiliPlus/utils/extension/iterable_ext.dart'; import 'package:PiliPlus/utils/extension/iterable_ext.dart';
import 'package:PiliPlus/utils/storage_pref.dart'; import 'package:PiliPlus/utils/storage_pref.dart';
@@ -236,10 +237,12 @@ class ItemModulesModel {
class ModuleFold { class ModuleFold {
List<String>? ids; List<String>? ids;
String? statement; String? statement;
List<Owner>? users;
ModuleFold.fromJson(Map<String, dynamic> json) { ModuleFold.fromJson(Map<String, dynamic> json) {
ids = (json['ids'] as List?)?.fromCast(); ids = (json['ids'] as List?)?.fromCast();
statement = json['statement']; statement = json['statement'];
users = (json['users'] as List?)?.map((e) => Owner.fromJson(e)).toList();
} }
} }

View File

@@ -1,20 +1,26 @@
class FolloweeVote { import 'package:PiliPlus/models/model_owner.dart';
int uid;
String name; class FolloweeVote extends Owner {
String face; String _name;
@override
String get name => _name;
String _face;
@override
String get face => _face;
List<int> votes; List<int> votes;
int ctime; int ctime;
FolloweeVote({ FolloweeVote({
required this.uid, required super.mid,
required this.name, required String name,
required this.face, required String face,
required this.votes, required this.votes,
required this.ctime, required this.ctime,
}); }) : _name = name,
_face = face;
factory FolloweeVote.fromJson(Map<String, dynamic> json) => FolloweeVote( factory FolloweeVote.fromJson(Map<String, dynamic> json) => FolloweeVote(
uid: json['uid'], mid: json['uid'],
name: json['name'], name: json['name'],
face: json['face'], face: json['face'],
votes: List<int>.from(json['votes']), votes: List<int>.from(json['votes']),

View File

@@ -1,3 +1,4 @@
import 'package:PiliPlus/common/widgets/avatars.dart';
import 'package:PiliPlus/common/widgets/flutter/dyn/ink_well.dart'; import 'package:PiliPlus/common/widgets/flutter/dyn/ink_well.dart';
import 'package:PiliPlus/common/widgets/image/image_save.dart'; import 'package:PiliPlus/common/widgets/image/image_save.dart';
import 'package:PiliPlus/models/dynamics/result.dart'; import 'package:PiliPlus/models/dynamics/result.dart';
@@ -93,39 +94,7 @@ class DynamicPanel extends StatelessWidget {
height: 1, height: 1,
color: theme.dividerColor.withValues(alpha: 0.1), color: theme.dividerColor.withValues(alpha: 0.1),
), ),
InkWell( _buildFoldItem(theme, moduleFold),
onTap: onUnfold,
child: Container(
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(vertical: 10),
child: Text.rich(
textAlign: TextAlign.center,
style: TextStyle(
height: 1,
fontSize: 13,
color: theme.colorScheme.outline,
),
strutStyle: const StrutStyle(
height: 1,
leading: 0,
fontSize: 13,
),
TextSpan(
children: [
TextSpan(text: moduleFold.statement ?? '展开'),
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: Icon(
size: 19,
Icons.keyboard_arrow_down,
color: theme.colorScheme.outline,
),
),
],
),
),
),
),
], ],
] else if (!isSave) ] else if (!isSave)
const SizedBox(height: 12), const SizedBox(height: 12),
@@ -216,4 +185,52 @@ class DynamicPanel extends StatelessWidget {
bvid: bvid, bvid: bvid,
); );
} }
Widget _buildFoldItem(ThemeData theme, ModuleFold moduleFold) {
Widget child = Text.rich(
textAlign: TextAlign.center,
style: TextStyle(
height: 1,
fontSize: 13,
color: theme.colorScheme.outline,
),
strutStyle: const StrutStyle(
height: 1,
leading: 0,
fontSize: 13,
),
TextSpan(
children: [
TextSpan(text: moduleFold.statement ?? '展开'),
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: Icon(
size: 19,
Icons.keyboard_arrow_down,
color: theme.colorScheme.outline,
),
),
],
),
);
final users = moduleFold.users;
if (users != null && users.isNotEmpty) {
child = Row(
spacing: 5,
mainAxisAlignment: .center,
children: [
avatars(colorScheme: theme.colorScheme, users: users),
child,
],
);
}
return InkWell(
onTap: onUnfold,
child: Container(
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(vertical: 10),
child: child,
),
);
}
} }

View File

@@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:math'; import 'dart:math';
import 'package:PiliPlus/common/widgets/avatars.dart';
import 'package:PiliPlus/common/widgets/badge.dart'; import 'package:PiliPlus/common/widgets/badge.dart';
import 'package:PiliPlus/common/widgets/dialog/report.dart'; import 'package:PiliPlus/common/widgets/dialog/report.dart';
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
@@ -149,51 +150,6 @@ class _VotePanelState extends State<VotePanel> {
Obx(() { Obx(() {
final list = followeeVote.value; final list = followeeVote.value;
if (list != null && list.isNotEmpty) { if (list != null && list.isNotEmpty) {
Widget child;
const size = 22.0;
const gap = 6.0;
const offset = size - gap;
if (list.length == 1) {
child = NetworkImgLayer(
src: list.first.face,
width: size,
height: size,
);
} else {
final decoration = BoxDecoration(
shape: .circle,
border: Border.all(color: theme.colorScheme.surface),
);
child = SizedBox(
height: size,
width: offset * min(3, list.length) + gap,
child: Stack(
clipBehavior: .none,
children: list
.take(3)
.indexed
.map(
(e) => Positioned(
top: 0,
left: e.$1 * offset,
bottom: 0,
child: DecoratedBox(
decoration: decoration,
child: Padding(
padding: const .all(.8),
child: NetworkImgLayer(
src: e.$2.face,
width: size - .8,
height: size - .8,
),
),
),
),
)
.toList(),
),
);
}
return GestureDetector( return GestureDetector(
behavior: .opaque, behavior: .opaque,
onTap: () { onTap: () {
@@ -213,7 +169,7 @@ class _VotePanelState extends State<VotePanel> {
(e) => ListTile( (e) => ListTile(
dense: true, dense: true,
onTap: () => onTap: () =>
Get.toNamed('/member?mid=${e.uid}'), Get.toNamed('/member?mid=${e.mid}'),
leading: NetworkImgLayer( leading: NetworkImgLayer(
src: e.face, src: e.face,
width: 40, width: 40,
@@ -259,7 +215,10 @@ class _VotePanelState extends State<VotePanel> {
child: Row( child: Row(
mainAxisSize: .min, mainAxisSize: .min,
children: [ children: [
child, avatars(
colorScheme: theme.colorScheme,
users: list.take(3),
),
Icon( Icon(
size: 18, size: 18,
color: theme.colorScheme.outline.withValues(alpha: .7), color: theme.colorScheme.outline.withValues(alpha: .7),

View File

@@ -1,9 +1,8 @@
import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/avatars.dart';
import 'package:PiliPlus/common/widgets/pendant_avatar.dart'; import 'package:PiliPlus/common/widgets/pendant_avatar.dart';
import 'package:PiliPlus/common/widgets/view_safe_area.dart'; import 'package:PiliPlus/common/widgets/view_safe_area.dart';
import 'package:PiliPlus/models/common/image_preview_type.dart'; import 'package:PiliPlus/models/common/image_preview_type.dart';
import 'package:PiliPlus/models/common/image_type.dart';
import 'package:PiliPlus/models/common/member/user_info_type.dart'; import 'package:PiliPlus/models/common/member/user_info_type.dart';
import 'package:PiliPlus/models_new/space/space/card.dart'; import 'package:PiliPlus/models_new/space/space/card.dart';
import 'package:PiliPlus/models_new/space/space/followings_followed_upper.dart'; import 'package:PiliPlus/models_new/space/space/followings_followed_upper.dart';
@@ -601,50 +600,11 @@ class UserInfoCard extends StatelessWidget {
var list = item.items!; var list = item.items!;
final flag = list.length > 3; final flag = list.length > 3;
if (flag) list = list.sublist(0, 3); if (flag) list = list.sublist(0, 3);
final length = list.length;
const size = 22.0;
Widget avatar(String url) => NetworkImgLayer(
src: url,
width: size,
height: size,
type: ImageType.avatar,
);
Widget avatars;
if (length == 1) {
avatars = avatar(list.first.face!);
} else {
const gap = 4.0;
const offset = size - gap;
final decoration = BoxDecoration(
shape: BoxShape.circle,
border: Border.all(color: colorScheme.surface),
);
avatars = SizedBox(
width: length * size - (length - 1) * gap,
height: size + 1.6,
child: Stack(
clipBehavior: Clip.none,
children: List.generate(
length,
(index) => Positioned(
right: index * offset,
child: DecoratedBox(
decoration: decoration,
child: Padding(
padding: const EdgeInsets.all(.8),
child: avatar(list[length - 1 - index].face!),
),
),
),
),
),
);
}
Widget child = Row( Widget child = Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
const SizedBox(width: 20), const SizedBox(width: 20),
avatars, avatars(colorScheme: colorScheme, users: list),
const SizedBox(width: 4), const SizedBox(width: 4),
Flexible( Flexible(
child: Text( child: Text(