Merge pull request #1 from guozhigq/feature-videoReply
Feature video reply
BIN
assets/images/lv/lv0.png
Normal file
|
After Width: | Height: | Size: 514 B |
BIN
assets/images/lv/lv1.png
Normal file
|
After Width: | Height: | Size: 524 B |
BIN
assets/images/lv/lv2.png
Normal file
|
After Width: | Height: | Size: 518 B |
BIN
assets/images/lv/lv3.png
Normal file
|
After Width: | Height: | Size: 541 B |
BIN
assets/images/lv/lv4.png
Normal file
|
After Width: | Height: | Size: 498 B |
BIN
assets/images/lv/lv5.png
Normal file
|
After Width: | Height: | Size: 539 B |
BIN
assets/images/lv/lv6.png
Normal file
|
After Width: | Height: | Size: 517 B |
@ -45,4 +45,4 @@ SPEC CHECKSUMS:
|
||||
|
||||
PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3
|
||||
|
||||
COCOAPODS: 1.11.3
|
||||
COCOAPODS: 1.12.1
|
||||
|
||||
@ -36,6 +36,7 @@ class NetworkImgLayer extends StatelessWidget {
|
||||
imageUrl: src!,
|
||||
width: width ?? double.infinity,
|
||||
height: height ?? double.infinity,
|
||||
alignment: Alignment.center,
|
||||
maxWidthDiskCache: ((cacheW ?? width!) * pr).toInt(),
|
||||
// maxHeightDiskCache: (cacheH ?? height!).toInt(),
|
||||
memCacheWidth: ((cacheW ?? width!) * pr).toInt(),
|
||||
|
||||
@ -14,8 +14,11 @@ class ReplyHttp {
|
||||
'type': type,
|
||||
'sort': 1,
|
||||
});
|
||||
print(res);
|
||||
if (res.data['code'] == 0) {
|
||||
return {
|
||||
'status': true,
|
||||
'data': res.data['data'],
|
||||
};
|
||||
} else {
|
||||
Map errMap = {
|
||||
-400: '请求错误',
|
||||
|
||||
17
lib/models/video/reply/config.dart
Normal file
@ -0,0 +1,17 @@
|
||||
class ReplyConfig {
|
||||
ReplyConfig({
|
||||
this.showtopic,
|
||||
this.showUpFlag,
|
||||
this.readOnly,
|
||||
});
|
||||
|
||||
int? showtopic;
|
||||
bool? showUpFlag;
|
||||
bool? readOnly;
|
||||
|
||||
ReplyConfig.fromJson(Map<String, dynamic> json) {
|
||||
showtopic = json['showtopic'];
|
||||
showUpFlag = json['show_up_flag'];
|
||||
readOnly = json['read_only'];
|
||||
}
|
||||
}
|
||||
26
lib/models/video/reply/content.dart
Normal file
@ -0,0 +1,26 @@
|
||||
class ReplyContent {
|
||||
ReplyContent({
|
||||
this.message,
|
||||
this.atNameToMid, // @的用户的mid null
|
||||
this.memebers, // 被@的用户List 如果有的话 []
|
||||
this.emote, // 表情包 如果有的话 null
|
||||
this.jumpUrl, // {}
|
||||
this.pictures, // {}
|
||||
});
|
||||
|
||||
String? message;
|
||||
Map? atNameToMid;
|
||||
List? memebers;
|
||||
Map? emote;
|
||||
Map? jumpUrl;
|
||||
List? pictures;
|
||||
|
||||
ReplyContent.fromJson(Map<String, dynamic> json) {
|
||||
message = json['message'];
|
||||
atNameToMid = json['at_name_to_mid'] ?? {};
|
||||
memebers = json['memebers'] ?? [];
|
||||
emote = json['emote'] ?? {};
|
||||
jumpUrl = json['jump_url'] ?? {};
|
||||
pictures = json['pictures'] ?? [];
|
||||
}
|
||||
}
|
||||
38
lib/models/video/reply/data.dart
Normal file
@ -0,0 +1,38 @@
|
||||
import 'package:pilipala/models/video/reply/item.dart';
|
||||
|
||||
import 'config.dart';
|
||||
import 'page.dart';
|
||||
import 'upper.dart';
|
||||
|
||||
class ReplyData {
|
||||
ReplyData({
|
||||
this.page,
|
||||
this.config,
|
||||
this.replies,
|
||||
this.topReplies,
|
||||
this.upper,
|
||||
});
|
||||
|
||||
ReplyPage? page;
|
||||
ReplyConfig? config;
|
||||
late List<ReplyItemModel>? replies;
|
||||
late List<ReplyItemModel>? topReplies;
|
||||
ReplyUpper? upper;
|
||||
|
||||
ReplyData.fromJson(Map<String, dynamic> json) {
|
||||
page = ReplyPage.fromJson(json['page']);
|
||||
config = ReplyConfig.fromJson(json['config']);
|
||||
replies = json['replies']
|
||||
.map<ReplyItemModel>(
|
||||
(item) => ReplyItemModel.fromJson(item, json['upper']['mid']))
|
||||
.toList();
|
||||
topReplies = json['top_replies'] != null
|
||||
? json['top_replies']
|
||||
.map<ReplyItemModel>((item) => ReplyItemModel.fromJson(
|
||||
item, json['upper']['mid'],
|
||||
isTopStatus: true))
|
||||
.toList()
|
||||
: [];
|
||||
upper = ReplyUpper.fromJson(json['upper']);
|
||||
}
|
||||
}
|
||||
154
lib/models/video/reply/item.dart
Normal file
@ -0,0 +1,154 @@
|
||||
import 'content.dart';
|
||||
import 'member.dart';
|
||||
|
||||
class ReplyItemModel {
|
||||
ReplyItemModel({
|
||||
this.rpid,
|
||||
this.oid,
|
||||
this.type,
|
||||
this.mid,
|
||||
this.root,
|
||||
this.parent,
|
||||
this.dialog,
|
||||
this.count,
|
||||
this.floor,
|
||||
this.state,
|
||||
this.fansgrade,
|
||||
this.attr,
|
||||
this.ctime,
|
||||
this.rpidStr,
|
||||
this.rootStr,
|
||||
this.parentStr,
|
||||
this.like,
|
||||
this.action,
|
||||
this.member,
|
||||
this.content,
|
||||
this.replies,
|
||||
this.assist,
|
||||
this.upAction,
|
||||
this.invisible,
|
||||
this.replyControl,
|
||||
this.isUp,
|
||||
this.isTop,
|
||||
});
|
||||
|
||||
int? rpid;
|
||||
int? oid;
|
||||
int? type;
|
||||
int? mid;
|
||||
int? root;
|
||||
int? parent;
|
||||
int? dialog;
|
||||
int? count;
|
||||
int? floor;
|
||||
int? state;
|
||||
int? fansgrade;
|
||||
int? attr;
|
||||
int? ctime;
|
||||
String? rpidStr;
|
||||
String? rootStr;
|
||||
String? parentStr;
|
||||
int? like;
|
||||
int? action;
|
||||
ReplyMember? member;
|
||||
ReplyContent? content;
|
||||
List? replies;
|
||||
int? assist;
|
||||
UpAction? upAction;
|
||||
bool? invisible;
|
||||
ReplyControl? replyControl;
|
||||
bool? isUp;
|
||||
bool? isTop = false;
|
||||
|
||||
ReplyItemModel.fromJson(Map<String, dynamic> json, upperMid,
|
||||
{isTopStatus = false}) {
|
||||
rpid = json['rpid'];
|
||||
oid = json['oid'];
|
||||
type = json['type'];
|
||||
mid = json['mid'];
|
||||
root = json['root'];
|
||||
parent = json['parent'];
|
||||
dialog = json['dialog'];
|
||||
count = json['count'];
|
||||
floor = json['floor'];
|
||||
state = json['state'];
|
||||
fansgrade = json['fansgrade'];
|
||||
attr = json['attr'];
|
||||
ctime = json['ctime'];
|
||||
rpidStr = json['rpid_str'];
|
||||
rootStr = json['root_str'];
|
||||
parentStr = json['parent_str'];
|
||||
like = json['like'];
|
||||
action = json['action'];
|
||||
member = ReplyMember.fromJson(json['member']);
|
||||
content = ReplyContent.fromJson(json['content']);
|
||||
replies = json['replies'] != null
|
||||
? json['replies']
|
||||
.map((item) => ReplyItemModel.fromJson(item, upperMid))
|
||||
.toList()
|
||||
: [];
|
||||
assist = json['assist'];
|
||||
upAction = UpAction.fromJson(json['up_action']);
|
||||
invisible = json['invisible'];
|
||||
replyControl = json['reply_control'] == null
|
||||
? null
|
||||
: ReplyControl.fromJson(json['reply_control']);
|
||||
isUp = upperMid.toString() == json['member']['mid'];
|
||||
isTop = isTopStatus;
|
||||
}
|
||||
}
|
||||
|
||||
class UpAction {
|
||||
UpAction({this.like, this.reply});
|
||||
|
||||
bool? like;
|
||||
bool? reply;
|
||||
|
||||
UpAction.fromJson(Map<String, dynamic> json) {
|
||||
like = json['like'];
|
||||
reply = json['reply'];
|
||||
}
|
||||
}
|
||||
|
||||
class ReplyControl {
|
||||
ReplyControl({
|
||||
this.upReply,
|
||||
this.isUpTop,
|
||||
this.upLike,
|
||||
this.isShow,
|
||||
this.entryText,
|
||||
this.titleText,
|
||||
this.time,
|
||||
this.location,
|
||||
});
|
||||
|
||||
bool? upReply;
|
||||
bool? isUpTop;
|
||||
bool? upLike;
|
||||
bool? isShow;
|
||||
String? entryText;
|
||||
String? titleText;
|
||||
String? time;
|
||||
String? location;
|
||||
|
||||
ReplyControl.fromJson(Map<String, dynamic> json) {
|
||||
upReply = json['up_reply'] ?? false;
|
||||
isUpTop = json['is_up_top'] ?? false;
|
||||
upLike = json['up_like'] ?? false;
|
||||
if (json['sub_reply_entry_text'] != null) {
|
||||
final RegExp regex = RegExp(r"\d+");
|
||||
final RegExpMatch match = regex.firstMatch(
|
||||
json['sub_reply_entry_text'] == null
|
||||
? ''
|
||||
: json['sub_reply_entry_text']!)!;
|
||||
isShow = int.parse(match.group(0)!) >= 3;
|
||||
} else {
|
||||
isShow = false;
|
||||
}
|
||||
|
||||
entryText = json['sub_reply_entry_text'];
|
||||
titleText = json['sub_reply_title_text'];
|
||||
time = json['time_desc'];
|
||||
location = json['location'];
|
||||
}
|
||||
}
|
||||
55
lib/models/video/reply/member.dart
Normal file
@ -0,0 +1,55 @@
|
||||
import 'dart:convert' as convert;
|
||||
|
||||
class ReplyMember {
|
||||
ReplyMember({
|
||||
this.mid,
|
||||
this.uname,
|
||||
this.sign,
|
||||
this.avatar,
|
||||
this.level,
|
||||
this.pendant,
|
||||
this.officialVerify,
|
||||
this.vip,
|
||||
this.fansDetail,
|
||||
});
|
||||
|
||||
String? mid;
|
||||
String? uname;
|
||||
String? sign;
|
||||
String? avatar;
|
||||
int? level;
|
||||
Pendant? pendant;
|
||||
Map? officialVerify;
|
||||
Map? vip;
|
||||
Map? fansDetail;
|
||||
|
||||
ReplyMember.fromJson(Map<String, dynamic> json) {
|
||||
mid = json['mid'];
|
||||
uname = json['uname'];
|
||||
sign = json['sign'];
|
||||
avatar = json['avatar'];
|
||||
level = json['level_info']['current_level'];
|
||||
pendant = Pendant.fromJson(json['pendant']);
|
||||
officialVerify = json['officia_vVerify'];
|
||||
vip = json['vip'];
|
||||
fansDetail = json['fans_detail'];
|
||||
}
|
||||
}
|
||||
|
||||
class Pendant {
|
||||
Pendant({
|
||||
this.pid,
|
||||
this.name,
|
||||
this.image,
|
||||
});
|
||||
|
||||
int? pid;
|
||||
String? name;
|
||||
String? image;
|
||||
|
||||
Pendant.fromJson(Map<String, dynamic> json) {
|
||||
pid = json['pid'];
|
||||
name = json['name'];
|
||||
image = json['image'];
|
||||
}
|
||||
}
|
||||
20
lib/models/video/reply/page.dart
Normal file
@ -0,0 +1,20 @@
|
||||
class ReplyPage {
|
||||
ReplyPage({
|
||||
this.num,
|
||||
this.size,
|
||||
this.count,
|
||||
this.acount,
|
||||
});
|
||||
|
||||
int? num;
|
||||
int? size;
|
||||
int? count;
|
||||
int? acount;
|
||||
|
||||
ReplyPage.fromJson(Map<String, dynamic> json) {
|
||||
num = json['num'];
|
||||
size = json['size'];
|
||||
count = json['count'];
|
||||
acount = json['acount'];
|
||||
}
|
||||
}
|
||||
1
lib/models/video/reply/top_replies.dart
Normal file
@ -0,0 +1 @@
|
||||
class ReplyTop {}
|
||||
18
lib/models/video/reply/upper.dart
Normal file
@ -0,0 +1,18 @@
|
||||
import 'item.dart';
|
||||
|
||||
class ReplyUpper {
|
||||
ReplyUpper({
|
||||
this.mid,
|
||||
this.top,
|
||||
});
|
||||
|
||||
int? mid;
|
||||
ReplyItemModel? top;
|
||||
|
||||
ReplyUpper.fromJson(Map<String, dynamic> json) {
|
||||
mid = json['mid'];
|
||||
top = json['top'] != null
|
||||
? ReplyItemModel.fromJson(json['top'], json['mid'])
|
||||
: null;
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:pilipala/http/reply.dart';
|
||||
import 'package:pilipala/models/video/reply/data.dart';
|
||||
|
||||
class VideoReplyController extends GetxController {
|
||||
// 视频aid
|
||||
@ -13,5 +14,9 @@ class VideoReplyController extends GetxController {
|
||||
|
||||
Future queryReplyList() async {
|
||||
var res = await ReplyHttp.replyList(oid: aid, pageNum: 1, type: 1);
|
||||
if (res['status']) {
|
||||
res['data'] = ReplyData.fromJson(res['data']);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:pilipala/common/skeleton/video_card_h.dart';
|
||||
import 'package:pilipala/common/widgets/http_error.dart';
|
||||
import 'package:pilipala/models/video/reply/item.dart';
|
||||
import 'controller.dart';
|
||||
import 'widgets/reply_item.dart';
|
||||
|
||||
class VideoReplyPanel extends StatefulWidget {
|
||||
const VideoReplyPanel({super.key});
|
||||
@ -7,11 +13,68 @@ class VideoReplyPanel extends StatefulWidget {
|
||||
State<VideoReplyPanel> createState() => _VideoReplyPanelState();
|
||||
}
|
||||
|
||||
class _VideoReplyPanelState extends State<VideoReplyPanel> {
|
||||
class _VideoReplyPanelState extends State<VideoReplyPanel>
|
||||
with AutomaticKeepAliveClientMixin {
|
||||
final VideoReplyController _videoReplyController =
|
||||
Get.put(VideoReplyController(), tag: Get.arguments['heroTag']);
|
||||
|
||||
// 添加页面缓存
|
||||
@override
|
||||
bool get wantKeepAlive => true;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const SliverToBoxAdapter(
|
||||
child: Text('评论'),
|
||||
return FutureBuilder(
|
||||
future: _videoReplyController.queryReplyList(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
if (snapshot.data['status']) {
|
||||
List<ReplyItemModel> replies = snapshot.data['data'].replies;
|
||||
// 添加置顶回复
|
||||
if (snapshot.data['data'].upper.top != null) {
|
||||
bool flag = false;
|
||||
for (var i = 0;
|
||||
i < snapshot.data['data'].topReplies.length;
|
||||
i++) {
|
||||
if (snapshot.data['data'].topReplies[i].rpid ==
|
||||
snapshot.data['data'].upper.top.rpid) {
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
if (!flag) {
|
||||
replies.insert(0, snapshot.data['data'].upper.top);
|
||||
}
|
||||
}
|
||||
|
||||
replies.insertAll(0, snapshot.data['data'].topReplies);
|
||||
// 请求成功
|
||||
return SliverList(
|
||||
delegate: SliverChildBuilderDelegate((context, index) {
|
||||
if (index == replies.length) {
|
||||
return SizedBox(height: MediaQuery.of(context).padding.bottom);
|
||||
} else {
|
||||
return ReplyItem(
|
||||
replyItem: replies[index],
|
||||
isUp:
|
||||
replies[index].mid == snapshot.data['data'].upper.mid);
|
||||
}
|
||||
}, childCount: replies.length + 1));
|
||||
} else {
|
||||
// 请求错误
|
||||
return HttpError(
|
||||
errMsg: snapshot.data['msg'],
|
||||
fn: () => setState(() {}),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// 骨架屏
|
||||
return SliverList(
|
||||
delegate: SliverChildBuilderDelegate((context, index) {
|
||||
return const VideoCardHSkeleton();
|
||||
}, childCount: 5),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
419
lib/pages/video/detail/reply/widgets/reply_item.dart
Normal file
@ -0,0 +1,419 @@
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||
import 'package:pilipala/models/video/reply/item.dart';
|
||||
import 'package:pilipala/utils/utils.dart';
|
||||
|
||||
class ReplyItem extends StatelessWidget {
|
||||
ReplyItem({super.key, this.replyItem, required this.isUp});
|
||||
ReplyItemModel? replyItem;
|
||||
bool isUp = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: () {},
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(12, 6, 8, 0),
|
||||
child: content(context),
|
||||
),
|
||||
Divider(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor.withOpacity(0.08),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget lfAvtar(context) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(top: 5),
|
||||
child: NetworkImgLayer(
|
||||
src: replyItem!.member!.avatar,
|
||||
width: 30,
|
||||
height: 30,
|
||||
type: 'avatar',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget content(context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
// 头像、昵称
|
||||
Row(
|
||||
// 两端对齐
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
GestureDetector(
|
||||
// onTap: () =>
|
||||
// Get.toNamed('/member/${reply.userName}', parameters: {
|
||||
// 'memberAvatar': reply.avatar,
|
||||
// 'heroTag': reply.userName + heroTag,
|
||||
// }),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
lfAvtar(context),
|
||||
const SizedBox(width: 12),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
replyItem!.member!.uname!,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleSmall!
|
||||
.copyWith(
|
||||
color: replyItem!.isUp!
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Theme.of(context).colorScheme.outline,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Image.asset(
|
||||
'assets/images/lv/lv${replyItem!.member!.level}.png',
|
||||
height: 13,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// title
|
||||
Container(
|
||||
margin: const EdgeInsets.only(top: 0, left: 45, right: 6),
|
||||
child: SelectableRegion(
|
||||
magnifierConfiguration: const TextMagnifierConfiguration(),
|
||||
focusNode: FocusNode(),
|
||||
selectionControls: MaterialTextSelectionControls(),
|
||||
child: Text.rich(
|
||||
style: const TextStyle(height: 1.65),
|
||||
TextSpan(
|
||||
children: [
|
||||
buildContent(context, replyItem!.content!),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// 操作区域
|
||||
bottonAction(context, replyItem!.replyControl),
|
||||
if (replyItem!.replies!.isNotEmpty) ...[
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 2, bottom: 12),
|
||||
child: ReplyItemRow(
|
||||
replies: replyItem!.replies,
|
||||
replyControl: replyItem!.replyControl,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// 感谢、回复、复制
|
||||
Widget bottonAction(context, replyControl) {
|
||||
var color = Theme.of(context).colorScheme.outline;
|
||||
return Row(
|
||||
children: [
|
||||
const SizedBox(width: 48),
|
||||
Text(
|
||||
Utils.dateFormat(replyItem!.ctime),
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.labelMedium!
|
||||
.copyWith(color: Theme.of(context).colorScheme.outline),
|
||||
),
|
||||
if (replyItem!.isTop!) ...[
|
||||
Text(
|
||||
' • 置顶',
|
||||
style: TextStyle(
|
||||
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
],
|
||||
if (replyControl!.isUpTop!) ...[
|
||||
Text(
|
||||
' • 超赞',
|
||||
style: TextStyle(
|
||||
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
// const SizedBox(width: 4),
|
||||
],
|
||||
const Spacer(),
|
||||
SizedBox(
|
||||
height: 35,
|
||||
child: TextButton(
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.thumb_up_alt_outlined,
|
||||
size: 16,
|
||||
color: color,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
replyItem!.like.toString(),
|
||||
style: TextStyle(
|
||||
color: color,
|
||||
fontSize:
|
||||
Theme.of(context).textTheme.labelSmall!.fontSize),
|
||||
),
|
||||
],
|
||||
),
|
||||
onPressed: () {},
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class ReplyItemRow extends StatelessWidget {
|
||||
ReplyItemRow({
|
||||
super.key,
|
||||
this.replies,
|
||||
this.replyControl,
|
||||
});
|
||||
List? replies;
|
||||
ReplyControl? replyControl;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
bool isShow = replyControl!.isShow!;
|
||||
int extraRow = replyControl != null && isShow ? 1 : 0;
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(left: 42, right: 4, top: 0),
|
||||
child: Material(
|
||||
color: Theme.of(context).colorScheme.onInverseSurface.withOpacity(0.7),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
animationDuration: Duration.zero,
|
||||
child: ListView.builder(
|
||||
padding: EdgeInsets.zero,
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: replies!.length + extraRow,
|
||||
itemBuilder: (context, index) {
|
||||
if (extraRow == 1 && index == replies!.length) {
|
||||
// 有楼中楼回复,在最后显示
|
||||
return InkWell(
|
||||
onTap: () {},
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 8, horizontal: 8),
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
style: TextStyle(
|
||||
fontSize:
|
||||
Theme.of(context).textTheme.labelMedium!.fontSize,
|
||||
),
|
||||
children: [
|
||||
if (replyControl!.upReply!)
|
||||
const TextSpan(text: 'up主等人 '),
|
||||
TextSpan(
|
||||
text: replyControl!.entryText!,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return InkWell(
|
||||
onTap: () {},
|
||||
child: Padding(
|
||||
padding: EdgeInsets.fromLTRB(8, index == 0 ? 8 : 4, 8, 4),
|
||||
child: Text.rich(
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 2,
|
||||
TextSpan(
|
||||
children: [
|
||||
if (replies![index].isUp)
|
||||
TextSpan(
|
||||
text: 'UP • ',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: Theme.of(context)
|
||||
.textTheme
|
||||
.labelMedium!
|
||||
.fontSize,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: replies![index].member.uname + ' ',
|
||||
style: TextStyle(
|
||||
fontSize: Theme.of(context)
|
||||
.textTheme
|
||||
.titleSmall!
|
||||
.fontSize,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () => {
|
||||
print('跳转至用户主页'),
|
||||
},
|
||||
),
|
||||
buildContent(context, replies![index].content),
|
||||
],
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
InlineSpan buildContent(BuildContext context, content) {
|
||||
if (content.emote.isEmpty &&
|
||||
content.atNameToMid.isEmpty &&
|
||||
content.jumpUrl.isEmpty &&
|
||||
content.pictures.isEmpty) {
|
||||
return TextSpan(text: content.message);
|
||||
}
|
||||
List<InlineSpan> spanChilds = [];
|
||||
// 匹配表情
|
||||
String matchEmote = content.message.splitMapJoin(
|
||||
RegExp(r"\[.*?\]"),
|
||||
onMatch: (Match match) {
|
||||
String matchStr = match[0]!;
|
||||
if (content.emote.isNotEmpty) {
|
||||
if (content.emote.keys.contains(matchStr)) {
|
||||
spanChilds.add(
|
||||
WidgetSpan(
|
||||
child: NetworkImgLayer(
|
||||
src: content.emote[matchStr]['url'],
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
spanChilds.add(TextSpan(text: matchStr));
|
||||
return matchStr;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
},
|
||||
onNonMatch: (String str) {
|
||||
// 匹配@用户
|
||||
String matchMember = str;
|
||||
if (content.atNameToMid.isNotEmpty) {
|
||||
matchMember = str.splitMapJoin(
|
||||
RegExp(r"@.*:"),
|
||||
onMatch: (Match match) {
|
||||
if (match[0] != null) {
|
||||
content.atNameToMid.forEach((key, value) {
|
||||
spanChilds.add(
|
||||
TextSpan(
|
||||
text: '@$key ',
|
||||
style: TextStyle(
|
||||
fontSize:
|
||||
Theme.of(context).textTheme.titleSmall!.fontSize,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () => {
|
||||
print('跳转至用户主页'),
|
||||
},
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
return '';
|
||||
},
|
||||
onNonMatch: (String str) {
|
||||
spanChilds.add(TextSpan(text: str));
|
||||
return str;
|
||||
},
|
||||
);
|
||||
} else {
|
||||
matchMember = str;
|
||||
}
|
||||
|
||||
// 匹配 jumpUrl
|
||||
String matchUrl = matchMember;
|
||||
if (content.jumpUrl.isNotEmpty) {
|
||||
List urlKeys = content.jumpUrl.keys.toList();
|
||||
matchUrl = matchMember.splitMapJoin(
|
||||
RegExp("(?:${urlKeys.join("|")})"),
|
||||
onMatch: (Match match) {
|
||||
String matchStr = match[0]!;
|
||||
// spanChilds.add(TextSpan(text: matchStr));
|
||||
spanChilds.add(
|
||||
TextSpan(
|
||||
text: content.jumpUrl[matchStr]['title'],
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () => {
|
||||
print('Url 点击'),
|
||||
},
|
||||
),
|
||||
);
|
||||
return '';
|
||||
},
|
||||
onNonMatch: (String str) {
|
||||
spanChilds.add(TextSpan(text: str));
|
||||
return str;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (content.atNameToMid.isEmpty && content.jumpUrl.isEmpty) {
|
||||
spanChilds.add(TextSpan(text: str));
|
||||
}
|
||||
return str;
|
||||
},
|
||||
);
|
||||
|
||||
// 图片渲染
|
||||
if (content.pictures.isNotEmpty) {
|
||||
spanChilds.add(
|
||||
const TextSpan(text: '\n'),
|
||||
);
|
||||
for (var i = 0; i < content.pictures.length; i++) {
|
||||
spanChilds.add(
|
||||
WidgetSpan(
|
||||
child: SizedBox(
|
||||
height: 180,
|
||||
child: NetworkImgLayer(
|
||||
src: content.pictures[i]['img_src'],
|
||||
width: 200,
|
||||
height: 200 *
|
||||
content.pictures[i]['img_height'] /
|
||||
content.pictures[i]['img_width'],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
// spanChilds.add(TextSpan(text: matchMember));
|
||||
return TextSpan(children: spanChilds);
|
||||
}
|
||||
140
pubspec.lock
@ -6,7 +6,7 @@ packages:
|
||||
description:
|
||||
name: args
|
||||
sha256: "4cab82a83ffef80b262ddedf47a0a8e56ee6fbf7fe21e6e768b02792034dd440"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
async:
|
||||
@ -14,7 +14,7 @@ packages:
|
||||
description:
|
||||
name: async
|
||||
sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.10.0"
|
||||
boolean_selector:
|
||||
@ -22,7 +22,7 @@ packages:
|
||||
description:
|
||||
name: boolean_selector
|
||||
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
cached_network_image:
|
||||
@ -30,7 +30,7 @@ packages:
|
||||
description:
|
||||
name: cached_network_image
|
||||
sha256: fd3d0dc1d451f9a252b32d95d3f0c3c487bc41a75eba2e6097cb0b9c71491b15
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.3"
|
||||
cached_network_image_platform_interface:
|
||||
@ -38,7 +38,7 @@ packages:
|
||||
description:
|
||||
name: cached_network_image_platform_interface
|
||||
sha256: bb2b8403b4ccdc60ef5f25c70dead1f3d32d24b9d6117cfc087f496b178594a7
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
cached_network_image_web:
|
||||
@ -46,7 +46,7 @@ packages:
|
||||
description:
|
||||
name: cached_network_image_web
|
||||
sha256: b8eb814ebfcb4dea049680f8c1ffb2df399e4d03bf7a352c775e26fa06e02fa0
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
characters:
|
||||
@ -54,7 +54,7 @@ packages:
|
||||
description:
|
||||
name: characters
|
||||
sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
clock:
|
||||
@ -62,7 +62,7 @@ packages:
|
||||
description:
|
||||
name: clock
|
||||
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
collection:
|
||||
@ -70,7 +70,7 @@ packages:
|
||||
description:
|
||||
name: collection
|
||||
sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.17.0"
|
||||
connectivity_plus:
|
||||
@ -78,7 +78,7 @@ packages:
|
||||
description:
|
||||
name: connectivity_plus
|
||||
sha256: d73575bb66216738db892f72ba67dc478bd3b5490fbbcf43644b57645eabc822
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.4"
|
||||
connectivity_plus_platform_interface:
|
||||
@ -86,7 +86,7 @@ packages:
|
||||
description:
|
||||
name: connectivity_plus_platform_interface
|
||||
sha256: cf1d1c28f4416f8c654d7dc3cd638ec586076255d407cef3ddbdaf178272a71a
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.4"
|
||||
cookie_jar:
|
||||
@ -94,7 +94,7 @@ packages:
|
||||
description:
|
||||
name: cookie_jar
|
||||
sha256: d1cc6516a190ba667941f722b6365d202caff3dacb38de24268b8d6ff1ec8a1d
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
crypto:
|
||||
@ -102,7 +102,7 @@ packages:
|
||||
description:
|
||||
name: crypto
|
||||
sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
cupertino_icons:
|
||||
@ -110,7 +110,7 @@ packages:
|
||||
description:
|
||||
name: cupertino_icons
|
||||
sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
dbus:
|
||||
@ -118,7 +118,7 @@ packages:
|
||||
description:
|
||||
name: dbus
|
||||
sha256: "6f07cba3f7b3448d42d015bfd3d53fe12e5b36da2423f23838efc1d5fb31a263"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.8"
|
||||
dio:
|
||||
@ -126,7 +126,7 @@ packages:
|
||||
description:
|
||||
name: dio
|
||||
sha256: "0894a098594263fe1caaba3520e3016d8a855caeb010a882273189cca10f11e9"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.1.1"
|
||||
dio_cookie_manager:
|
||||
@ -134,7 +134,7 @@ packages:
|
||||
description:
|
||||
name: dio_cookie_manager
|
||||
sha256: b45f11c2fcbccf39c5952ab68910b3a155486c4fa730ceb4ce867c4943169ea1
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
dio_http2_adapter:
|
||||
@ -142,7 +142,7 @@ packages:
|
||||
description:
|
||||
name: dio_http2_adapter
|
||||
sha256: b06a02faaff972c4809c4ada7a2f71f6c74ce21f0feee79b357f2a9590c049d4
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
dynamic_color:
|
||||
@ -150,7 +150,7 @@ packages:
|
||||
description:
|
||||
name: dynamic_color
|
||||
sha256: bbebb1b7ebed819e0ec83d4abdc2a8482d934f6a85289ffc1c6acf7589fa2aad
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.6.3"
|
||||
fake_async:
|
||||
@ -158,7 +158,7 @@ packages:
|
||||
description:
|
||||
name: fake_async
|
||||
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
ffi:
|
||||
@ -166,7 +166,7 @@ packages:
|
||||
description:
|
||||
name: ffi
|
||||
sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
file:
|
||||
@ -174,7 +174,7 @@ packages:
|
||||
description:
|
||||
name: file
|
||||
sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.4"
|
||||
flutter:
|
||||
@ -187,7 +187,7 @@ packages:
|
||||
description:
|
||||
name: flutter_blurhash
|
||||
sha256: "05001537bd3fac7644fa6558b09ec8c0a3f2eba78c0765f88912882b1331a5c6"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.0"
|
||||
flutter_cache_manager:
|
||||
@ -195,7 +195,7 @@ packages:
|
||||
description:
|
||||
name: flutter_cache_manager
|
||||
sha256: "32cd900555219333326a2d0653aaaf8671264c29befa65bbd9856d204a4c9fb3"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.3.0"
|
||||
flutter_lints:
|
||||
@ -203,7 +203,7 @@ packages:
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
flutter_test:
|
||||
@ -221,7 +221,7 @@ packages:
|
||||
description:
|
||||
name: get
|
||||
sha256: "2ba20a47c8f1f233bed775ba2dd0d3ac97b4cf32fc17731b3dfc672b06b0e92a"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.6.5"
|
||||
http:
|
||||
@ -229,7 +229,7 @@ packages:
|
||||
description:
|
||||
name: http
|
||||
sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.13.5"
|
||||
http2:
|
||||
@ -237,7 +237,7 @@ packages:
|
||||
description:
|
||||
name: http2
|
||||
sha256: "58805ebc6513eed3b98ee0a455a8357e61d187bf2e0fdc1e53120770f78de258"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
http_parser:
|
||||
@ -245,7 +245,7 @@ packages:
|
||||
description:
|
||||
name: http_parser
|
||||
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
js:
|
||||
@ -253,7 +253,7 @@ packages:
|
||||
description:
|
||||
name: js
|
||||
sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.5"
|
||||
lints:
|
||||
@ -261,7 +261,7 @@ packages:
|
||||
description:
|
||||
name: lints
|
||||
sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
matcher:
|
||||
@ -269,7 +269,7 @@ packages:
|
||||
description:
|
||||
name: matcher
|
||||
sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.12.13"
|
||||
material_color_utilities:
|
||||
@ -277,7 +277,7 @@ packages:
|
||||
description:
|
||||
name: material_color_utilities
|
||||
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.0"
|
||||
meta:
|
||||
@ -285,7 +285,7 @@ packages:
|
||||
description:
|
||||
name: meta
|
||||
sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.8.0"
|
||||
nm:
|
||||
@ -293,7 +293,7 @@ packages:
|
||||
description:
|
||||
name: nm
|
||||
sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.0"
|
||||
octo_image:
|
||||
@ -301,7 +301,7 @@ packages:
|
||||
description:
|
||||
name: octo_image
|
||||
sha256: "107f3ed1330006a3bea63615e81cf637433f5135a52466c7caa0e7152bca9143"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
path:
|
||||
@ -309,7 +309,7 @@ packages:
|
||||
description:
|
||||
name: path
|
||||
sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.8.2"
|
||||
path_provider:
|
||||
@ -317,7 +317,7 @@ packages:
|
||||
description:
|
||||
name: path_provider
|
||||
sha256: c7edf82217d4b2952b2129a61d3ad60f1075b9299e629e149a8d2e39c2e6aad4
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.14"
|
||||
path_provider_android:
|
||||
@ -325,7 +325,7 @@ packages:
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: da97262be945a72270513700a92b39dd2f4a54dad55d061687e2e37a6390366a
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.25"
|
||||
path_provider_foundation:
|
||||
@ -333,7 +333,7 @@ packages:
|
||||
description:
|
||||
name: path_provider_foundation
|
||||
sha256: ad4c4d011830462633f03eb34445a45345673dfd4faf1ab0b4735fbd93b19183
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.2"
|
||||
path_provider_linux:
|
||||
@ -341,7 +341,7 @@ packages:
|
||||
description:
|
||||
name: path_provider_linux
|
||||
sha256: "2ae08f2216225427e64ad224a24354221c2c7907e448e6e0e8b57b1eb9f10ad1"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.10"
|
||||
path_provider_platform_interface:
|
||||
@ -349,7 +349,7 @@ packages:
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.6"
|
||||
path_provider_windows:
|
||||
@ -357,7 +357,7 @@ packages:
|
||||
description:
|
||||
name: path_provider_windows
|
||||
sha256: f53720498d5a543f9607db4b0e997c4b5438884de25b0f73098cc2671a51b130
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.5"
|
||||
pedantic:
|
||||
@ -365,7 +365,7 @@ packages:
|
||||
description:
|
||||
name: pedantic
|
||||
sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.11.1"
|
||||
petitparser:
|
||||
@ -373,7 +373,7 @@ packages:
|
||||
description:
|
||||
name: petitparser
|
||||
sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.1.0"
|
||||
platform:
|
||||
@ -381,7 +381,7 @@ packages:
|
||||
description:
|
||||
name: platform
|
||||
sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
plugin_platform_interface:
|
||||
@ -389,7 +389,7 @@ packages:
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
process:
|
||||
@ -397,7 +397,7 @@ packages:
|
||||
description:
|
||||
name: process
|
||||
sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2.4"
|
||||
rxdart:
|
||||
@ -405,7 +405,7 @@ packages:
|
||||
description:
|
||||
name: rxdart
|
||||
sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.27.7"
|
||||
sky_engine:
|
||||
@ -418,31 +418,31 @@ packages:
|
||||
description:
|
||||
name: source_span
|
||||
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.1"
|
||||
sqflite:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqflite
|
||||
sha256: "500d6fec583d2c021f2d25a056d96654f910662c64f836cd2063167b8f1fa758"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
sha256: e7dfb6482d5d02b661d0b2399efa72b98909e5aa7b8336e1fb37e226264ade00
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.6"
|
||||
version: "2.2.7"
|
||||
sqflite_common:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqflite_common
|
||||
sha256: "963dad8c4aa2f814ce7d2d5b1da2f36f31bd1a439d8f27e3dc189bb9d26bc684"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
sha256: "220831bf0bd5333ff2445eee35ec131553b804e6b5d47a4a37ca6f5eb66e282c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.3"
|
||||
version: "2.4.4"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stack_trace
|
||||
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.11.0"
|
||||
stream_channel:
|
||||
@ -450,7 +450,7 @@ packages:
|
||||
description:
|
||||
name: stream_channel
|
||||
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
string_scanner:
|
||||
@ -458,23 +458,23 @@ packages:
|
||||
description:
|
||||
name: string_scanner
|
||||
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
synchronized:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: synchronized
|
||||
sha256: "33b31b6beb98100bf9add464a36a8dd03eb10c7a8cf15aeec535e9b054aaf04b"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
version: "3.1.0"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
test_api:
|
||||
@ -482,7 +482,7 @@ packages:
|
||||
description:
|
||||
name: test_api
|
||||
sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.16"
|
||||
typed_data:
|
||||
@ -490,7 +490,7 @@ packages:
|
||||
description:
|
||||
name: typed_data
|
||||
sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
uuid:
|
||||
@ -498,7 +498,7 @@ packages:
|
||||
description:
|
||||
name: uuid
|
||||
sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.7"
|
||||
vector_math:
|
||||
@ -506,7 +506,7 @@ packages:
|
||||
description:
|
||||
name: vector_math
|
||||
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
win32:
|
||||
@ -514,7 +514,7 @@ packages:
|
||||
description:
|
||||
name: win32
|
||||
sha256: a6f0236dbda0f63aa9a25ad1ff9a9d8a4eaaa5012da0dc59d21afdb1dc361ca4
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.4"
|
||||
xdg_directories:
|
||||
@ -522,7 +522,7 @@ packages:
|
||||
description:
|
||||
name: xdg_directories
|
||||
sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
xml:
|
||||
@ -530,7 +530,7 @@ packages:
|
||||
description:
|
||||
name: xml
|
||||
sha256: "979ee37d622dec6365e2efa4d906c37470995871fe9ae080d967e192d88286b5"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.2.2"
|
||||
sdks:
|
||||
|
||||
@ -76,6 +76,7 @@ flutter:
|
||||
# To add assets to your application, add an assets section, like this:
|
||||
assets:
|
||||
- assets/images/
|
||||
- assets/images/lv/
|
||||
# An image asset can refer to one or more resolution-specific "variants", see
|
||||
# https://flutter.dev/assets-and-images/#resolution-aware
|
||||
|
||||
|
||||