feat: 新增动态页面

This commit is contained in:
guozhigq
2023-06-24 23:47:05 +08:00
parent 7174eef890
commit 714cbb2d0f
10 changed files with 844 additions and 12 deletions

View 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;
}
}

View File

@ -0,0 +1,4 @@
library dynamics;
export './controller.dart';
export './view.dart';

View 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('加载中');
}
},
),
);
}
}

View 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),
)
],
);
}
}