feat: 新增动态页面
This commit is contained in:
BIN
assets/images/play.png
Normal file
BIN
assets/images/play.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
@ -135,6 +135,8 @@ class Api {
|
|||||||
// https://api.bilibili.com/x/polymer/web-dynamic/v1/portal
|
// https://api.bilibili.com/x/polymer/web-dynamic/v1/portal
|
||||||
|
|
||||||
// 关注的up动态
|
// 关注的up动态
|
||||||
|
// https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all
|
||||||
|
static const String followDynamic = '/x/polymer/web-dynamic/v1/feed/all';
|
||||||
|
|
||||||
// 获取稍后再看
|
// 获取稍后再看
|
||||||
static const String seeYouLater = '/x/v2/history/toview';
|
static const String seeYouLater = '/x/v2/history/toview';
|
||||||
|
29
lib/http/dynamics.dart
Normal file
29
lib/http/dynamics.dart
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import 'package:pilipala/http/index.dart';
|
||||||
|
import 'package:pilipala/models/dynamics/result.dart';
|
||||||
|
|
||||||
|
class DynamicsHttp {
|
||||||
|
static Future followDynamic({
|
||||||
|
String? type,
|
||||||
|
int? page,
|
||||||
|
String? offset,
|
||||||
|
}) async {
|
||||||
|
var res = await Request().get(Api.followDynamic, data: {
|
||||||
|
'type': type ?? 'all',
|
||||||
|
'page': page ?? 1,
|
||||||
|
'offest': page == 1 ? '' : offset,
|
||||||
|
'features': 'itemOpusStyle'
|
||||||
|
});
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return {
|
||||||
|
'status': true,
|
||||||
|
'data': DynamicsDataModel.fromJson(res.data['data']),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
'status': false,
|
||||||
|
'data': [],
|
||||||
|
'msg': '请求错误 🙅',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
415
lib/models/dynamics/result.dart
Normal file
415
lib/models/dynamics/result.dart
Normal file
@ -0,0 +1,415 @@
|
|||||||
|
class DynamicsDataModel {
|
||||||
|
DynamicsDataModel({
|
||||||
|
this.hasMore,
|
||||||
|
this.items,
|
||||||
|
this.offset,
|
||||||
|
});
|
||||||
|
bool? hasMore;
|
||||||
|
List<DynamicItemModel>? items;
|
||||||
|
String? offset;
|
||||||
|
|
||||||
|
DynamicsDataModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
hasMore = json['has_more'];
|
||||||
|
items = json['items']
|
||||||
|
.map<DynamicItemModel>((e) => DynamicItemModel.fromJson(e))
|
||||||
|
.toList();
|
||||||
|
offset = json['offset'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单个动态
|
||||||
|
class DynamicItemModel {
|
||||||
|
DynamicItemModel({
|
||||||
|
// this.basic,
|
||||||
|
this.idStr,
|
||||||
|
this.modules,
|
||||||
|
this.orig,
|
||||||
|
this.type,
|
||||||
|
this.visible,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Map? basic;
|
||||||
|
String? idStr;
|
||||||
|
ItemModulesModel? modules;
|
||||||
|
ItemOrigModel? orig;
|
||||||
|
String? type;
|
||||||
|
bool? visible;
|
||||||
|
|
||||||
|
DynamicItemModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
// basic = json['basic'];
|
||||||
|
idStr = json['id_str'];
|
||||||
|
modules = ItemModulesModel.fromJson(json['modules']);
|
||||||
|
orig = json['orig'] != null ? ItemOrigModel.fromJson(json['orig']) : null;
|
||||||
|
type = json['type'];
|
||||||
|
visible = json['visible'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ItemOrigModel {
|
||||||
|
ItemOrigModel({
|
||||||
|
this.basic,
|
||||||
|
this.isStr,
|
||||||
|
this.modules,
|
||||||
|
this.type,
|
||||||
|
this.visible,
|
||||||
|
});
|
||||||
|
|
||||||
|
Map? basic;
|
||||||
|
String? isStr;
|
||||||
|
ItemModulesModel? modules;
|
||||||
|
String? type;
|
||||||
|
bool? visible;
|
||||||
|
|
||||||
|
ItemOrigModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
basic = json['basic'];
|
||||||
|
isStr = json['is_str'];
|
||||||
|
modules = ItemModulesModel.fromJson(json['modules']);
|
||||||
|
type = json['type'];
|
||||||
|
visible = json['visible'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单个动态详情
|
||||||
|
class ItemModulesModel {
|
||||||
|
ItemModulesModel({
|
||||||
|
this.moduleAuthor,
|
||||||
|
this.moduleDynamic,
|
||||||
|
// this.moduleInter,
|
||||||
|
this.moduleStat,
|
||||||
|
});
|
||||||
|
|
||||||
|
ModuleAuthorModel? moduleAuthor;
|
||||||
|
ModuleDynamicModel? moduleDynamic;
|
||||||
|
// ModuleInterModel? moduleInter;
|
||||||
|
ModuleStatModel? moduleStat;
|
||||||
|
|
||||||
|
ItemModulesModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
moduleAuthor = json['module_author'] != null
|
||||||
|
? ModuleAuthorModel.fromJson(json['module_author'])
|
||||||
|
: null;
|
||||||
|
moduleDynamic = json['module_dynamic'] != null
|
||||||
|
? ModuleDynamicModel.fromJson(json['module_dynamic'])
|
||||||
|
: null;
|
||||||
|
// moduleInter = ModuleInterModel.fromJson(json['module_interaction']);
|
||||||
|
moduleStat = json['module_stat'] != null
|
||||||
|
? ModuleStatModel.fromJson(json['module_stat'])
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单个动态详情 - 作者信息
|
||||||
|
class ModuleAuthorModel {
|
||||||
|
ModuleAuthorModel({
|
||||||
|
// this.avatar,
|
||||||
|
// this.decorate,
|
||||||
|
this.face,
|
||||||
|
this.following,
|
||||||
|
this.jumpUrl,
|
||||||
|
this.label,
|
||||||
|
this.mid,
|
||||||
|
this.name,
|
||||||
|
// this.officialVerify,
|
||||||
|
// this.pandant,
|
||||||
|
this.pubAction,
|
||||||
|
// this.pubLocationText,
|
||||||
|
this.pubTime,
|
||||||
|
this.pubTs,
|
||||||
|
this.type,
|
||||||
|
// this.vip,
|
||||||
|
});
|
||||||
|
|
||||||
|
String? face;
|
||||||
|
bool? following;
|
||||||
|
String? jumpUrl;
|
||||||
|
String? label;
|
||||||
|
int? mid;
|
||||||
|
String? name;
|
||||||
|
String? pubAction;
|
||||||
|
String? pubTime;
|
||||||
|
int? pubTs;
|
||||||
|
String? type;
|
||||||
|
|
||||||
|
ModuleAuthorModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
face = json['face'];
|
||||||
|
following = json['following'];
|
||||||
|
jumpUrl = json['jump_url'];
|
||||||
|
label = json['label'];
|
||||||
|
mid = json['mid'];
|
||||||
|
name = json['name'];
|
||||||
|
pubAction = json['pub_action'];
|
||||||
|
pubTime = json['pub_time'];
|
||||||
|
pubTs = json['pub_ts'];
|
||||||
|
type = json['type'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单个动态详情 - 动态信息
|
||||||
|
class ModuleDynamicModel {
|
||||||
|
ModuleDynamicModel({
|
||||||
|
// this.additional,
|
||||||
|
this.desc,
|
||||||
|
this.major,
|
||||||
|
this.topic,
|
||||||
|
});
|
||||||
|
|
||||||
|
String? additional;
|
||||||
|
DynamicDescModel? desc;
|
||||||
|
DynamicMajorModel? major;
|
||||||
|
Map? topic;
|
||||||
|
|
||||||
|
ModuleDynamicModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
desc =
|
||||||
|
json['desc'] != null ? DynamicDescModel.fromJson(json['desc']) : null;
|
||||||
|
if (json['major'] != null) {
|
||||||
|
major = DynamicMajorModel.fromJson(json['major']);
|
||||||
|
}
|
||||||
|
topic = json['topic'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单个动态详情 - 评论?信息
|
||||||
|
// class ModuleInterModel {
|
||||||
|
// ModuleInterModel({
|
||||||
|
|
||||||
|
// });
|
||||||
|
|
||||||
|
// ModuleInterModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
class DynamicDescModel {
|
||||||
|
DynamicDescModel({
|
||||||
|
this.richTextNode,
|
||||||
|
this.text,
|
||||||
|
});
|
||||||
|
|
||||||
|
List? richTextNode;
|
||||||
|
String? text;
|
||||||
|
|
||||||
|
DynamicDescModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
richTextNode = json['rich_text_nodes'];
|
||||||
|
text = json['text'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
class DynamicMajorModel {
|
||||||
|
DynamicMajorModel({
|
||||||
|
this.archive,
|
||||||
|
this.draw,
|
||||||
|
this.type,
|
||||||
|
});
|
||||||
|
|
||||||
|
DynamicArchiveModel? archive;
|
||||||
|
DynamicDrawModel? draw;
|
||||||
|
DynamicOpusModel? opus;
|
||||||
|
// MAJOR_TYPE_DRAW 图片
|
||||||
|
// MAJOR_TYPE_ARCHIVE 视频
|
||||||
|
// MAJOR_TYPE_OPUS 图文/文章
|
||||||
|
String? type;
|
||||||
|
|
||||||
|
DynamicMajorModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
archive = json['archive'] != null
|
||||||
|
? DynamicArchiveModel.fromJson(json['archive'])
|
||||||
|
: null;
|
||||||
|
draw =
|
||||||
|
json['draw'] != null ? DynamicDrawModel.fromJson(json['draw']) : null;
|
||||||
|
opus =
|
||||||
|
json['opus'] != null ? DynamicOpusModel.fromJson(json['opus']) : null;
|
||||||
|
type = json['type'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DynamicArchiveModel {
|
||||||
|
DynamicArchiveModel({
|
||||||
|
this.aid,
|
||||||
|
this.badge,
|
||||||
|
this.bvid,
|
||||||
|
this.cover,
|
||||||
|
this.desc,
|
||||||
|
this.disablePreview,
|
||||||
|
this.durationText,
|
||||||
|
this.jumpUrl,
|
||||||
|
this.stat,
|
||||||
|
this.title,
|
||||||
|
this.type,
|
||||||
|
});
|
||||||
|
|
||||||
|
String? aid;
|
||||||
|
Map? badge;
|
||||||
|
String? bvid;
|
||||||
|
String? cover;
|
||||||
|
String? desc;
|
||||||
|
int? disablePreview;
|
||||||
|
String? durationText;
|
||||||
|
String? jumpUrl;
|
||||||
|
Stat? stat;
|
||||||
|
String? title;
|
||||||
|
int? type;
|
||||||
|
|
||||||
|
DynamicArchiveModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
aid = json['aid'];
|
||||||
|
badge = json['badge'];
|
||||||
|
bvid = json['bvid'];
|
||||||
|
cover = json['cover'];
|
||||||
|
disablePreview = json['disable_preview'];
|
||||||
|
durationText = json['duration_text'];
|
||||||
|
jumpUrl = json['jump_url'];
|
||||||
|
stat = Stat.fromJson(json['stat']);
|
||||||
|
title = json['title'];
|
||||||
|
type = json['type'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DynamicDrawModel {
|
||||||
|
DynamicDrawModel({
|
||||||
|
this.id,
|
||||||
|
this.item,
|
||||||
|
});
|
||||||
|
|
||||||
|
int? id;
|
||||||
|
List<DynamicDrawItemModel>? item;
|
||||||
|
|
||||||
|
DynamicDrawModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
id = json['id'];
|
||||||
|
// ignore: prefer_null_aware_operators
|
||||||
|
item = json['item'] != null
|
||||||
|
? json['item']
|
||||||
|
.map<DynamicDrawItemModel>((e) => DynamicDrawItemModel.fromJson(e))
|
||||||
|
.toList()
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DynamicOpusModel {
|
||||||
|
DynamicOpusModel({
|
||||||
|
this.jumpUrl,
|
||||||
|
this.pics,
|
||||||
|
this.summary,
|
||||||
|
this.title,
|
||||||
|
});
|
||||||
|
|
||||||
|
String? jumpUrl;
|
||||||
|
List? pics;
|
||||||
|
Map? summary;
|
||||||
|
String? title;
|
||||||
|
DynamicOpusModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
jumpUrl = json['jump_url'];
|
||||||
|
pics = json['pics'];
|
||||||
|
summary = json['summary'];
|
||||||
|
title = json['title'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OpusPicsModel {
|
||||||
|
OpusPicsModel({
|
||||||
|
this.width,
|
||||||
|
this.height,
|
||||||
|
this.size,
|
||||||
|
this.src,
|
||||||
|
});
|
||||||
|
|
||||||
|
int? width;
|
||||||
|
int? height;
|
||||||
|
int? size;
|
||||||
|
String? src;
|
||||||
|
|
||||||
|
OpusPicsModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
width = json['width'];
|
||||||
|
height = json['height'];
|
||||||
|
size = json['size'];
|
||||||
|
src = json['src'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DynamicDrawItemModel {
|
||||||
|
DynamicDrawItemModel({
|
||||||
|
this.height,
|
||||||
|
this.size,
|
||||||
|
this.src,
|
||||||
|
this.tags,
|
||||||
|
this.width,
|
||||||
|
});
|
||||||
|
int? height;
|
||||||
|
int? size;
|
||||||
|
String? src;
|
||||||
|
List? tags;
|
||||||
|
int? width;
|
||||||
|
DynamicDrawItemModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
height = json['height'];
|
||||||
|
size = json['size'];
|
||||||
|
src = json['src'];
|
||||||
|
tags = json['tags'];
|
||||||
|
width = json['width'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动态状态 转发、评论、点赞
|
||||||
|
class ModuleStatModel {
|
||||||
|
ModuleStatModel({
|
||||||
|
this.comment,
|
||||||
|
this.forward,
|
||||||
|
this.like,
|
||||||
|
});
|
||||||
|
|
||||||
|
Comment? comment;
|
||||||
|
Map? forward;
|
||||||
|
Like? like;
|
||||||
|
|
||||||
|
ModuleStatModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
comment = Comment.fromJson(json['comment']);
|
||||||
|
forward = json['forward'];
|
||||||
|
like = Like.fromJson(json['like']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动态状态 评论
|
||||||
|
class Comment {
|
||||||
|
Comment({
|
||||||
|
this.count,
|
||||||
|
this.forbidden,
|
||||||
|
});
|
||||||
|
|
||||||
|
String? count;
|
||||||
|
bool? forbidden;
|
||||||
|
|
||||||
|
Comment.fromJson(Map<String, dynamic> json) {
|
||||||
|
count = json['count'].toString();
|
||||||
|
forbidden = json['forbidden'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动态状态 点赞
|
||||||
|
class Like {
|
||||||
|
Like({
|
||||||
|
this.count,
|
||||||
|
this.forbidden,
|
||||||
|
this.status,
|
||||||
|
});
|
||||||
|
|
||||||
|
String? count;
|
||||||
|
bool? forbidden;
|
||||||
|
bool? status;
|
||||||
|
|
||||||
|
Like.fromJson(Map<String, dynamic> json) {
|
||||||
|
count = json['count'].toString();
|
||||||
|
forbidden = json['forbidden'];
|
||||||
|
status = json['status'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Stat {
|
||||||
|
Stat({
|
||||||
|
this.danmaku,
|
||||||
|
this.play,
|
||||||
|
});
|
||||||
|
|
||||||
|
String? danmaku;
|
||||||
|
String? play;
|
||||||
|
|
||||||
|
Stat.fromJson(Map<String, dynamic> json) {
|
||||||
|
danmaku = json['danmaku'];
|
||||||
|
play = json['play'];
|
||||||
|
}
|
||||||
|
}
|
27
lib/pages/dynamics/controller.dart
Normal file
27
lib/pages/dynamics/controller.dart
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:pilipala/http/dynamics.dart';
|
||||||
|
import 'package:pilipala/models/dynamics/result.dart';
|
||||||
|
|
||||||
|
class DynamicsController extends GetxController {
|
||||||
|
int page = 1;
|
||||||
|
String reqType = 'all';
|
||||||
|
String? offset;
|
||||||
|
RxList<DynamicItemModel>? dynamicsList = [DynamicItemModel()].obs;
|
||||||
|
|
||||||
|
Future queryFollowDynamic({type = 'init'}) async {
|
||||||
|
var res = await DynamicsHttp.followDynamic(
|
||||||
|
page: page,
|
||||||
|
type: reqType,
|
||||||
|
offset: offset,
|
||||||
|
);
|
||||||
|
if (res['status']) {
|
||||||
|
if (type == 'init') {
|
||||||
|
dynamicsList!.value = res['data'].items;
|
||||||
|
} else {
|
||||||
|
dynamicsList!.addAll(res['data'].items);
|
||||||
|
}
|
||||||
|
offset = res['data'].offset;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
4
lib/pages/dynamics/index.dart
Normal file
4
lib/pages/dynamics/index.dart
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
library dynamics;
|
||||||
|
|
||||||
|
export './controller.dart';
|
||||||
|
export './view.dart';
|
78
lib/pages/dynamics/view.dart
Normal file
78
lib/pages/dynamics/view.dart
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:font_awesome_flutter/font_awesome_flutter.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/dynamics/result.dart';
|
||||||
|
|
||||||
|
import 'controller.dart';
|
||||||
|
import 'widgets/dynamic_panel.dart';
|
||||||
|
|
||||||
|
class DynamicsPage extends StatefulWidget {
|
||||||
|
const DynamicsPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DynamicsPage> createState() => _DynamicsPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DynamicsPageState extends State<DynamicsPage> {
|
||||||
|
DynamicsController _dynamicsController = Get.put(DynamicsController());
|
||||||
|
Future? _futureBuilderFuture;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_futureBuilderFuture = _dynamicsController.queryFollowDynamic();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
centerTitle: false,
|
||||||
|
title: const Text('动态'),
|
||||||
|
actions: [
|
||||||
|
IconButton(onPressed: () {}, icon: const Icon(Icons.more_horiz)),
|
||||||
|
const SizedBox(width: 10)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: FutureBuilder(
|
||||||
|
future: _dynamicsController.queryFollowDynamic(),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
|
Map data = snapshot.data;
|
||||||
|
if (data['status']) {
|
||||||
|
List<DynamicItemModel> list = _dynamicsController.dynamicsList!;
|
||||||
|
return Obx(
|
||||||
|
() => ListView.builder(
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemCount: list.length,
|
||||||
|
itemBuilder: (BuildContext context, index) {
|
||||||
|
return DynamicPanel(item: list[index]);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
HttpError(
|
||||||
|
errMsg: data['msg'],
|
||||||
|
fn: () => setState(() {}),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 骨架屏
|
||||||
|
// return SliverList(
|
||||||
|
// delegate: SliverChildBuilderDelegate((context, index) {
|
||||||
|
// return const VideoCardHSkeleton();
|
||||||
|
// }, childCount: 10),
|
||||||
|
// );
|
||||||
|
return Text('加载中');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
272
lib/pages/dynamics/widgets/dynamic_panel.dart
Normal file
272
lib/pages/dynamics/widgets/dynamic_panel.dart
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
|
import 'package:pilipala/common/constants.dart';
|
||||||
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
|
import 'package:pilipala/common/widgets/stat/danmu.dart';
|
||||||
|
import 'package:pilipala/common/widgets/stat/view.dart';
|
||||||
|
import 'package:pilipala/models/dynamics/result.dart';
|
||||||
|
|
||||||
|
class DynamicPanel extends StatelessWidget {
|
||||||
|
DynamicItemModel? item;
|
||||||
|
DynamicPanel({this.item, Key? key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
top: BorderSide(
|
||||||
|
width: 8,
|
||||||
|
color: Theme.of(context).dividerColor.withOpacity(0.05),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Material(
|
||||||
|
elevation: 0,
|
||||||
|
clipBehavior: Clip.hardEdge,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(0),
|
||||||
|
),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {},
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
author(item, context),
|
||||||
|
if (item!.modules!.moduleDynamic!.desc != null)
|
||||||
|
content(item, context),
|
||||||
|
Padding(
|
||||||
|
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, 10, 12, 10),
|
||||||
|
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),
|
||||||
|
Text(
|
||||||
|
item.modules.moduleAuthor.pubTime +
|
||||||
|
(item.modules.moduleAuthor.pubAction != ''
|
||||||
|
? ' - ${item.modules.moduleAuthor.pubAction}'
|
||||||
|
: ''),
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.outline,
|
||||||
|
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 内容
|
||||||
|
Widget content(item, context) {
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
padding: const EdgeInsets.fromLTRB(15, 0, 15, 10),
|
||||||
|
child: Text(
|
||||||
|
item!.modules!.moduleDynamic!.desc!.text!,
|
||||||
|
maxLines: 5,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转发
|
||||||
|
Widget forWard(item, context, {floor = 1}) {
|
||||||
|
switch (item.type) {
|
||||||
|
// 图文
|
||||||
|
case 'DYNAMIC_TYPE_DRAW':
|
||||||
|
return const Text('DYNAMIC_TYPE_DRAW');
|
||||||
|
// 视频
|
||||||
|
case 'DYNAMIC_TYPE_AV':
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
if (floor == 2) ...[
|
||||||
|
Text('@' + item.modules.moduleAuthor.name),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
],
|
||||||
|
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: item.modules.moduleDynamic.major.archive.cover,
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.fromLTRB(12, 22, 10, 15),
|
||||||
|
clipBehavior: Clip.hardEdge,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: const LinearGradient(
|
||||||
|
begin: Alignment.topCenter,
|
||||||
|
end: Alignment.bottomCenter,
|
||||||
|
colors: <Color>[
|
||||||
|
Colors.transparent,
|
||||||
|
Colors.black87,
|
||||||
|
],
|
||||||
|
tileMode: TileMode.mirror,
|
||||||
|
),
|
||||||
|
borderRadius: floor == 1
|
||||||
|
? null
|
||||||
|
: const BorderRadius.all(Radius.circular(6))),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
item.modules.moduleDynamic.major.archive
|
||||||
|
.durationText,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.labelMedium!
|
||||||
|
.fontSize,
|
||||||
|
color: Colors.white),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Text(
|
||||||
|
item.modules.moduleDynamic.major.archive
|
||||||
|
.stat.play,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.labelMedium!
|
||||||
|
.fontSize,
|
||||||
|
color: Colors.white),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Text(
|
||||||
|
item.modules.moduleDynamic.major.archive
|
||||||
|
.stat.danmaku,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.labelMedium!
|
||||||
|
.fontSize,
|
||||||
|
color: Colors.white),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Image.asset(
|
||||||
|
'assets/images/play.png',
|
||||||
|
width: 70,
|
||||||
|
height: 70,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 6),
|
||||||
|
Padding(
|
||||||
|
padding: floor == 1
|
||||||
|
? const EdgeInsets.only(left: 12, right: 12)
|
||||||
|
: EdgeInsets.zero,
|
||||||
|
child: Text(
|
||||||
|
item.modules.moduleDynamic.major.archive.title,
|
||||||
|
maxLines: 1,
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
// 文章
|
||||||
|
case 'DYNAMIC_TYPE_ARTICLE':
|
||||||
|
return const Text('DYNAMIC_TYPE_ARTICLE');
|
||||||
|
// 转发
|
||||||
|
case 'DYNAMIC_TYPE_FORWARD':
|
||||||
|
// return const Text('DYNAMIC_TYPE_FORWARD');
|
||||||
|
switch (item.orig.type) {
|
||||||
|
// 递归
|
||||||
|
case 'DYNAMIC_TYPE_AV':
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
left: 15, top: 10, right: 15, bottom: 10),
|
||||||
|
color: Theme.of(context).dividerColor.withOpacity(0.08),
|
||||||
|
child: forWard(item.orig, context, floor: 2),
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return const Text('渲染出错了');
|
||||||
|
}
|
||||||
|
// 直播
|
||||||
|
case 'DYNAMIC_TYPE_LIVE_RCMD':
|
||||||
|
return const Text('DYNAMIC_TYPE_LIVE_RCMD');
|
||||||
|
// 合集
|
||||||
|
case 'DYNAMIC_TYPE_UGC_SEASON':
|
||||||
|
return const Text('DYNAMIC_TYPE_UGC_SEASON');
|
||||||
|
default:
|
||||||
|
return const Text('渲染出错了');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 操作栏
|
||||||
|
Widget action(item, context) {
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
TextButton.icon(
|
||||||
|
onPressed: () {},
|
||||||
|
icon: const Icon(
|
||||||
|
FontAwesomeIcons.shareFromSquare,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
label: const Text('转发'),
|
||||||
|
),
|
||||||
|
TextButton.icon(
|
||||||
|
onPressed: () {},
|
||||||
|
icon: const Icon(
|
||||||
|
FontAwesomeIcons.comment,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
label: Text(item.modules.moduleStat.comment.count),
|
||||||
|
),
|
||||||
|
TextButton.icon(
|
||||||
|
onPressed: () {},
|
||||||
|
icon: const Icon(
|
||||||
|
FontAwesomeIcons.thumbsUp,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
label: Text(item.modules.moduleStat.like.count),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ import 'package:get/get.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
|
import 'package:pilipala/pages/dynamics/index.dart';
|
||||||
import 'package:pilipala/pages/home/view.dart';
|
import 'package:pilipala/pages/home/view.dart';
|
||||||
import 'package:pilipala/pages/hot/view.dart';
|
import 'package:pilipala/pages/hot/view.dart';
|
||||||
import 'package:pilipala/pages/media/index.dart';
|
import 'package:pilipala/pages/media/index.dart';
|
||||||
@ -13,6 +14,7 @@ class MainController extends GetxController {
|
|||||||
List<Widget> pages = <Widget>[
|
List<Widget> pages = <Widget>[
|
||||||
const HomePage(),
|
const HomePage(),
|
||||||
const HotPage(),
|
const HotPage(),
|
||||||
|
const DynamicsPage(),
|
||||||
const MediaPage(),
|
const MediaPage(),
|
||||||
];
|
];
|
||||||
RxList navigationBars = [
|
RxList navigationBars = [
|
||||||
@ -42,17 +44,17 @@ class MainController extends GetxController {
|
|||||||
),
|
),
|
||||||
'label': "热门",
|
'label': "热门",
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// 'icon': const Icon(
|
'icon': const Icon(
|
||||||
// CupertinoIcons.person,
|
CupertinoIcons.camera_on_rectangle,
|
||||||
// size: 21,
|
size: 21,
|
||||||
// ),
|
),
|
||||||
// 'selectedIcon': const Icon(
|
'selectedIcon': const Icon(
|
||||||
// CupertinoIcons.person_fill,
|
CupertinoIcons.camera_on_rectangle_fill,
|
||||||
// size: 21,
|
size: 21,
|
||||||
// ),
|
),
|
||||||
// 'label': "我的",
|
'label': "动态",
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
// 'icon': const Icon(Icons.person_outline),
|
// 'icon': const Icon(Icons.person_outline),
|
||||||
// 'selectedIcon': const Icon(Icons.person),
|
// 'selectedIcon': const Icon(Icons.person),
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:pilipala/pages/dynamics/view.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';
|
||||||
@ -47,6 +48,8 @@ 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())
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user