mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-05-30 23:58:13 +08:00
54
lib/common/widgets/avatars.dart
Normal file
54
lib/common/widgets/avatars.dart
Normal 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(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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']),
|
||||||
|
|||||||
@@ -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,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
Reference in New Issue
Block a user