mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
@@ -168,7 +168,7 @@ class _AppExpansionPanelListState extends State<AppExpansionPanelList> {
|
||||
if (widget.expansionCallback != null &&
|
||||
childIndex != index &&
|
||||
child.value == _currentOpenPanel?.value) {
|
||||
widget.expansionCallback!(childIndex, false);
|
||||
widget.expansionCallback?.call(childIndex, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,90 +6,83 @@ import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_html/flutter_html.dart';
|
||||
|
||||
class ArticleContent extends StatelessWidget {
|
||||
const ArticleContent({
|
||||
super.key,
|
||||
required this.list,
|
||||
});
|
||||
|
||||
final List<ArticleContentModel> list;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<String>? imgList = list
|
||||
.where((item) => item.pic != null)
|
||||
.toList()
|
||||
.map((item) => item.pic?.pics?.first.url ?? '')
|
||||
.toList();
|
||||
return SliverList.separated(
|
||||
itemCount: list.length,
|
||||
itemBuilder: (_, index) {
|
||||
ArticleContentModel item = list[index];
|
||||
if (item.text != null) {
|
||||
List<InlineSpan> spanList = [];
|
||||
item.text?.nodes?.forEach((item) {
|
||||
spanList.add(TextSpan(
|
||||
text: item.word?.words,
|
||||
style: TextStyle(
|
||||
letterSpacing: 0.3,
|
||||
fontSize: FontSize.large.value,
|
||||
height: LineHeight.percent(125).size,
|
||||
fontStyle:
|
||||
item.word?.style?.italic == true ? FontStyle.italic : null,
|
||||
color: item.word?.color != null
|
||||
? Color(int.parse(
|
||||
item.word!.color!.replaceFirst('#', 'FF'),
|
||||
radix: 16,
|
||||
))
|
||||
: null,
|
||||
decoration: item.word?.style?.strikethrough == true
|
||||
? TextDecoration.lineThrough
|
||||
: null,
|
||||
fontWeight:
|
||||
item.word?.style?.bold == true ? FontWeight.bold : null,
|
||||
),
|
||||
));
|
||||
});
|
||||
return SelectableText.rich(TextSpan(children: spanList));
|
||||
} else if (item.line != null) {
|
||||
return Container(
|
||||
alignment: Alignment.center,
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: item.line?.pic?.url?.http2https ?? '',
|
||||
height: item.line?.pic?.height?.toDouble(),
|
||||
Widget articleContent({
|
||||
required BuildContext context,
|
||||
required List<ArticleContentModel> list,
|
||||
}) {
|
||||
List<String>? imgList = list
|
||||
.where((item) => item.pic != null)
|
||||
.toList()
|
||||
.map((item) => item.pic?.pics?.first.url ?? '')
|
||||
.toList();
|
||||
return SliverList.separated(
|
||||
itemCount: list.length,
|
||||
itemBuilder: (_, index) {
|
||||
ArticleContentModel item = list[index];
|
||||
if (item.text != null) {
|
||||
List<InlineSpan> spanList = [];
|
||||
item.text?.nodes?.forEach((item) {
|
||||
spanList.add(TextSpan(
|
||||
text: item.word?.words,
|
||||
style: TextStyle(
|
||||
letterSpacing: 0.3,
|
||||
fontSize: FontSize.large.value,
|
||||
height: LineHeight.percent(125).size,
|
||||
fontStyle:
|
||||
item.word?.style?.italic == true ? FontStyle.italic : null,
|
||||
color: item.word?.color != null
|
||||
? Color(int.parse(
|
||||
item.word!.color!.replaceFirst('#', 'FF'),
|
||||
radix: 16,
|
||||
))
|
||||
: null,
|
||||
decoration: item.word?.style?.strikethrough == true
|
||||
? TextDecoration.lineThrough
|
||||
: null,
|
||||
fontWeight:
|
||||
item.word?.style?.bold == true ? FontWeight.bold : null,
|
||||
),
|
||||
);
|
||||
} else if (item.pic != null) {
|
||||
return LayoutBuilder(
|
||||
builder: (_, constraints) => GestureDetector(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
useSafeArea: false,
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return ImagePreview(
|
||||
initialPage: imgList.indexOf(item.pic!.pics!.first.url!),
|
||||
imgList: imgList,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: NetworkImgLayer(
|
||||
width: constraints.maxWidth,
|
||||
height: constraints.maxWidth *
|
||||
item.pic!.pics!.first.height! /
|
||||
item.pic!.pics!.first.width!,
|
||||
src: item.pic!.pics!.first.url,
|
||||
),
|
||||
));
|
||||
});
|
||||
return SelectableText.rich(TextSpan(children: spanList));
|
||||
} else if (item.line != null) {
|
||||
return Container(
|
||||
alignment: Alignment.center,
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: item.line?.pic?.url?.http2https ?? '',
|
||||
height: item.line?.pic?.height?.toDouble(),
|
||||
),
|
||||
);
|
||||
} else if (item.pic != null) {
|
||||
return LayoutBuilder(
|
||||
builder: (_, constraints) => GestureDetector(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
useSafeArea: false,
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return ImagePreview(
|
||||
initialPage: imgList.indexOf(item.pic!.pics!.first.url!),
|
||||
imgList: imgList,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: NetworkImgLayer(
|
||||
width: constraints.maxWidth,
|
||||
height: constraints.maxWidth *
|
||||
item.pic!.pics!.first.height! /
|
||||
item.pic!.pics!.first.width!,
|
||||
src: item.pic!.pics!.first.url,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return const SizedBox.shrink();
|
||||
// return Text('unsupported content');
|
||||
}
|
||||
},
|
||||
separatorBuilder: (context, index) => const SizedBox(height: 10),
|
||||
);
|
||||
}
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return const SizedBox.shrink();
|
||||
// return Text('unsupported content');
|
||||
}
|
||||
},
|
||||
separatorBuilder: (context, index) => const SizedBox(height: 10),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,139 +3,125 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_html/flutter_html.dart';
|
||||
import 'network_img_layer.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class HtmlRender extends StatelessWidget {
|
||||
const HtmlRender({
|
||||
this.htmlContent,
|
||||
this.imgCount,
|
||||
this.imgList,
|
||||
required this.constrainedWidth,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final String? htmlContent;
|
||||
final int? imgCount;
|
||||
final List<String>? imgList;
|
||||
final double constrainedWidth;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// double textScale =
|
||||
// setting.get(SettingBoxKey.defaultTextScale, defaultValue: 1.0);
|
||||
return SelectionArea(
|
||||
child: Html(
|
||||
data: htmlContent,
|
||||
onLinkTap: (String? url, Map<String, String> buildContext, attributes) {},
|
||||
extensions: [
|
||||
TagExtension(
|
||||
tagsToExtend: <String>{'img'},
|
||||
builder: (ExtensionContext extensionContext) {
|
||||
try {
|
||||
final Map<String, dynamic> attributes =
|
||||
extensionContext.attributes;
|
||||
final List<dynamic> key = attributes.keys.toList();
|
||||
String imgUrl = key.contains('src')
|
||||
? attributes['src'] as String
|
||||
: attributes['data-src'] as String;
|
||||
if (imgUrl.startsWith('//')) {
|
||||
imgUrl = 'https:$imgUrl';
|
||||
}
|
||||
if (imgUrl.startsWith('http://')) {
|
||||
imgUrl = imgUrl.replaceAll('http://', 'https://');
|
||||
}
|
||||
imgUrl = imgUrl.contains('@') ? imgUrl.split('@').first : imgUrl;
|
||||
final bool isEmote = imgUrl.contains('/emote/');
|
||||
final bool isMall = imgUrl.contains('/mall/');
|
||||
if (isMall) {
|
||||
return const SizedBox();
|
||||
}
|
||||
// bool inTable =
|
||||
// extensionContext.element!.previousElementSibling == null ||
|
||||
// extensionContext.element!.nextElementSibling == null;
|
||||
// imgUrl = Utils().imageUrl(imgUrl!);
|
||||
// return Image.network(
|
||||
// imgUrl,
|
||||
// width: isEmote ? 22 : null,
|
||||
// height: isEmote ? 22 : null,
|
||||
// );
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
useSafeArea: false,
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return ImagePreview(
|
||||
initialPage: 0,
|
||||
imgList: [imgUrl],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: NetworkImgLayer(
|
||||
width: isEmote ? 22 : constrainedWidth,
|
||||
height: isEmote ? 22 : 200,
|
||||
src: imgUrl,
|
||||
ignoreHeight: !isEmote,
|
||||
),
|
||||
);
|
||||
} catch (err) {
|
||||
Widget htmlRender({
|
||||
required BuildContext context,
|
||||
String? htmlContent,
|
||||
int? imgCount,
|
||||
List<String>? imgList,
|
||||
required double constrainedWidth,
|
||||
}) {
|
||||
return SelectionArea(
|
||||
child: Html(
|
||||
data: htmlContent,
|
||||
onLinkTap: (String? url, Map<String, String> buildContext, attributes) {},
|
||||
extensions: [
|
||||
TagExtension(
|
||||
tagsToExtend: <String>{'img'},
|
||||
builder: (ExtensionContext extensionContext) {
|
||||
try {
|
||||
final Map<String, dynamic> attributes = extensionContext.attributes;
|
||||
final List<dynamic> key = attributes.keys.toList();
|
||||
String imgUrl = key.contains('src')
|
||||
? attributes['src'] as String
|
||||
: attributes['data-src'] as String;
|
||||
if (imgUrl.startsWith('//')) {
|
||||
imgUrl = 'https:$imgUrl';
|
||||
}
|
||||
if (imgUrl.startsWith('http://')) {
|
||||
imgUrl = imgUrl.replaceAll('http://', 'https://');
|
||||
}
|
||||
imgUrl = imgUrl.contains('@') ? imgUrl.split('@').first : imgUrl;
|
||||
final bool isEmote = imgUrl.contains('/emote/');
|
||||
final bool isMall = imgUrl.contains('/mall/');
|
||||
if (isMall) {
|
||||
return const SizedBox();
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
style: {
|
||||
'html': Style(
|
||||
fontSize: FontSize.large,
|
||||
lineHeight: LineHeight.percent(160),
|
||||
letterSpacing: 0.3,
|
||||
),
|
||||
// 'br': Style(margin: Margins.zero, padding: HtmlPaddings.zero),
|
||||
'body': Style(margin: Margins.zero, padding: HtmlPaddings.zero),
|
||||
'a': Style(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
textDecoration: TextDecoration.none,
|
||||
),
|
||||
'br': Style(
|
||||
lineHeight: LineHeight.percent(-1),
|
||||
),
|
||||
'p': Style(
|
||||
margin: Margins.only(bottom: 4),
|
||||
// margin: Margins.zero,
|
||||
),
|
||||
'span': Style(
|
||||
fontSize: FontSize.medium,
|
||||
height: Height(1.8),
|
||||
),
|
||||
'div': Style(height: Height.auto()),
|
||||
'li > p': Style(
|
||||
display: Display.inline,
|
||||
),
|
||||
'li': Style(
|
||||
padding: HtmlPaddings.only(bottom: 4),
|
||||
textAlign: TextAlign.justify,
|
||||
),
|
||||
'img': Style(margin: Margins.only(top: 4, bottom: 4)),
|
||||
'h1,h2': Style(
|
||||
fontSize: FontSize.xLarge,
|
||||
fontWeight: FontWeight.bold,
|
||||
margin: Margins.only(bottom: 8),
|
||||
),
|
||||
'h3,h4,h5': Style(
|
||||
fontSize: FontSize.large,
|
||||
fontWeight: FontWeight.bold,
|
||||
margin: Margins.only(bottom: 4),
|
||||
),
|
||||
'figcaption': Style(
|
||||
fontSize: FontSize.medium,
|
||||
textAlign: TextAlign.center,
|
||||
// margin: Margins.only(top: 4),
|
||||
),
|
||||
'strong': Style(fontWeight: FontWeight.bold),
|
||||
'figure': Style(
|
||||
margin: Margins.zero,
|
||||
),
|
||||
},
|
||||
));
|
||||
}
|
||||
// bool inTable =
|
||||
// extensionContext.element!.previousElementSibling == null ||
|
||||
// extensionContext.element!.nextElementSibling == null;
|
||||
// imgUrl = Utils().imageUrl(imgUrl!);
|
||||
// return Image.network(
|
||||
// imgUrl,
|
||||
// width: isEmote ? 22 : null,
|
||||
// height: isEmote ? 22 : null,
|
||||
// );
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
showDialog(
|
||||
useSafeArea: false,
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return ImagePreview(
|
||||
initialPage: 0,
|
||||
imgList: [imgUrl],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: NetworkImgLayer(
|
||||
width: isEmote ? 22 : constrainedWidth,
|
||||
height: isEmote ? 22 : 200,
|
||||
src: imgUrl,
|
||||
ignoreHeight: !isEmote,
|
||||
),
|
||||
);
|
||||
} catch (err) {
|
||||
return const SizedBox();
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
style: {
|
||||
'html': Style(
|
||||
fontSize: FontSize.large,
|
||||
lineHeight: LineHeight.percent(160),
|
||||
letterSpacing: 0.3,
|
||||
),
|
||||
// 'br': Style(margin: Margins.zero, padding: HtmlPaddings.zero),
|
||||
'body': Style(margin: Margins.zero, padding: HtmlPaddings.zero),
|
||||
'a': Style(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
textDecoration: TextDecoration.none,
|
||||
),
|
||||
'br': Style(
|
||||
lineHeight: LineHeight.percent(-1),
|
||||
),
|
||||
'p': Style(
|
||||
margin: Margins.only(bottom: 4),
|
||||
// margin: Margins.zero,
|
||||
),
|
||||
'span': Style(
|
||||
fontSize: FontSize.medium,
|
||||
height: Height(1.8),
|
||||
),
|
||||
'div': Style(height: Height.auto()),
|
||||
'li > p': Style(
|
||||
display: Display.inline,
|
||||
),
|
||||
'li': Style(
|
||||
padding: HtmlPaddings.only(bottom: 4),
|
||||
textAlign: TextAlign.justify,
|
||||
),
|
||||
'img': Style(margin: Margins.only(top: 4, bottom: 4)),
|
||||
'h1,h2': Style(
|
||||
fontSize: FontSize.xLarge,
|
||||
fontWeight: FontWeight.bold,
|
||||
margin: Margins.only(bottom: 8),
|
||||
),
|
||||
'h3,h4,h5': Style(
|
||||
fontSize: FontSize.large,
|
||||
fontWeight: FontWeight.bold,
|
||||
margin: Margins.only(bottom: 4),
|
||||
),
|
||||
'figcaption': Style(
|
||||
fontSize: FontSize.medium,
|
||||
textAlign: TextAlign.center,
|
||||
// margin: Margins.only(top: 4),
|
||||
),
|
||||
'strong': Style(fontWeight: FontWeight.bold),
|
||||
'figure': Style(
|
||||
margin: Margins.zero,
|
||||
),
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
@@ -13,53 +13,6 @@ import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||
import '../../utils/storage.dart';
|
||||
import '../../utils/utils.dart';
|
||||
|
||||
class ListSheet {
|
||||
ListSheet({
|
||||
this.index,
|
||||
this.season,
|
||||
required this.episodes,
|
||||
this.bvid,
|
||||
this.aid,
|
||||
required this.currentCid,
|
||||
required this.changeFucCall,
|
||||
required this.context,
|
||||
this.scaffoldState,
|
||||
});
|
||||
|
||||
final dynamic index;
|
||||
final dynamic season;
|
||||
final dynamic episodes;
|
||||
final String? bvid;
|
||||
final int? aid;
|
||||
final int currentCid;
|
||||
final Function changeFucCall;
|
||||
final BuildContext context;
|
||||
final ScaffoldState? scaffoldState;
|
||||
|
||||
late PersistentBottomSheetController bottomSheetController;
|
||||
|
||||
Widget get listSheetContent => ListSheetContent(
|
||||
index: index,
|
||||
season: season,
|
||||
episodes: episodes,
|
||||
bvid: bvid,
|
||||
aid: aid,
|
||||
currentCid: currentCid,
|
||||
changeFucCall: changeFucCall,
|
||||
onClose: bottomSheetController.close,
|
||||
);
|
||||
|
||||
void buildShowBottomSheet() {
|
||||
bottomSheetController = scaffoldState?.showBottomSheet(
|
||||
(context) => listSheetContent,
|
||||
) ??
|
||||
showBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => listSheetContent,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ListSheetContent extends StatefulWidget {
|
||||
const ListSheetContent({
|
||||
super.key,
|
||||
@@ -80,7 +33,7 @@ class ListSheetContent extends StatefulWidget {
|
||||
final int? aid;
|
||||
final int currentCid;
|
||||
final Function changeFucCall;
|
||||
final Function() onClose;
|
||||
final VoidCallback? onClose;
|
||||
|
||||
@override
|
||||
State<ListSheetContent> createState() => _ListSheetContentState();
|
||||
@@ -184,7 +137,7 @@ class _ListSheetContentState extends State<ListSheetContent>
|
||||
}
|
||||
}
|
||||
SmartDialog.showToast('切换到:$title');
|
||||
widget.onClose();
|
||||
widget.onClose?.call();
|
||||
widget.changeFucCall(
|
||||
episode is bangumi.EpisodeItem ? episode.epId : null,
|
||||
episode.runtimeType.toString() == "EpisodeItem"
|
||||
|
||||
@@ -53,31 +53,21 @@ class LiveCard extends StatelessWidget {
|
||||
child: AnimatedOpacity(
|
||||
opacity: 1,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
child: LiveStat(
|
||||
// view: liveItem.stat.view,
|
||||
// danmaku: liveItem.stat.danmaku,
|
||||
// duration: liveItem.duration,
|
||||
online: liveItem.online as int,
|
||||
),
|
||||
child: liveStat(context),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
LiveContent(liveItem: liveItem)
|
||||
liveContent(context)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class LiveContent extends StatelessWidget {
|
||||
final dynamic liveItem;
|
||||
const LiveContent({super.key, required this.liveItem});
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget liveContent(context) {
|
||||
return Padding(
|
||||
// 多列
|
||||
padding: const EdgeInsets.fromLTRB(8, 8, 6, 7),
|
||||
@@ -109,15 +99,8 @@ class LiveContent extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class LiveStat extends StatelessWidget {
|
||||
const LiveStat({super.key, required this.online});
|
||||
|
||||
final int? online;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget liveStat(context) {
|
||||
return Container(
|
||||
height: 45,
|
||||
padding: const EdgeInsets.only(top: 22, left: 8, right: 8),
|
||||
@@ -149,7 +132,7 @@ class LiveStat extends StatelessWidget {
|
||||
// ],
|
||||
// ),
|
||||
Text(
|
||||
online.toString(),
|
||||
liveItem.online.toString(),
|
||||
style: const TextStyle(fontSize: 11, color: Colors.white),
|
||||
)
|
||||
],
|
||||
|
||||
@@ -53,7 +53,7 @@ class OverlayPop extends StatelessWidget {
|
||||
style: ButtonStyle(
|
||||
padding: WidgetStateProperty.all(EdgeInsets.zero),
|
||||
),
|
||||
onPressed: () => closeFn!(),
|
||||
onPressed: () => closeFn?.call(),
|
||||
icon: const Icon(
|
||||
Icons.close,
|
||||
size: 18,
|
||||
@@ -93,7 +93,7 @@ class OverlayPop extends StatelessWidget {
|
||||
: (videoItem.cover as String).http2https)
|
||||
],
|
||||
);
|
||||
closeFn!();
|
||||
closeFn?.call();
|
||||
},
|
||||
icon: const Icon(Icons.download, size: 20),
|
||||
)
|
||||
|
||||
@@ -1,40 +1,36 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:PiliPalaX/utils/utils.dart';
|
||||
|
||||
class StatDanMu extends StatelessWidget {
|
||||
final String? theme;
|
||||
final dynamic danmu;
|
||||
final String? size;
|
||||
|
||||
const StatDanMu({super.key, this.theme, this.danmu, this.size});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Map<String, Color> colorObject = {
|
||||
'white': Colors.white,
|
||||
'gray': Theme.of(context).colorScheme.outline.withOpacity(0.8),
|
||||
'black': Theme.of(context).colorScheme.onSurface.withOpacity(0.7),
|
||||
};
|
||||
Color color = colorObject[theme]!;
|
||||
return Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.subtitles_outlined,
|
||||
size: 14,
|
||||
Widget statDanMu({
|
||||
required BuildContext context,
|
||||
String? theme,
|
||||
dynamic danmu,
|
||||
String? size,
|
||||
}) {
|
||||
Map<String, Color> colorObject = {
|
||||
'white': Colors.white,
|
||||
'gray': Theme.of(context).colorScheme.outline.withOpacity(0.8),
|
||||
'black': Theme.of(context).colorScheme.onSurface.withOpacity(0.7),
|
||||
};
|
||||
Color color = colorObject[theme]!;
|
||||
return Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.subtitles_outlined,
|
||||
size: 14,
|
||||
color: color,
|
||||
),
|
||||
const SizedBox(width: 2),
|
||||
Text(
|
||||
Utils.numFormat(danmu!),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: size == 'medium' ? 12 : 11,
|
||||
color: color,
|
||||
),
|
||||
const SizedBox(width: 2),
|
||||
Text(
|
||||
Utils.numFormat(danmu!),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: size == 'medium' ? 12 : 11,
|
||||
color: color,
|
||||
),
|
||||
overflow: TextOverflow.clip,
|
||||
semanticsLabel: '${Utils.numFormat(danmu!)}条弹幕',
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
overflow: TextOverflow.clip,
|
||||
semanticsLabel: '${Utils.numFormat(danmu!)}条弹幕',
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,44 +1,40 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:PiliPalaX/utils/utils.dart';
|
||||
|
||||
class StatView extends StatelessWidget {
|
||||
final String? theme;
|
||||
final dynamic view;
|
||||
final String? size;
|
||||
final String? goto;
|
||||
|
||||
const StatView({super.key, this.theme, this.view, this.size, this.goto});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Map<String, Color> colorObject = {
|
||||
'white': Colors.white,
|
||||
'gray': Theme.of(context).colorScheme.outline.withOpacity(0.8),
|
||||
'black': Theme.of(context).colorScheme.onSurface.withOpacity(0.7),
|
||||
};
|
||||
Color color = colorObject[theme]!;
|
||||
return Row(
|
||||
children: [
|
||||
Icon(
|
||||
goto == 'picture'
|
||||
? Icons.remove_red_eye_outlined
|
||||
: Icons.play_circle_outlined,
|
||||
size: 13,
|
||||
Widget statView({
|
||||
required BuildContext context,
|
||||
String? theme,
|
||||
dynamic view,
|
||||
String? size,
|
||||
String? goto,
|
||||
}) {
|
||||
Map<String, Color> colorObject = {
|
||||
'white': Colors.white,
|
||||
'gray': Theme.of(context).colorScheme.outline.withOpacity(0.8),
|
||||
'black': Theme.of(context).colorScheme.onSurface.withOpacity(0.7),
|
||||
};
|
||||
Color color = colorObject[theme]!;
|
||||
return Row(
|
||||
children: [
|
||||
Icon(
|
||||
goto == 'picture'
|
||||
? Icons.remove_red_eye_outlined
|
||||
: Icons.play_circle_outlined,
|
||||
size: 13,
|
||||
color: color,
|
||||
),
|
||||
const SizedBox(width: 2),
|
||||
Text(
|
||||
Utils.numFormat(view!),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: size == 'medium' ? 12 : 11,
|
||||
color: color,
|
||||
),
|
||||
const SizedBox(width: 2),
|
||||
Text(
|
||||
Utils.numFormat(view!),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: size == 'medium' ? 12 : 11,
|
||||
color: color,
|
||||
),
|
||||
overflow: TextOverflow.clip,
|
||||
semanticsLabel:
|
||||
'${Utils.numFormat(view!)}次${goto == "picture" ? "浏览" : "播放"}',
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
overflow: TextOverflow.clip,
|
||||
semanticsLabel:
|
||||
'${Utils.numFormat(view!)}次${goto == "picture" ? "浏览" : "播放"}',
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -55,11 +55,7 @@ class VideoCardH extends StatelessWidget {
|
||||
},
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
onLongPress: () {
|
||||
if (longPress != null) {
|
||||
longPress!();
|
||||
}
|
||||
},
|
||||
onLongPress: longPress,
|
||||
onTap: () async {
|
||||
if (type == 'ketang') {
|
||||
SmartDialog.showToast('课堂视频暂不支持播放');
|
||||
@@ -120,14 +116,7 @@ class VideoCardH extends StatelessWidget {
|
||||
},
|
||||
),
|
||||
),
|
||||
VideoContent(
|
||||
videoItem: videoItem,
|
||||
source: source,
|
||||
showOwner: showOwner,
|
||||
showView: showView,
|
||||
showDanmaku: showDanmaku,
|
||||
showPubdate: showPubdate,
|
||||
)
|
||||
videoContent(context)
|
||||
],
|
||||
);
|
||||
},
|
||||
@@ -146,28 +135,8 @@ class VideoCardH extends StatelessWidget {
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
class VideoContent extends StatelessWidget {
|
||||
final dynamic videoItem;
|
||||
final String source;
|
||||
final bool showOwner;
|
||||
final bool showView;
|
||||
final bool showDanmaku;
|
||||
final bool showPubdate;
|
||||
|
||||
const VideoContent({
|
||||
super.key,
|
||||
required this.videoItem,
|
||||
this.source = 'normal',
|
||||
this.showOwner = true,
|
||||
this.showView = true,
|
||||
this.showDanmaku = true,
|
||||
this.showPubdate = false,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget videoContent(context) {
|
||||
String pubdate = showPubdate
|
||||
? Utils.dateFormat(videoItem.pubdate!, formatType: 'day')
|
||||
: '';
|
||||
@@ -258,14 +227,16 @@ class VideoContent extends StatelessWidget {
|
||||
Row(
|
||||
children: [
|
||||
if (showView) ...[
|
||||
StatView(
|
||||
statView(
|
||||
context: context,
|
||||
theme: 'gray',
|
||||
view: videoItem.stat.view as int,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
if (showDanmaku)
|
||||
StatDanMu(
|
||||
statDanMu(
|
||||
context: context,
|
||||
theme: 'gray',
|
||||
danmu: videoItem.stat.danmu as int,
|
||||
),
|
||||
|
||||
@@ -50,11 +50,7 @@ class VideoCardHGrpc extends StatelessWidget {
|
||||
// },
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
onLongPress: () {
|
||||
if (longPress != null) {
|
||||
longPress!();
|
||||
}
|
||||
},
|
||||
onLongPress: longPress,
|
||||
onTap: () async {
|
||||
if (type == 'ketang') {
|
||||
SmartDialog.showToast('课堂视频暂不支持播放');
|
||||
@@ -121,14 +117,7 @@ class VideoCardHGrpc extends StatelessWidget {
|
||||
},
|
||||
),
|
||||
),
|
||||
VideoContent(
|
||||
videoItem: videoItem,
|
||||
source: source,
|
||||
showOwner: showOwner,
|
||||
showView: showView,
|
||||
showDanmaku: showDanmaku,
|
||||
showPubdate: showPubdate,
|
||||
)
|
||||
videoContent(context)
|
||||
],
|
||||
);
|
||||
},
|
||||
@@ -147,32 +136,8 @@ class VideoCardHGrpc extends StatelessWidget {
|
||||
// ),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
class VideoContent extends StatelessWidget {
|
||||
final card.Card videoItem;
|
||||
final String source;
|
||||
final bool showOwner;
|
||||
final bool showView;
|
||||
final bool showDanmaku;
|
||||
final bool showPubdate;
|
||||
|
||||
const VideoContent({
|
||||
super.key,
|
||||
required this.videoItem,
|
||||
this.source = 'normal',
|
||||
this.showOwner = true,
|
||||
this.showView = true,
|
||||
this.showDanmaku = true,
|
||||
this.showPubdate = false,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// String pubdate = showPubdate
|
||||
// ? Utils.dateFormat(videoItem.pubdate!, formatType: 'day')
|
||||
// : '';
|
||||
// if (pubdate != '') pubdate += ' ';
|
||||
Widget videoContent(context) {
|
||||
return Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(10, 0, 6, 0),
|
||||
|
||||
@@ -30,11 +30,7 @@ class VideoCardHMemberVideo extends StatelessWidget {
|
||||
return Stack(children: [
|
||||
InkWell(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
onLongPress: () {
|
||||
if (longPress != null) {
|
||||
longPress!();
|
||||
}
|
||||
},
|
||||
onLongPress: longPress,
|
||||
onTap: () async {
|
||||
try {
|
||||
Get.toNamed('/video?bvid=$bvid&cid=${videoItem.firstCid}',
|
||||
@@ -87,9 +83,7 @@ class VideoCardHMemberVideo extends StatelessWidget {
|
||||
},
|
||||
),
|
||||
),
|
||||
VideoContent(
|
||||
videoItem: videoItem,
|
||||
)
|
||||
videoContent(context)
|
||||
],
|
||||
);
|
||||
},
|
||||
@@ -106,18 +100,8 @@ class VideoCardHMemberVideo extends StatelessWidget {
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
class VideoContent extends StatelessWidget {
|
||||
final Item videoItem;
|
||||
|
||||
const VideoContent({
|
||||
super.key,
|
||||
required this.videoItem,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget videoContent(context) {
|
||||
return Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(10, 0, 6, 0),
|
||||
@@ -157,14 +141,16 @@ class VideoContent extends StatelessWidget {
|
||||
const SizedBox(height: 3),
|
||||
Row(
|
||||
children: [
|
||||
StatView(
|
||||
statView(
|
||||
context: context,
|
||||
theme: 'gray',
|
||||
// view: videoItem.season?['view_content'] ??
|
||||
// videoItem.viewContent,
|
||||
view: videoItem.viewContent,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
StatDanMu(
|
||||
statDanMu(
|
||||
context: context,
|
||||
theme: 'gray',
|
||||
// danmu: videoItem.season?['danmaku'] ?? videoItem.danmaku,
|
||||
danmu: videoItem.danmaku,
|
||||
|
||||
@@ -158,11 +158,7 @@ class VideoCardV extends StatelessWidget {
|
||||
margin: EdgeInsets.zero,
|
||||
child: InkWell(
|
||||
onTap: () async => onPushDetail(heroTag),
|
||||
onLongPress: () {
|
||||
if (longPress != null) {
|
||||
longPress!();
|
||||
}
|
||||
},
|
||||
onLongPress: longPress,
|
||||
child: Column(
|
||||
children: [
|
||||
AspectRatio(
|
||||
@@ -194,7 +190,7 @@ class VideoCardV extends StatelessWidget {
|
||||
);
|
||||
}),
|
||||
),
|
||||
VideoContent(videoItem: videoItem)
|
||||
videoContent(context)
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -211,13 +207,8 @@ class VideoCardV extends StatelessWidget {
|
||||
)),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
class VideoContent extends StatelessWidget {
|
||||
final dynamic videoItem;
|
||||
const VideoContent({super.key, required this.videoItem});
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget videoContent(context) {
|
||||
return Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(6, 5, 6, 5),
|
||||
@@ -241,9 +232,7 @@ class VideoContent extends StatelessWidget {
|
||||
),
|
||||
const Spacer(),
|
||||
// const SizedBox(height: 2),
|
||||
VideoStat(
|
||||
videoItem: videoItem,
|
||||
),
|
||||
videoStat(context),
|
||||
Row(
|
||||
children: [
|
||||
if (videoItem.goto == 'bangumi') ...[
|
||||
@@ -303,28 +292,20 @@ class VideoContent extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class VideoStat extends StatelessWidget {
|
||||
final dynamic videoItem;
|
||||
|
||||
const VideoStat({
|
||||
super.key,
|
||||
required this.videoItem,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget videoStat(context) {
|
||||
return Row(
|
||||
children: [
|
||||
StatView(
|
||||
statView(
|
||||
context: context,
|
||||
theme: 'gray',
|
||||
view: videoItem.stat.view,
|
||||
goto: videoItem.goto,
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
if (videoItem.goto != 'picture')
|
||||
StatDanMu(
|
||||
statDanMu(
|
||||
context: context,
|
||||
theme: 'gray',
|
||||
danmu: videoItem.stat.danmu,
|
||||
),
|
||||
|
||||
@@ -147,11 +147,7 @@ class VideoCardVMemberHome extends StatelessWidget {
|
||||
margin: EdgeInsets.zero,
|
||||
child: InkWell(
|
||||
onTap: () async => onPushDetail(heroTag),
|
||||
onLongPress: () {
|
||||
if (longPress != null) {
|
||||
longPress!();
|
||||
}
|
||||
},
|
||||
onLongPress: longPress,
|
||||
child: Column(
|
||||
children: [
|
||||
AspectRatio(
|
||||
|
||||
Reference in New Issue
Block a user