feat: 图文动态详情页&评论渲染
This commit is contained in:
33
lib/common/widgets/badge.dart
Normal file
33
lib/common/widgets/badge.dart
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
Widget pBadge(
|
||||||
|
text,
|
||||||
|
context,
|
||||||
|
double? top,
|
||||||
|
double? right,
|
||||||
|
double? bottom,
|
||||||
|
double? left, {
|
||||||
|
type = 'primary',
|
||||||
|
}) {
|
||||||
|
Color bgColor = Theme.of(context).colorScheme.primary;
|
||||||
|
Color color = Theme.of(context).colorScheme.onPrimary;
|
||||||
|
if (type == 'gray') {
|
||||||
|
bgColor = Colors.black54.withOpacity(0.4);
|
||||||
|
color = Colors.white;
|
||||||
|
}
|
||||||
|
return Positioned(
|
||||||
|
top: top,
|
||||||
|
left: left,
|
||||||
|
right: right,
|
||||||
|
bottom: bottom,
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 1, horizontal: 6),
|
||||||
|
decoration:
|
||||||
|
BoxDecoration(borderRadius: BorderRadius.circular(4), color: bgColor),
|
||||||
|
child: Text(
|
||||||
|
text,
|
||||||
|
style: TextStyle(fontSize: 11, color: color),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:pilipala/common/constants.dart';
|
import 'package:pilipala/common/constants.dart';
|
||||||
|
import 'package:pilipala/common/widgets/badge.dart';
|
||||||
import 'package:pilipala/common/widgets/stat/view.dart';
|
import 'package:pilipala/common/widgets/stat/view.dart';
|
||||||
import 'package:pilipala/http/search.dart';
|
import 'package:pilipala/http/search.dart';
|
||||||
import 'package:pilipala/utils/utils.dart';
|
import 'package:pilipala/utils/utils.dart';
|
||||||
@ -84,24 +85,13 @@ class VideoCardH extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
// Image.network( videoItem['pic'], width: double.infinity, height: double.infinity,),
|
// Image.network( videoItem['pic'], width: double.infinity, height: double.infinity,),
|
||||||
Positioned(
|
pBadge(Utils.timeFormat(videoItem.duration!),
|
||||||
right: 4,
|
context, null, 6.0, 6.0, null,
|
||||||
bottom: 4,
|
type: 'gray'),
|
||||||
child: Container(
|
if (videoItem.rcmdReason != null &&
|
||||||
padding: const EdgeInsets.symmetric(
|
videoItem.rcmdReason.content != '')
|
||||||
vertical: 1, horizontal: 6),
|
pBadge(videoItem.rcmdReason.content,
|
||||||
decoration: BoxDecoration(
|
context, 6.0, 6.0, null, null),
|
||||||
borderRadius:
|
|
||||||
BorderRadius.circular(4),
|
|
||||||
color:
|
|
||||||
Colors.black54.withOpacity(0.4)),
|
|
||||||
child: Text(
|
|
||||||
Utils.timeFormat(videoItem.duration!),
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 11, color: Colors.white),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -171,22 +161,22 @@ class VideoContent extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
if (videoItem.rcmdReason != null &&
|
// if (videoItem.rcmdReason != null &&
|
||||||
videoItem.rcmdReason.content != '')
|
// videoItem.rcmdReason.content != '')
|
||||||
Container(
|
// Container(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5),
|
// padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5),
|
||||||
decoration: BoxDecoration(
|
// decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(4),
|
// borderRadius: BorderRadius.circular(4),
|
||||||
border: Border.all(
|
// border: Border.all(
|
||||||
color: Theme.of(context).colorScheme.surfaceTint),
|
// color: Theme.of(context).colorScheme.surfaceTint),
|
||||||
),
|
// ),
|
||||||
child: Text(
|
// child: Text(
|
||||||
videoItem.rcmdReason.content,
|
// videoItem.rcmdReason.content,
|
||||||
style: TextStyle(
|
// style: TextStyle(
|
||||||
fontSize: 9,
|
// fontSize: 9,
|
||||||
color: Theme.of(context).colorScheme.surfaceTint),
|
// color: Theme.of(context).colorScheme.surfaceTint),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@ -98,6 +98,7 @@ class Api {
|
|||||||
static const String relationMod = '/x/relation/modify';
|
static const String relationMod = '/x/relation/modify';
|
||||||
|
|
||||||
// 评论列表
|
// 评论列表
|
||||||
|
// https://api.bilibili.com/x/v2/reply/main?csrf=6e22efc1a47225ea25f901f922b5cfdd&mode=3&oid=254175381&pagination_str=%7B%22offset%22:%22%22%7D&plat=1&seek_rpid=0&type=11
|
||||||
static const String replyList = '/x/v2/reply';
|
static const String replyList = '/x/v2/reply';
|
||||||
|
|
||||||
// 楼中楼
|
// 楼中楼
|
||||||
|
|||||||
@ -22,7 +22,7 @@ class DynamicsDataModel {
|
|||||||
// 单个动态
|
// 单个动态
|
||||||
class DynamicItemModel {
|
class DynamicItemModel {
|
||||||
DynamicItemModel({
|
DynamicItemModel({
|
||||||
// this.basic,
|
this.basic,
|
||||||
this.idStr,
|
this.idStr,
|
||||||
this.modules,
|
this.modules,
|
||||||
this.orig,
|
this.orig,
|
||||||
@ -30,7 +30,7 @@ class DynamicItemModel {
|
|||||||
this.visible,
|
this.visible,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Map? basic;
|
Map? basic;
|
||||||
String? idStr;
|
String? idStr;
|
||||||
ItemModulesModel? modules;
|
ItemModulesModel? modules;
|
||||||
ItemOrigModel? orig;
|
ItemOrigModel? orig;
|
||||||
@ -38,7 +38,7 @@ class DynamicItemModel {
|
|||||||
bool? visible;
|
bool? visible;
|
||||||
|
|
||||||
DynamicItemModel.fromJson(Map<String, dynamic> json) {
|
DynamicItemModel.fromJson(Map<String, dynamic> json) {
|
||||||
// basic = json['basic'];
|
basic = json['basic'];
|
||||||
idStr = json['id_str'];
|
idStr = json['id_str'];
|
||||||
modules = ItemModulesModel.fromJson(json['modules']);
|
modules = ItemModulesModel.fromJson(json['modules']);
|
||||||
orig = json['orig'] != null ? ItemOrigModel.fromJson(json['orig']) : null;
|
orig = json['orig'] != null ? ItemOrigModel.fromJson(json['orig']) : null;
|
||||||
@ -140,7 +140,7 @@ class ModuleAuthorModel {
|
|||||||
name = json['name'];
|
name = json['name'];
|
||||||
pubAction = json['pub_action'];
|
pubAction = json['pub_action'];
|
||||||
pubTime = json['pub_time'];
|
pubTime = json['pub_time'];
|
||||||
pubTs = json['pub_ts'];
|
pubTs = json['pub_ts'] == 0 ? null : json['pub_ts'];
|
||||||
type = json['type'];
|
type = json['type'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -158,7 +158,7 @@ class History {
|
|||||||
History.fromJson(Map<String, dynamic> json) {
|
History.fromJson(Map<String, dynamic> json) {
|
||||||
oid = json['oid'];
|
oid = json['oid'];
|
||||||
epid = json['epid'];
|
epid = json['epid'];
|
||||||
bvid = json['bvid'];
|
bvid = json['bvid'] == '' ? null : json['bvid'];
|
||||||
page = json['page'];
|
page = json['page'];
|
||||||
cid = json['cid'] == 0 ? null : json['cid'];
|
cid = json['cid'] == 0 ? null : json['cid'];
|
||||||
part = json['part'];
|
part = json['part'];
|
||||||
|
|||||||
@ -32,4 +32,32 @@ class DynamicsController extends GetxController {
|
|||||||
dynamicsTypeLabel.value = label;
|
dynamicsTypeLabel.value = label;
|
||||||
queryFollowDynamic();
|
queryFollowDynamic();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pushDetail(item, floor) {
|
||||||
|
switch (item!.type) {
|
||||||
|
case 'DYNAMIC_TYPE_FORWARD':
|
||||||
|
print('转发的动态');
|
||||||
|
Get.toNamed('/dynamicDetail',
|
||||||
|
arguments: {'item': item, 'floor': floor});
|
||||||
|
break;
|
||||||
|
case 'DYNAMIC_TYPE_DRAW':
|
||||||
|
Get.toNamed('/dynamicDetail',
|
||||||
|
arguments: {'item': item, 'floor': floor});
|
||||||
|
break;
|
||||||
|
case 'DYNAMIC_TYPE_AV':
|
||||||
|
print('视频');
|
||||||
|
break;
|
||||||
|
case 'DYNAMIC_TYPE_ARTICLE':
|
||||||
|
print('文章/专栏');
|
||||||
|
break;
|
||||||
|
case 'DYNAMIC_TYPE_PGC':
|
||||||
|
print('番剧');
|
||||||
|
break;
|
||||||
|
case 'DYNAMIC_TYPE_WORD':
|
||||||
|
print('纯文本');
|
||||||
|
Get.toNamed('/dynamicDetail',
|
||||||
|
arguments: {'item': item, 'floor': floor});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
80
lib/pages/dynamics/deatil/controller.dart
Normal file
80
lib/pages/dynamics/deatil/controller.dart
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:pilipala/http/reply.dart';
|
||||||
|
import 'package:pilipala/models/dynamics/result.dart';
|
||||||
|
import 'package:pilipala/models/video/reply/data.dart';
|
||||||
|
import 'package:pilipala/models/video/reply/item.dart';
|
||||||
|
|
||||||
|
class DynamicDetailController extends GetxController {
|
||||||
|
DynamicDetailController(this.oid, this.type);
|
||||||
|
int? oid;
|
||||||
|
int? type;
|
||||||
|
var item;
|
||||||
|
int? floor;
|
||||||
|
int currentPage = 0;
|
||||||
|
bool isLoadingMore = false;
|
||||||
|
RxString noMore = ''.obs;
|
||||||
|
RxList<ReplyItemModel> replyList = [ReplyItemModel()].obs;
|
||||||
|
RxInt acount = 0.obs;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
super.onInit();
|
||||||
|
item = Get.arguments['item'];
|
||||||
|
floor = Get.arguments['floor'];
|
||||||
|
if (floor == 1) {
|
||||||
|
acount.value =
|
||||||
|
int.parse(item!.modules!.moduleStat!.comment!.count ?? '0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future queryReplyList({reqType = 'init'}) async {
|
||||||
|
if (reqType == 'init') {
|
||||||
|
currentPage = 0;
|
||||||
|
}
|
||||||
|
var res = await ReplyHttp.replyList(
|
||||||
|
oid: oid!,
|
||||||
|
pageNum: currentPage + 1,
|
||||||
|
type: type!,
|
||||||
|
);
|
||||||
|
if (res['status']) {
|
||||||
|
res['data'] = ReplyData.fromJson(res['data']);
|
||||||
|
acount.value = res['data'].page.acount;
|
||||||
|
if (res['data'].replies.isNotEmpty) {
|
||||||
|
currentPage = currentPage + 1;
|
||||||
|
noMore.value = '加载中...';
|
||||||
|
if (replyList.isEmpty) {
|
||||||
|
noMore.value = '没有更多了';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (currentPage == 0) {
|
||||||
|
noMore.value = '还没有评论';
|
||||||
|
} else {
|
||||||
|
noMore.value = '没有更多了';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<ReplyItemModel> replies = res['data'].replies;
|
||||||
|
if (reqType == 'init') {
|
||||||
|
// 添加置顶回复
|
||||||
|
if (res['data'].upper.top != null) {
|
||||||
|
bool flag = false;
|
||||||
|
for (var i = 0; i < res['data'].topReplies.length; i++) {
|
||||||
|
if (res['data'].topReplies[i].rpid == res['data'].upper.top.rpid) {
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!flag) {
|
||||||
|
replies.insert(0, res['data'].upper.top);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
replies.insertAll(0, res['data'].topReplies);
|
||||||
|
replyList.value = replies;
|
||||||
|
} else {
|
||||||
|
replyList.addAll(replies);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isLoadingMore = false;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
4
lib/pages/dynamics/deatil/index.dart
Normal file
4
lib/pages/dynamics/deatil/index.dart
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
library dynamic_detail;
|
||||||
|
|
||||||
|
export './controller.dart';
|
||||||
|
export './view.dart';
|
||||||
248
lib/pages/dynamics/deatil/view.dart
Normal file
248
lib/pages/dynamics/deatil/view.dart
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:pilipala/common/skeleton/video_reply.dart';
|
||||||
|
import 'package:pilipala/common/widgets/http_error.dart';
|
||||||
|
import 'package:pilipala/pages/dynamics/deatil/index.dart';
|
||||||
|
import 'package:pilipala/pages/dynamics/widgets/author_panel.dart';
|
||||||
|
import 'package:pilipala/pages/video/detail/reply/widgets/reply_item.dart';
|
||||||
|
|
||||||
|
import '../widgets/dynamic_panel.dart';
|
||||||
|
|
||||||
|
class DynamicDetailPage extends StatefulWidget {
|
||||||
|
// const DynamicDetailPage({super.key});
|
||||||
|
const DynamicDetailPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DynamicDetailPage> createState() => _DynamicDetailPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DynamicDetailPageState extends State<DynamicDetailPage> {
|
||||||
|
late DynamicDetailController? _dynamicDetailController;
|
||||||
|
Future? _futureBuilderFuture;
|
||||||
|
late StreamController<bool> titleStreamC; // appBar title
|
||||||
|
final ScrollController scrollController = ScrollController();
|
||||||
|
bool _visibleTitle = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
int oid = 0;
|
||||||
|
int type = 0;
|
||||||
|
if (Get.arguments['floor'] == 1) {
|
||||||
|
oid = int.parse(Get.arguments['item'].basic!['comment_id_str']);
|
||||||
|
type = Get.arguments['item'].basic!['comment_type'];
|
||||||
|
} else {
|
||||||
|
oid = Get.arguments['item'].modules.moduleDynamic.major.draw.id;
|
||||||
|
type = 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
_dynamicDetailController = Get.put(DynamicDetailController(oid, type));
|
||||||
|
_futureBuilderFuture = _dynamicDetailController!.queryReplyList();
|
||||||
|
titleStreamC = StreamController<bool>();
|
||||||
|
scrollController.addListener(_listen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _listen() async {
|
||||||
|
if (scrollController.position.pixels >=
|
||||||
|
scrollController.position.maxScrollExtent - 300) {
|
||||||
|
if (!_dynamicDetailController!.isLoadingMore) {
|
||||||
|
_dynamicDetailController!.isLoadingMore = true;
|
||||||
|
await _dynamicDetailController!.queryReplyList(reqType: 'onLoad');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scrollController.offset > 55 && !_visibleTitle) {
|
||||||
|
_visibleTitle = true;
|
||||||
|
titleStreamC.add(true);
|
||||||
|
} else if (scrollController.offset <= 55 && _visibleTitle) {
|
||||||
|
_visibleTitle = false;
|
||||||
|
titleStreamC.add(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
elevation: 0,
|
||||||
|
scrolledUnderElevation: 0,
|
||||||
|
centerTitle: false,
|
||||||
|
titleSpacing: 0,
|
||||||
|
title: StreamBuilder(
|
||||||
|
stream: titleStreamC.stream,
|
||||||
|
initialData: false,
|
||||||
|
builder: (context, AsyncSnapshot snapshot) {
|
||||||
|
return AnimatedOpacity(
|
||||||
|
opacity: snapshot.data ? 1 : 0,
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
child: author(_dynamicDetailController!.item, context),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// actions: _detailModel != null ? appBarAction() : [],
|
||||||
|
),
|
||||||
|
body: RefreshIndicator(
|
||||||
|
onRefresh: () async {
|
||||||
|
await _dynamicDetailController!.queryReplyList();
|
||||||
|
},
|
||||||
|
child: CustomScrollView(
|
||||||
|
controller: scrollController,
|
||||||
|
slivers: [
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: DynamicPanel(
|
||||||
|
item: _dynamicDetailController!.item,
|
||||||
|
source: 'detail',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SliverPersistentHeader(
|
||||||
|
delegate: _MySliverPersistentHeaderDelegate(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).colorScheme.surface,
|
||||||
|
border: Border(
|
||||||
|
top: BorderSide(
|
||||||
|
width: 0.6,
|
||||||
|
color: Theme.of(context).dividerColor.withOpacity(0.05),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
height: 45,
|
||||||
|
padding: const EdgeInsets.only(left: 15, right: 12),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Obx(
|
||||||
|
() => AnimatedSwitcher(
|
||||||
|
duration: const Duration(milliseconds: 400),
|
||||||
|
transitionBuilder:
|
||||||
|
(Widget child, Animation<double> animation) {
|
||||||
|
return ScaleTransition(
|
||||||
|
scale: animation, child: child);
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
'${_dynamicDetailController!.acount.value}',
|
||||||
|
key: ValueKey<int>(
|
||||||
|
_dynamicDetailController!.acount.value),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Text('条回复'),
|
||||||
|
const Spacer(),
|
||||||
|
// TextButton.icon(
|
||||||
|
// onPressed: () {},
|
||||||
|
// icon: const Icon(
|
||||||
|
// Icons.subject_rounded,
|
||||||
|
// size: 15,
|
||||||
|
// ),
|
||||||
|
// style: TextButton.styleFrom(
|
||||||
|
// padding: const EdgeInsets.fromLTRB(12, 0, 12, 0),
|
||||||
|
// foregroundColor:
|
||||||
|
// Theme.of(context).colorScheme.outline,
|
||||||
|
// ),
|
||||||
|
// label: Text(
|
||||||
|
// '按时间',
|
||||||
|
// style: TextStyle(
|
||||||
|
// fontSize: Theme.of(context)
|
||||||
|
// .textTheme
|
||||||
|
// .titleSmall!
|
||||||
|
// .fontSize,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
pinned: true,
|
||||||
|
),
|
||||||
|
FutureBuilder(
|
||||||
|
future: _futureBuilderFuture,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
|
Map data = snapshot.data as Map;
|
||||||
|
if (snapshot.data['status']) {
|
||||||
|
// 请求成功
|
||||||
|
return Obx(
|
||||||
|
() => SliverList(
|
||||||
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
(context, index) {
|
||||||
|
if (index ==
|
||||||
|
_dynamicDetailController!.replyList.length) {
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
bottom:
|
||||||
|
MediaQuery.of(context).padding.bottom),
|
||||||
|
height:
|
||||||
|
MediaQuery.of(context).padding.bottom + 100,
|
||||||
|
child: Center(
|
||||||
|
child: Obx(() => Text(
|
||||||
|
_dynamicDetailController!.noMore.value)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return ReplyItem(
|
||||||
|
replyItem: _dynamicDetailController!
|
||||||
|
.replyList[index],
|
||||||
|
showReplyRow: true,
|
||||||
|
replyLevel: '1');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
childCount:
|
||||||
|
_dynamicDetailController!.replyList.length + 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// 请求错误
|
||||||
|
return HttpError(
|
||||||
|
errMsg: data['msg'],
|
||||||
|
fn: () => setState(() {}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 骨架屏
|
||||||
|
return SliverList(
|
||||||
|
delegate: SliverChildBuilderDelegate((context, index) {
|
||||||
|
return const VideoReplySkeleton();
|
||||||
|
}, childCount: 5),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MySliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate {
|
||||||
|
final double _minExtent = 45;
|
||||||
|
final double _maxExtent = 45;
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
_MySliverPersistentHeaderDelegate({required this.child});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(
|
||||||
|
BuildContext context, double shrinkOffset, bool overlapsContent) {
|
||||||
|
//创建child子组件
|
||||||
|
//shrinkOffset:child偏移值minExtent~maxExtent
|
||||||
|
//overlapsContent:SliverPersistentHeader覆盖其他子组件返回true,否则返回false
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
//SliverPersistentHeader最大高度
|
||||||
|
@override
|
||||||
|
double get maxExtent => _maxExtent;
|
||||||
|
|
||||||
|
//SliverPersistentHeader最小高度
|
||||||
|
@override
|
||||||
|
double get minExtent => _minExtent;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldRebuild(covariant _MySliverPersistentHeaderDelegate oldDelegate) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,10 +1,15 @@
|
|||||||
// 操作栏
|
// 操作栏
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/models/dynamics/result.dart';
|
import 'package:pilipala/models/dynamics/result.dart';
|
||||||
|
import 'package:pilipala/pages/dynamics/index.dart';
|
||||||
|
|
||||||
|
final DynamicsController _dynamicsController = Get.put(DynamicsController());
|
||||||
|
|
||||||
Widget action(item, context) {
|
Widget action(item, context) {
|
||||||
ModuleStatModel stat = item.modules.moduleStat;
|
ModuleStatModel stat = item.modules.moduleStat;
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
children: [
|
children: [
|
||||||
@ -14,14 +19,22 @@ Widget action(item, context) {
|
|||||||
FontAwesomeIcons.shareFromSquare,
|
FontAwesomeIcons.shareFromSquare,
|
||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.fromLTRB(15, 0, 15, 0),
|
||||||
|
foregroundColor: Theme.of(context).colorScheme.outline,
|
||||||
|
),
|
||||||
label: Text(stat.forward!.count ?? '转发'),
|
label: Text(stat.forward!.count ?? '转发'),
|
||||||
),
|
),
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
onPressed: () {},
|
onPressed: () => _dynamicsController.pushDetail(item, 1),
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
FontAwesomeIcons.comment,
|
FontAwesomeIcons.comment,
|
||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.fromLTRB(15, 0, 15, 0),
|
||||||
|
foregroundColor: Theme.of(context).colorScheme.outline,
|
||||||
|
),
|
||||||
label: Text(stat.comment!.count ?? '评论'),
|
label: Text(stat.comment!.count ?? '评论'),
|
||||||
),
|
),
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
@ -30,6 +43,10 @@ Widget action(item, context) {
|
|||||||
FontAwesomeIcons.thumbsUp,
|
FontAwesomeIcons.thumbsUp,
|
||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.fromLTRB(15, 0, 15, 0),
|
||||||
|
foregroundColor: Theme.of(context).colorScheme.outline,
|
||||||
|
),
|
||||||
label: Text(stat.like!.count ?? '点赞'),
|
label: Text(stat.like!.count ?? '点赞'),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|||||||
50
lib/pages/dynamics/widgets/author_panel.dart
Normal file
50
lib/pages/dynamics/widgets/author_panel.dart
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
|
|
||||||
|
Widget author(item, context) {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.fromLTRB(12, 12, 12, 8),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
print('个人主页');
|
||||||
|
},
|
||||||
|
child: NetworkImgLayer(
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
type: 'avatar',
|
||||||
|
src: item.modules.moduleAuthor.face,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
item.modules.moduleAuthor.name,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: Theme.of(context).textTheme.titleSmall!.fontSize,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
DefaultTextStyle.merge(
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.outline,
|
||||||
|
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Text(item.modules.moduleAuthor.pubTime),
|
||||||
|
if (item.modules.moduleAuthor.pubTime != '' &&
|
||||||
|
item.modules.moduleAuthor.pubAction != '')
|
||||||
|
const Text(' '),
|
||||||
|
Text(item.modules.moduleAuthor.pubAction),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
|||||||
|
|
||||||
import 'rich_node_panel.dart';
|
import 'rich_node_panel.dart';
|
||||||
|
|
||||||
Widget content(item, context) {
|
Widget content(item, context, source) {
|
||||||
TextStyle authorStyle =
|
TextStyle authorStyle =
|
||||||
TextStyle(color: Theme.of(context).colorScheme.primary);
|
TextStyle(color: Theme.of(context).colorScheme.primary);
|
||||||
return Container(
|
return Container(
|
||||||
@ -22,7 +22,7 @@ Widget content(item, context) {
|
|||||||
],
|
],
|
||||||
Text.rich(
|
Text.rich(
|
||||||
richNode(item, context),
|
richNode(item, context),
|
||||||
maxLines: 3,
|
maxLines: source == 'detail' ? 999 : 3,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -1,28 +1,26 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/common/constants.dart';
|
import 'package:pilipala/pages/dynamics/index.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
|
||||||
import 'package:pilipala/models/dynamics/result.dart';
|
|
||||||
import 'package:pilipala/utils/utils.dart';
|
|
||||||
|
|
||||||
import 'action_panel.dart';
|
import 'action_panel.dart';
|
||||||
import 'article_panel.dart';
|
import 'author_panel.dart';
|
||||||
import 'content_panel.dart';
|
import 'content_panel.dart';
|
||||||
import 'live_rcmd_panel.dart';
|
import 'forward_panel.dart';
|
||||||
import 'pic_panel.dart';
|
|
||||||
import 'rich_node_panel.dart';
|
|
||||||
|
|
||||||
class DynamicPanel extends StatelessWidget {
|
class DynamicPanel extends StatelessWidget {
|
||||||
DynamicItemModel? item;
|
var item;
|
||||||
DynamicPanel({this.item, Key? key});
|
String? source;
|
||||||
|
DynamicPanel({this.item, this.source, Key? key}) : super(key: key);
|
||||||
|
final DynamicsController _dynamicsController = Get.put(DynamicsController());
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
|
padding: source == 'detail'
|
||||||
|
? const EdgeInsets.only(bottom: 12)
|
||||||
|
: EdgeInsets.zero,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border(
|
border: Border(
|
||||||
top: BorderSide(
|
bottom: BorderSide(
|
||||||
width: 8,
|
width: 8,
|
||||||
color: Theme.of(context).dividerColor.withOpacity(0.05),
|
color: Theme.of(context).dividerColor.withOpacity(0.05),
|
||||||
),
|
),
|
||||||
@ -35,334 +33,20 @@ class DynamicPanel extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.circular(0),
|
borderRadius: BorderRadius.circular(0),
|
||||||
),
|
),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {},
|
onTap: () => _dynamicsController.pushDetail(item, 1),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
author(item, context),
|
author(item, context),
|
||||||
if (item!.modules!.moduleDynamic!.desc != null)
|
if (item!.modules!.moduleDynamic!.desc != null)
|
||||||
content(item, context),
|
content(item, context, source),
|
||||||
Padding(
|
forWard(item, context, _dynamicsController, source),
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
// padding: const EdgeInsets.only(left: 15, right: 15),
|
|
||||||
child: forWard(item, context),
|
|
||||||
),
|
|
||||||
action(item, context),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget author(item, context) {
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.fromLTRB(12, 12, 12, 8),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
NetworkImgLayer(
|
|
||||||
width: 40,
|
|
||||||
height: 40,
|
|
||||||
type: 'avatar',
|
|
||||||
src: item.modules.moduleAuthor.face,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(item.modules.moduleAuthor.name),
|
|
||||||
DefaultTextStyle.merge(
|
|
||||||
style: TextStyle(
|
|
||||||
color: Theme.of(context).colorScheme.outline,
|
|
||||||
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize,
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Text(item.modules.moduleAuthor.pubTime),
|
|
||||||
if (item.modules.moduleAuthor.pubTime != '' &&
|
|
||||||
item.modules.moduleAuthor.pubAction != '')
|
|
||||||
const Text(' '),
|
|
||||||
Text(item.modules.moduleAuthor.pubAction),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 转发
|
|
||||||
Widget forWard(item, context, {floor = 1}) {
|
|
||||||
TextStyle authorStyle =
|
|
||||||
TextStyle(color: Theme.of(context).colorScheme.primary);
|
|
||||||
switch (item.type) {
|
|
||||||
// 图文
|
|
||||||
case 'DYNAMIC_TYPE_DRAW':
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
if (floor == 2) ...[
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () {},
|
|
||||||
child: Text(
|
|
||||||
'@${item.modules.moduleAuthor.name}',
|
|
||||||
style: authorStyle,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 6),
|
|
||||||
Text(
|
|
||||||
Utils.dateFormat(item.modules.moduleAuthor.pubTs),
|
|
||||||
style: TextStyle(
|
|
||||||
color: Theme.of(context).colorScheme.outline,
|
|
||||||
fontSize:
|
|
||||||
Theme.of(context).textTheme.labelSmall!.fontSize),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
if (item.modules.moduleDynamic.topic != null) ...[
|
if (source == null) action(item, context),
|
||||||
Padding(
|
|
||||||
padding: floor == 2
|
|
||||||
? EdgeInsets.zero
|
|
||||||
: const EdgeInsets.only(left: 12, right: 12),
|
|
||||||
child: GestureDetector(
|
|
||||||
child: Text(
|
|
||||||
'#${item.modules.moduleDynamic.topic.name}',
|
|
||||||
style: authorStyle,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
Text.rich(
|
|
||||||
richNode(item, context),
|
|
||||||
maxLines: 4,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 4),
|
|
||||||
],
|
|
||||||
Padding(
|
|
||||||
padding: floor == 2
|
|
||||||
? EdgeInsets.zero
|
|
||||||
: const EdgeInsets.only(left: 12, right: 12),
|
|
||||||
child: picWidget(item, context),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
// 视频
|
|
||||||
case 'DYNAMIC_TYPE_AV':
|
|
||||||
return videoSeasonWidget(item, context, 'archive', floor: floor);
|
|
||||||
// 文章
|
|
||||||
case 'DYNAMIC_TYPE_ARTICLE':
|
|
||||||
return articlePanel(item, context, floor: floor);
|
|
||||||
// 转发
|
|
||||||
case 'DYNAMIC_TYPE_FORWARD':
|
|
||||||
return Container(
|
|
||||||
padding:
|
|
||||||
const EdgeInsets.only(left: 15, top: 10, right: 15, bottom: 8),
|
|
||||||
color: Theme.of(context).dividerColor.withOpacity(0.08),
|
|
||||||
child: forWard(item.orig, context, floor: 2),
|
|
||||||
);
|
|
||||||
// 直播
|
|
||||||
case 'DYNAMIC_TYPE_LIVE_RCMD':
|
|
||||||
return liveRcmdPanel(item, context, floor: floor);
|
|
||||||
// 合集
|
|
||||||
case 'DYNAMIC_TYPE_UGC_SEASON':
|
|
||||||
return videoSeasonWidget(item, context, 'ugcSeason');
|
|
||||||
case 'DYNAMIC_TYPE_WORD':
|
|
||||||
return floor == 2
|
|
||||||
? Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () {},
|
|
||||||
child: Text(
|
|
||||||
'@${item.modules.moduleAuthor.name}',
|
|
||||||
style: authorStyle,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 6),
|
|
||||||
Text(
|
|
||||||
Utils.dateFormat(item.modules.moduleAuthor.pubTs),
|
|
||||||
style: TextStyle(
|
|
||||||
color: Theme.of(context).colorScheme.outline,
|
|
||||||
fontSize: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.labelSmall!
|
|
||||||
.fontSize),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
Text(item.modules.moduleDynamic.desc.text)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
: const SizedBox(height: 0);
|
|
||||||
case 'DYNAMIC_TYPE_PGC':
|
|
||||||
return videoSeasonWidget(item, context, 'pgc', floor: floor);
|
|
||||||
case 'DYNAMIC_TYPE_NONE':
|
|
||||||
return Row(
|
|
||||||
children: [
|
|
||||||
const Icon(
|
|
||||||
FontAwesomeIcons.ghost,
|
|
||||||
size: 14,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 4),
|
|
||||||
Text(item.modules.moduleDynamic.major.none.tips)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
return const SizedBox(height: 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 视频or合集
|
|
||||||
Widget videoSeasonWidget(item, context, type, {floor = 1}) {
|
|
||||||
TextStyle authorStyle =
|
|
||||||
TextStyle(color: Theme.of(context).colorScheme.primary);
|
|
||||||
// type archive ugcSeason
|
|
||||||
// archive 视频/显示发布人
|
|
||||||
// ugcSeason 合集/不显示发布人
|
|
||||||
|
|
||||||
// floor 1 2
|
|
||||||
// 1 投稿视频 铺满 borderRadius 0
|
|
||||||
// 2 转发视频 铺满 borderRadius 6
|
|
||||||
Map<dynamic, dynamic> dynamicProperty = {
|
|
||||||
'ugcSeason': item.modules.moduleDynamic.major.ugcSeason,
|
|
||||||
'archive': item.modules.moduleDynamic.major.archive,
|
|
||||||
'pgc': item.modules.moduleDynamic.major.pgc
|
|
||||||
};
|
|
||||||
dynamic content = dynamicProperty[type];
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
if (floor == 2) ...[
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () {},
|
|
||||||
child: Text(
|
|
||||||
'@${item.modules.moduleAuthor.name}',
|
|
||||||
style: authorStyle,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 6),
|
|
||||||
Text(
|
|
||||||
Utils.dateFormat(item.modules.moduleAuthor.pubTs),
|
|
||||||
style: TextStyle(
|
|
||||||
color: Theme.of(context).colorScheme.outline,
|
|
||||||
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
|
||||||
],
|
|
||||||
// const SizedBox(height: 4),
|
|
||||||
if (item.modules.moduleDynamic.topic != null) ...[
|
|
||||||
Padding(
|
|
||||||
padding: floor == 2
|
|
||||||
? EdgeInsets.zero
|
|
||||||
: const EdgeInsets.only(left: 12, right: 12),
|
|
||||||
child: GestureDetector(
|
|
||||||
child: Text(
|
|
||||||
'#${item.modules.moduleDynamic.topic.name}',
|
|
||||||
style: authorStyle,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 6),
|
|
||||||
],
|
|
||||||
if (floor == 2 && item.modules.moduleDynamic.desc != null) ...[
|
|
||||||
Text.rich(richNode(item, context)),
|
|
||||||
const SizedBox(height: 6),
|
|
||||||
],
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () {},
|
|
||||||
child: LayoutBuilder(builder: (context, box) {
|
|
||||||
double width = box.maxWidth;
|
|
||||||
return Stack(
|
|
||||||
children: [
|
|
||||||
NetworkImgLayer(
|
|
||||||
type: floor == 1 ? 'emote' : null,
|
|
||||||
width: width,
|
|
||||||
height: width / StyleString.aspectRatio,
|
|
||||||
src: content.cover,
|
|
||||||
),
|
|
||||||
Positioned(
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
bottom: 0,
|
|
||||||
child: Container(
|
|
||||||
height: 80,
|
|
||||||
padding: const EdgeInsets.fromLTRB(12, 0, 10, 10),
|
|
||||||
clipBehavior: Clip.hardEdge,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
gradient: const LinearGradient(
|
|
||||||
begin: Alignment.topCenter,
|
|
||||||
end: Alignment.bottomCenter,
|
|
||||||
colors: <Color>[
|
|
||||||
Colors.transparent,
|
|
||||||
Colors.black54,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
borderRadius: floor == 1
|
|
||||||
? null
|
|
||||||
: const BorderRadius.all(Radius.circular(6))),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
DefaultTextStyle.merge(
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.labelMedium!
|
|
||||||
.fontSize,
|
|
||||||
color: Colors.white),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Text(content.durationText ?? ''),
|
|
||||||
if (content.durationText != null)
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Text(content.stat.play + '次围观'),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Text(content.stat.danmaku + '条弹幕')
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Image.asset(
|
|
||||||
'assets/images/play.png',
|
|
||||||
width: 60,
|
|
||||||
height: 60,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
),
|
||||||
Padding(
|
|
||||||
padding: floor == 1
|
|
||||||
? const EdgeInsets.only(left: 12, right: 12)
|
|
||||||
: EdgeInsets.zero,
|
|
||||||
child: Text(
|
|
||||||
content.title,
|
|
||||||
maxLines: 1,
|
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
139
lib/pages/dynamics/widgets/forward_panel.dart
Normal file
139
lib/pages/dynamics/widgets/forward_panel.dart
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
// 转发
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
|
import 'package:pilipala/utils/utils.dart';
|
||||||
|
|
||||||
|
import 'article_panel.dart';
|
||||||
|
import 'live_rcmd_panel.dart';
|
||||||
|
import 'pic_panel.dart';
|
||||||
|
import 'rich_node_panel.dart';
|
||||||
|
import 'video_panel.dart';
|
||||||
|
|
||||||
|
Widget forWard(item, context, ctr, source, {floor = 1}) {
|
||||||
|
TextStyle authorStyle =
|
||||||
|
TextStyle(color: Theme.of(context).colorScheme.primary);
|
||||||
|
switch (item.type) {
|
||||||
|
// 图文
|
||||||
|
case 'DYNAMIC_TYPE_DRAW':
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
if (floor == 2) ...[
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {},
|
||||||
|
child: Text(
|
||||||
|
'@${item.modules.moduleAuthor.name}',
|
||||||
|
style: authorStyle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
Text(
|
||||||
|
Utils.dateFormat(item.modules.moduleAuthor.pubTs),
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.outline,
|
||||||
|
fontSize:
|
||||||
|
Theme.of(context).textTheme.labelSmall!.fontSize),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 2),
|
||||||
|
if (item.modules.moduleDynamic.topic != null) ...[
|
||||||
|
Padding(
|
||||||
|
padding: floor == 2
|
||||||
|
? EdgeInsets.zero
|
||||||
|
: const EdgeInsets.only(left: 12, right: 12),
|
||||||
|
child: GestureDetector(
|
||||||
|
child: Text(
|
||||||
|
'#${item.modules.moduleDynamic.topic.name}',
|
||||||
|
style: authorStyle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
Text.rich(
|
||||||
|
richNode(item, context),
|
||||||
|
// 被转发状态(floor=2) 隐藏
|
||||||
|
maxLines: source == 'detail' && floor != 2 ? 999 : 4,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
],
|
||||||
|
Padding(
|
||||||
|
padding: floor == 2
|
||||||
|
? EdgeInsets.zero
|
||||||
|
: const EdgeInsets.only(left: 12, right: 12),
|
||||||
|
child: picWidget(item, context),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
// 视频
|
||||||
|
case 'DYNAMIC_TYPE_AV':
|
||||||
|
return videoSeasonWidget(item, context, 'archive', floor: floor);
|
||||||
|
// 文章
|
||||||
|
case 'DYNAMIC_TYPE_ARTICLE':
|
||||||
|
return articlePanel(item, context, floor: floor);
|
||||||
|
// 转发
|
||||||
|
case 'DYNAMIC_TYPE_FORWARD':
|
||||||
|
return InkWell(
|
||||||
|
onTap: () => ctr.pushDetail(item.orig, floor + 1),
|
||||||
|
child: Container(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.only(left: 15, top: 10, right: 15, bottom: 8),
|
||||||
|
color: Theme.of(context).dividerColor.withOpacity(0.08),
|
||||||
|
child: forWard(item.orig, context, ctr, source, floor: floor + 1),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
// 直播
|
||||||
|
case 'DYNAMIC_TYPE_LIVE_RCMD':
|
||||||
|
return liveRcmdPanel(item, context, floor: floor);
|
||||||
|
// 合集
|
||||||
|
case 'DYNAMIC_TYPE_UGC_SEASON':
|
||||||
|
return videoSeasonWidget(item, context, 'ugcSeason');
|
||||||
|
case 'DYNAMIC_TYPE_WORD':
|
||||||
|
return floor == 2
|
||||||
|
? Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {},
|
||||||
|
child: Text(
|
||||||
|
'@${item.modules.moduleAuthor.name}',
|
||||||
|
style: authorStyle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
Text(
|
||||||
|
Utils.dateFormat(item.modules.moduleAuthor.pubTs),
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.outline,
|
||||||
|
fontSize:
|
||||||
|
Theme.of(context).textTheme.labelSmall!.fontSize),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Text(item.modules.moduleDynamic.desc.text)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: const SizedBox(height: 0);
|
||||||
|
case 'DYNAMIC_TYPE_PGC':
|
||||||
|
return videoSeasonWidget(item, context, 'pgc', floor: floor);
|
||||||
|
case 'DYNAMIC_TYPE_NONE':
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
const Icon(
|
||||||
|
FontAwesomeIcons.ghost,
|
||||||
|
size: 14,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Text(item.modules.moduleDynamic.major.none.tips)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return const SizedBox(height: 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -26,14 +26,14 @@ Widget picWidget(item, context) {
|
|||||||
Get.toNamed('/preview',
|
Get.toNamed('/preview',
|
||||||
arguments: {'initialPage': i, 'imgList': picList});
|
arguments: {'initialPage': i, 'imgList': picList});
|
||||||
},
|
},
|
||||||
child: Hero(
|
// child: Hero(
|
||||||
tag: pictures[i].src,
|
// tag: pictures[i].src ?? pictures[i].url,
|
||||||
child: NetworkImgLayer(
|
child: NetworkImgLayer(
|
||||||
src: pictures[i].src ?? pictures[i].url,
|
src: pictures[i].src ?? pictures[i].url,
|
||||||
width: box.maxWidth,
|
width: box.maxWidth,
|
||||||
height: box.maxWidth,
|
height: box.maxWidth,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
// ),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -53,6 +53,10 @@ Widget picWidget(item, context) {
|
|||||||
if (len == 1) {
|
if (len == 1) {
|
||||||
aspectRatio = pictures.first.width / pictures.first.height;
|
aspectRatio = pictures.first.width / pictures.first.height;
|
||||||
height = pictures.first.height * maxWidth / pictures.first.width;
|
height = pictures.first.height * maxWidth / pictures.first.width;
|
||||||
|
if (pictures.first.width != 1920) {
|
||||||
|
crossCount = 2;
|
||||||
|
height = maxWidth / 2 / aspectRatio;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
aspectRatio = 1;
|
aspectRatio = 1;
|
||||||
height = maxWidth /
|
height = maxWidth /
|
||||||
@ -62,7 +66,6 @@ Widget picWidget(item, context) {
|
|||||||
: len ~/ crossCount + 1) +
|
: len ~/ crossCount + 1) +
|
||||||
6;
|
6;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.only(top: 4),
|
padding: const EdgeInsets.only(top: 4),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
|||||||
@ -8,7 +8,8 @@ InlineSpan richNode(item, context) {
|
|||||||
List<InlineSpan> spanChilds = [];
|
List<InlineSpan> spanChilds = [];
|
||||||
for (var i in item.modules.moduleDynamic.desc.richTextNodes) {
|
for (var i in item.modules.moduleDynamic.desc.richTextNodes) {
|
||||||
if (i.type == 'RICH_TEXT_NODE_TYPE_TEXT') {
|
if (i.type == 'RICH_TEXT_NODE_TYPE_TEXT') {
|
||||||
spanChilds.add(TextSpan(text: i.origText));
|
spanChilds.add(
|
||||||
|
TextSpan(text: i.origText, style: const TextStyle(height: 1.65)));
|
||||||
}
|
}
|
||||||
// @用户
|
// @用户
|
||||||
if (i.type == 'RICH_TEXT_NODE_TYPE_AT') {
|
if (i.type == 'RICH_TEXT_NODE_TYPE_AT') {
|
||||||
@ -100,6 +101,16 @@ InlineSpan richNode(item, context) {
|
|||||||
}
|
}
|
||||||
// 抽奖
|
// 抽奖
|
||||||
if (i.type == 'RICH_TEXT_NODE_TYPE_LOTTERY') {
|
if (i.type == 'RICH_TEXT_NODE_TYPE_LOTTERY') {
|
||||||
|
spanChilds.add(
|
||||||
|
WidgetSpan(
|
||||||
|
alignment: PlaceholderAlignment.middle,
|
||||||
|
child: Icon(
|
||||||
|
Icons.redeem_rounded,
|
||||||
|
size: 16,
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
spanChilds.add(
|
spanChilds.add(
|
||||||
WidgetSpan(
|
WidgetSpan(
|
||||||
alignment: PlaceholderAlignment.middle,
|
alignment: PlaceholderAlignment.middle,
|
||||||
@ -116,6 +127,16 @@ InlineSpan richNode(item, context) {
|
|||||||
|
|
||||||
/// TODO 商品
|
/// TODO 商品
|
||||||
if (i.type == 'RICH_TEXT_NODE_TYPE_GOODS') {
|
if (i.type == 'RICH_TEXT_NODE_TYPE_GOODS') {
|
||||||
|
spanChilds.add(
|
||||||
|
WidgetSpan(
|
||||||
|
alignment: PlaceholderAlignment.middle,
|
||||||
|
child: Icon(
|
||||||
|
Icons.shopping_bag_outlined,
|
||||||
|
size: 16,
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
spanChilds.add(
|
spanChilds.add(
|
||||||
WidgetSpan(
|
WidgetSpan(
|
||||||
alignment: PlaceholderAlignment.middle,
|
alignment: PlaceholderAlignment.middle,
|
||||||
|
|||||||
153
lib/pages/dynamics/widgets/video_panel.dart
Normal file
153
lib/pages/dynamics/widgets/video_panel.dart
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
// 视频or合集
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:pilipala/common/constants.dart';
|
||||||
|
import 'package:pilipala/common/widgets/badge.dart';
|
||||||
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
|
import 'package:pilipala/utils/utils.dart';
|
||||||
|
|
||||||
|
import 'rich_node_panel.dart';
|
||||||
|
|
||||||
|
Widget videoSeasonWidget(item, context, type, {floor = 1}) {
|
||||||
|
TextStyle authorStyle =
|
||||||
|
TextStyle(color: Theme.of(context).colorScheme.primary);
|
||||||
|
// type archive ugcSeason
|
||||||
|
// archive 视频/显示发布人
|
||||||
|
// ugcSeason 合集/不显示发布人
|
||||||
|
|
||||||
|
// floor 1 2
|
||||||
|
// 1 投稿视频 铺满 borderRadius 0
|
||||||
|
// 2 转发视频 铺满 borderRadius 6
|
||||||
|
Map<dynamic, dynamic> dynamicProperty = {
|
||||||
|
'ugcSeason': item.modules.moduleDynamic.major.ugcSeason,
|
||||||
|
'archive': item.modules.moduleDynamic.major.archive,
|
||||||
|
'pgc': item.modules.moduleDynamic.major.pgc
|
||||||
|
};
|
||||||
|
dynamic content = dynamicProperty[type];
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
if (floor == 2) ...[
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {},
|
||||||
|
child: Text(
|
||||||
|
item.modules.moduleAuthor.type == null
|
||||||
|
? '@${item.modules.moduleAuthor.name}'
|
||||||
|
: item.modules.moduleAuthor.name,
|
||||||
|
style: authorStyle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
Text(
|
||||||
|
item.modules.moduleAuthor.pubTs != null
|
||||||
|
? Utils.dateFormat(item.modules.moduleAuthor.pubTs)
|
||||||
|
: item.modules.moduleAuthor.pubTime,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.outline,
|
||||||
|
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 6),
|
||||||
|
],
|
||||||
|
// const SizedBox(height: 4),
|
||||||
|
if (item.modules.moduleDynamic.topic != null) ...[
|
||||||
|
Padding(
|
||||||
|
padding: floor == 2
|
||||||
|
? EdgeInsets.zero
|
||||||
|
: const EdgeInsets.only(left: 12, right: 12),
|
||||||
|
child: GestureDetector(
|
||||||
|
child: Text(
|
||||||
|
'#${item.modules.moduleDynamic.topic.name}',
|
||||||
|
style: authorStyle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 6),
|
||||||
|
],
|
||||||
|
if (floor == 2 && item.modules.moduleDynamic.desc != null) ...[
|
||||||
|
Text.rich(richNode(item, context)),
|
||||||
|
const SizedBox(height: 6),
|
||||||
|
],
|
||||||
|
LayoutBuilder(builder: (context, box) {
|
||||||
|
double width = box.maxWidth;
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
NetworkImgLayer(
|
||||||
|
type: floor == 1 ? 'emote' : null,
|
||||||
|
width: width,
|
||||||
|
height: width / StyleString.aspectRatio,
|
||||||
|
src: content.cover,
|
||||||
|
),
|
||||||
|
if (content.badge != null && type == 'pgc')
|
||||||
|
pBadge(content.badge['text'], context, 8.0, 10.0, null, null),
|
||||||
|
Positioned(
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
child: Container(
|
||||||
|
height: 80,
|
||||||
|
padding: const EdgeInsets.fromLTRB(12, 0, 10, 10),
|
||||||
|
clipBehavior: Clip.hardEdge,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: const LinearGradient(
|
||||||
|
begin: Alignment.topCenter,
|
||||||
|
end: Alignment.bottomCenter,
|
||||||
|
colors: <Color>[
|
||||||
|
Colors.transparent,
|
||||||
|
Colors.black54,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
borderRadius: floor == 1
|
||||||
|
? null
|
||||||
|
: const BorderRadius.all(Radius.circular(6))),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
DefaultTextStyle.merge(
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize:
|
||||||
|
Theme.of(context).textTheme.labelMedium!.fontSize,
|
||||||
|
color: Colors.white),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Text(content.durationText ?? ''),
|
||||||
|
if (content.durationText != null)
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Text(content.stat.play + '次围观'),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Text(content.stat.danmaku + '条弹幕')
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Image.asset(
|
||||||
|
'assets/images/play.png',
|
||||||
|
width: 60,
|
||||||
|
height: 60,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
const SizedBox(height: 6),
|
||||||
|
Padding(
|
||||||
|
padding: floor == 1
|
||||||
|
? const EdgeInsets.only(left: 12, right: 12)
|
||||||
|
: EdgeInsets.zero,
|
||||||
|
child: Text(
|
||||||
|
content.title,
|
||||||
|
maxLines: 1,
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/common/constants.dart';
|
import 'package:pilipala/common/constants.dart';
|
||||||
|
import 'package:pilipala/common/widgets/badge.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
import 'package:pilipala/http/search.dart';
|
import 'package:pilipala/http/search.dart';
|
||||||
import 'package:pilipala/models/common/business_type.dart';
|
import 'package:pilipala/models/common/business_type.dart';
|
||||||
@ -14,13 +15,15 @@ class HistoryItem extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
int aid = videoItem.history.oid;
|
int aid = videoItem.history.oid;
|
||||||
String bvid = videoItem.history.bvid;
|
String bvid = videoItem.history.bvid ?? IdUtils.av2bv(aid);
|
||||||
String heroTag = Utils.makeHeroTag(aid);
|
String heroTag = Utils.makeHeroTag(aid);
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
int cid = videoItem.history.cid ??
|
int cid = videoItem.history.cid ??
|
||||||
|
videoItem.history.oid ??
|
||||||
await SearchHttp.ab2c(aid: aid, bvid: bvid);
|
await SearchHttp.ab2c(aid: aid, bvid: bvid);
|
||||||
await Future.delayed(const Duration(milliseconds: 200));
|
await Future.delayed(const Duration(milliseconds: 200));
|
||||||
|
print(videoItem.history.business);
|
||||||
if (videoItem.history.business.contains('article')) {
|
if (videoItem.history.business.contains('article')) {
|
||||||
Get.toNamed(
|
Get.toNamed(
|
||||||
'/webview',
|
'/webview',
|
||||||
@ -75,71 +78,23 @@ class HistoryItem extends StatelessWidget {
|
|||||||
if (!BusinessType
|
if (!BusinessType
|
||||||
.hiddenDurationType.hiddenDurationType
|
.hiddenDurationType.hiddenDurationType
|
||||||
.contains(videoItem.history.business))
|
.contains(videoItem.history.business))
|
||||||
Positioned(
|
pBadge(
|
||||||
right: 4,
|
videoItem.progress == -1
|
||||||
bottom: 4,
|
? '已看完'
|
||||||
child: Container(
|
: '${Utils.timeFormat(videoItem.progress!)}/${Utils.timeFormat(videoItem.duration!)}',
|
||||||
padding: const EdgeInsets.symmetric(
|
context,
|
||||||
vertical: 1, horizontal: 6),
|
null,
|
||||||
decoration: BoxDecoration(
|
6.0,
|
||||||
borderRadius:
|
6.0,
|
||||||
BorderRadius.circular(4),
|
null,
|
||||||
color:
|
type: 'gray'),
|
||||||
Colors.black54.withOpacity(0.4)),
|
|
||||||
child: Text(
|
|
||||||
videoItem.progress == -1
|
|
||||||
? '已看完'
|
|
||||||
: '${Utils.timeFormat(videoItem.progress!)}/${Utils.timeFormat(videoItem.duration!)}',
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 11, color: Colors.white),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// 右上角
|
// 右上角
|
||||||
if (BusinessType.showBadge.showBadge
|
if (BusinessType.showBadge.showBadge
|
||||||
.contains(videoItem.history.business))
|
.contains(videoItem.history.business) ||
|
||||||
Positioned(
|
videoItem.history.business ==
|
||||||
right: 4,
|
BusinessType.live.type)
|
||||||
top: 4,
|
pBadge(videoItem.badge, context, 6.0, 6.0,
|
||||||
child: Container(
|
null, null),
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
vertical: 1, horizontal: 6),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius:
|
|
||||||
BorderRadius.circular(4),
|
|
||||||
color: Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.primaryContainer),
|
|
||||||
child: Text(
|
|
||||||
videoItem.badge,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 11,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.primary),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (videoItem.history.business ==
|
|
||||||
BusinessType.live.type)
|
|
||||||
Positioned(
|
|
||||||
right: 4,
|
|
||||||
top: 4,
|
|
||||||
child: Container(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
vertical: 1, horizontal: 6),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius:
|
|
||||||
BorderRadius.circular(4),
|
|
||||||
color:
|
|
||||||
Colors.black54.withOpacity(0.4)),
|
|
||||||
child: Text(
|
|
||||||
videoItem.badge,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 11, color: Colors.white),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:pilipala/common/widgets/badge.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
import 'package:pilipala/http/search.dart';
|
import 'package:pilipala/http/search.dart';
|
||||||
import 'package:pilipala/models/bangumi/info.dart';
|
import 'package:pilipala/models/bangumi/info.dart';
|
||||||
@ -33,7 +34,8 @@ Widget searchMbangumiPanel(BuildContext context, ctr, list) {
|
|||||||
height: 148,
|
height: 148,
|
||||||
src: i.cover,
|
src: i.cover,
|
||||||
),
|
),
|
||||||
Positioned(top: 6, right: 4, child: UpTag(type: i.mediaType))
|
pBadge(i.mediaType == 1 ? '番剧' : '国创', context, 6.0, 4.0,
|
||||||
|
null, null)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
@ -126,28 +128,3 @@ Widget searchMbangumiPanel(BuildContext context, ctr, list) {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class UpTag extends StatelessWidget {
|
|
||||||
int? type;
|
|
||||||
UpTag({super.key, this.type = 4});
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
Color primary = Theme.of(context).colorScheme.primary;
|
|
||||||
return Container(
|
|
||||||
width: 24,
|
|
||||||
height: 16,
|
|
||||||
decoration:
|
|
||||||
BoxDecoration(borderRadius: BorderRadius.circular(3), color: primary),
|
|
||||||
margin: const EdgeInsets.only(right: 4),
|
|
||||||
child: Center(
|
|
||||||
child: Text(
|
|
||||||
type == 1 ? '番剧' : '国创',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 9,
|
|
||||||
color: Theme.of(context).colorScheme.onPrimary,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/pages/dynamics/view.dart';
|
import 'package:pilipala/pages/dynamics/deatil/index.dart';
|
||||||
|
import 'package:pilipala/pages/dynamics/index.dart';
|
||||||
import 'package:pilipala/pages/fav/index.dart';
|
import 'package:pilipala/pages/fav/index.dart';
|
||||||
import 'package:pilipala/pages/favDetail/index.dart';
|
import 'package:pilipala/pages/favDetail/index.dart';
|
||||||
import 'package:pilipala/pages/history/index.dart';
|
import 'package:pilipala/pages/history/index.dart';
|
||||||
@ -8,13 +9,12 @@ import 'package:pilipala/pages/hot/index.dart';
|
|||||||
import 'package:pilipala/pages/later/index.dart';
|
import 'package:pilipala/pages/later/index.dart';
|
||||||
import 'package:pilipala/pages/preview/index.dart';
|
import 'package:pilipala/pages/preview/index.dart';
|
||||||
import 'package:pilipala/pages/search/index.dart';
|
import 'package:pilipala/pages/search/index.dart';
|
||||||
|
import 'package:pilipala/pages/searchResult/index.dart';
|
||||||
import 'package:pilipala/pages/video/detail/index.dart';
|
import 'package:pilipala/pages/video/detail/index.dart';
|
||||||
import 'package:pilipala/pages/webview/index.dart';
|
import 'package:pilipala/pages/webview/index.dart';
|
||||||
import 'package:pilipala/pages/setting/index.dart';
|
import 'package:pilipala/pages/setting/index.dart';
|
||||||
import 'package:pilipala/pages/media/index.dart';
|
import 'package:pilipala/pages/media/index.dart';
|
||||||
|
|
||||||
import '../pages/searchResult/index.dart';
|
|
||||||
|
|
||||||
class Routes {
|
class Routes {
|
||||||
static final List<GetPage> getPages = [
|
static final List<GetPage> getPages = [
|
||||||
// 首页(推荐)
|
// 首页(推荐)
|
||||||
@ -49,7 +49,9 @@ class Routes {
|
|||||||
GetPage(name: '/search', page: () => const SearchPage()),
|
GetPage(name: '/search', page: () => const SearchPage()),
|
||||||
// 搜索结果
|
// 搜索结果
|
||||||
GetPage(name: '/searchResult', page: () => const SearchResultPage()),
|
GetPage(name: '/searchResult', page: () => const SearchResultPage()),
|
||||||
//
|
// 动态
|
||||||
GetPage(name: '/dynamics', page: () => const DynamicsPage())
|
GetPage(name: '/dynamics', page: () => const DynamicsPage()),
|
||||||
|
// 动态详情
|
||||||
|
GetPage(name: '/dynamicDetail', page: () => const DynamicDetailPage())
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user