mod: 动态页面视频&专栏跳转

This commit is contained in:
guozhigq
2023-06-27 16:14:04 +08:00
parent bc8be693a8
commit eca48bc77e
7 changed files with 208 additions and 45 deletions

View File

@ -0,0 +1,122 @@
import 'package:flutter/material.dart';
import 'skeleton.dart';
class DynamicCardSkeleton extends StatelessWidget {
const DynamicCardSkeleton({super.key});
@override
Widget build(BuildContext context) {
return Skeleton(
child: Container(
padding: const EdgeInsets.only(left: 12, right: 12, top: 12),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
width: 8,
color: Theme.of(context).dividerColor.withOpacity(0.05),
),
),
),
child: Column(
children: [
Row(
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.onInverseSurface,
borderRadius: BorderRadius.circular(20),
),
),
const SizedBox(width: 10),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
color: Theme.of(context).colorScheme.onInverseSurface,
width: 100,
height: 13,
margin: const EdgeInsets.only(bottom: 5),
),
Container(
color: Theme.of(context).colorScheme.onInverseSurface,
width: 50,
height: 11,
),
],
)
],
),
Container(
width: double.infinity,
margin: const EdgeInsets.only(top: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
color: Theme.of(context).colorScheme.onInverseSurface,
width: double.infinity,
height: 13,
margin: const EdgeInsets.only(bottom: 7),
),
Container(
color: Theme.of(context).colorScheme.onInverseSurface,
width: double.infinity,
height: 13,
margin: const EdgeInsets.only(bottom: 7),
),
Container(
color: Theme.of(context).colorScheme.onInverseSurface,
width: 300,
height: 13,
margin: const EdgeInsets.only(bottom: 7),
),
Container(
color: Theme.of(context).colorScheme.onInverseSurface,
width: 250,
height: 13,
margin: const EdgeInsets.only(bottom: 7),
),
Container(
color: Theme.of(context).colorScheme.onInverseSurface,
width: 100,
height: 13,
margin: const EdgeInsets.only(bottom: 7),
),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
for (var i = 0; i < 3; i++)
TextButton.icon(
onPressed: () {},
icon: const Icon(
Icons.radio_button_unchecked_outlined,
size: 20,
),
style: TextButton.styleFrom(
padding: const EdgeInsets.fromLTRB(15, 0, 15, 0),
foregroundColor: Theme.of(context)
.colorScheme
.outline
.withOpacity(0.2),
),
label: Text(
i == 0
? '转发'
: i == 1
? '评论'
: '点赞',
),
)
],
)
],
),
),
);
}
}

View File

@ -23,7 +23,7 @@ class DynamicsHttp {
return {
'status': false,
'data': [],
'msg': '请求错误 🙅',
'msg': res.data['message'],
};
}
}

View File

@ -1,6 +1,10 @@
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:pilipala/http/dynamics.dart';
import 'package:pilipala/http/search.dart';
import 'package:pilipala/models/dynamics/result.dart';
import 'package:pilipala/utils/utils.dart';
class DynamicsController extends GetxController {
int page = 1;
@ -8,6 +12,7 @@ class DynamicsController extends GetxController {
RxList<DynamicItemModel>? dynamicsList = [DynamicItemModel()].obs;
RxString dynamicsType = 'all'.obs;
RxString dynamicsTypeLabel = '全部'.obs;
final ScrollController scrollController = ScrollController();
Future queryFollowDynamic({type = 'init'}) async {
var res = await DynamicsHttp.followDynamic(
@ -27,16 +32,22 @@ class DynamicsController extends GetxController {
return res;
}
onSelectType(value, label) {
onSelectType(value, label) async {
dynamicsType.value = value;
dynamicsTypeLabel.value = label;
queryFollowDynamic();
await queryFollowDynamic();
scrollController.animateTo(0,
duration: const Duration(milliseconds: 500), curve: Curves.easeInOut);
}
pushDetail(item, floor) {
pushDetail(item, floor, {action = 'all'}) async {
if (action == 'comment') {
Get.toNamed('/dynamicDetail',
arguments: {'item': item, 'floor': floor, 'action': action});
return false;
}
switch (item!.type) {
case 'DYNAMIC_TYPE_FORWARD':
print('转发的动态');
Get.toNamed('/dynamicDetail',
arguments: {'item': item, 'floor': floor});
break;
@ -45,10 +56,25 @@ class DynamicsController extends GetxController {
arguments: {'item': item, 'floor': floor});
break;
case 'DYNAMIC_TYPE_AV':
print('视频');
String bvid = item.modules.moduleDynamic.major.archive.bvid;
int aid = item.modules.moduleDynamic.major.archive.aid;
String cover = item.modules.moduleDynamic.major.archive.cover;
String heroTag = Utils.makeHeroTag(aid);
try {
int cid = await SearchHttp.ab2c(bvid: bvid);
Get.toNamed('/video?bvid=$bvid&cid=$cid',
arguments: {'pic': cover, 'heroTag': heroTag});
} catch (err) {
SmartDialog.showToast(err.toString());
}
break;
case 'DYNAMIC_TYPE_ARTICLE':
print('文章/专栏');
String title = item.modules.moduleDynamic.major.opus.title;
String url = item.modules.moduleDynamic.major.opus.jumpUrl;
Get.toNamed(
'/webview',
parameters: {'url': 'https:$url', 'type': 'note', 'pageTitle': title},
);
break;
case 'DYNAMIC_TYPE_PGC':
print('番剧');

View File

@ -24,6 +24,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage> {
late StreamController<bool> titleStreamC; // appBar title
final ScrollController scrollController = ScrollController();
bool _visibleTitle = false;
String? action;
@override
void initState() {
@ -37,11 +38,16 @@ class _DynamicDetailPageState extends State<DynamicDetailPage> {
oid = Get.arguments['item'].modules.moduleDynamic.major.draw.id;
type = 11;
}
action =
Get.arguments.containsKey('action') ? Get.arguments['action'] : null;
_dynamicDetailController = Get.put(DynamicDetailController(oid, type));
_futureBuilderFuture = _dynamicDetailController!.queryReplyList();
titleStreamC = StreamController<bool>();
scrollController.addListener(_listen);
if (action == 'comment') {
_visibleTitle = true;
titleStreamC.add(true);
}
}
void _listen() async {
@ -90,6 +96,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage> {
child: CustomScrollView(
controller: scrollController,
slivers: [
if (action != 'comment')
SliverToBoxAdapter(
child: DynamicPanel(
item: _dynamicDetailController!.item,

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/common/skeleton/dynamic_card.dart';
import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/models/common/dynamics_type.dart';
import 'package:pilipala/models/dynamics/result.dart';
@ -16,9 +17,9 @@ class DynamicsPage extends StatefulWidget {
class _DynamicsPageState extends State<DynamicsPage>
with AutomaticKeepAliveClientMixin {
DynamicsController _dynamicsController = Get.put(DynamicsController());
final DynamicsController _dynamicsController = Get.put(DynamicsController());
Future? _futureBuilderFuture;
final ScrollController scrollController = ScrollController();
// final ScrollController scrollController = ScrollController();
bool _isLoadingMore = false;
@override
bool get wantKeepAlive => true;
@ -28,10 +29,11 @@ class _DynamicsPageState extends State<DynamicsPage>
super.initState();
_futureBuilderFuture = _dynamicsController.queryFollowDynamic();
scrollController.addListener(
_dynamicsController.scrollController.addListener(
() async {
if (scrollController.position.pixels >=
scrollController.position.maxScrollExtent - 200) {
if (_dynamicsController.scrollController.position.pixels >=
_dynamicsController.scrollController.position.maxScrollExtent -
200) {
if (!_isLoadingMore) {
_isLoadingMore = true;
await _dynamicsController.queryFollowDynamic(type: 'onLoad');
@ -92,7 +94,7 @@ class _DynamicsPageState extends State<DynamicsPage>
List<DynamicItemModel> list = _dynamicsController.dynamicsList!;
return Obx(
() => ListView.builder(
controller: scrollController,
controller: _dynamicsController.scrollController,
shrinkWrap: true,
itemCount: list.length,
itemBuilder: (BuildContext context, index) {
@ -105,19 +107,18 @@ class _DynamicsPageState extends State<DynamicsPage>
slivers: [
HttpError(
errMsg: data['msg'],
fn: () => setState(() {}),
fn: () => _dynamicsController.queryFollowDynamic(),
)
],
);
}
} else {
// 骨架屏
// return SliverList(
// delegate: SliverChildBuilderDelegate((context, index) {
// return const VideoCardHSkeleton();
// }, childCount: 10),
// );
return Text('加载中');
return ListView.builder(
physics: const NeverScrollableScrollPhysics(),
itemCount: 5,
itemBuilder: ((context, index) => const DynamicCardSkeleton()),
);
}
},
),

View File

@ -26,7 +26,8 @@ Widget action(item, context) {
label: Text(stat.forward!.count ?? '转发'),
),
TextButton.icon(
onPressed: () => _dynamicsController.pushDetail(item, 1),
onPressed: () =>
_dynamicsController.pushDetail(item, 1, action: 'comment'),
icon: const Icon(
FontAwesomeIcons.comment,
size: 16,

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/common/constants.dart';
import 'package:pilipala/common/widgets/badge.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart';
Widget picWidget(item, context) {
@ -14,7 +15,6 @@ Widget picWidget(item, context) {
}
int len = pictures.length;
List picList = [];
List<Widget> list = [];
for (var i = 0; i < len; i++) {
picList.add(pictures[i].src ?? pictures[i].url);
@ -42,7 +42,8 @@ Widget picWidget(item, context) {
return LayoutBuilder(
builder: (context, BoxConstraints box) {
double maxWidth = box.maxWidth;
double aspectRatio = 1.1;
double aspectRatio = 1.0;
double origAspectRatio = 0.0;
double crossCount = len == 1
? 1
: len < 3
@ -51,20 +52,19 @@ Widget picWidget(item, context) {
double height = 0.0;
if (len == 1) {
origAspectRatio =
aspectRatio = pictures.first.width / pictures.first.height;
if (aspectRatio < 0.4) {
aspectRatio = 0.4;
}
height = pictures.first.height * maxWidth / pictures.first.width;
if (pictures.first.width != 1920) {
if (origAspectRatio < 0.5 || pictures.first.width < 1920) {
crossCount = 2;
height = maxWidth / 2 / aspectRatio;
}
} else {
aspectRatio = 1;
height = maxWidth /
crossCount *
(len % crossCount == 0
? len ~/ crossCount
: len ~/ crossCount + 1) +
6;
height = maxWidth / crossCount * ((len / crossCount).ceil()) + 6;
}
return Container(
padding: const EdgeInsets.only(top: 4),
@ -73,7 +73,9 @@ Widget picWidget(item, context) {
),
clipBehavior: Clip.hardEdge,
height: height,
child: GridView.count(
child: Stack(
children: [
GridView.count(
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: crossCount.toInt(),
@ -82,6 +84,10 @@ Widget picWidget(item, context) {
childAspectRatio: aspectRatio,
children: list,
),
if (len == 1 && origAspectRatio < 0.4)
pBadge('长图', context, null, null, 6.0, 6.0, type: 'gray')
],
),
);
},
);