mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
opt: article content
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import 'package:PiliPalaX/common/widgets/network_img_layer.dart';
|
||||
import 'package:PiliPalaX/models/dynamics/article_content_model.dart';
|
||||
import 'package:PiliPalaX/pages/preview/view.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_html/flutter_html.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class ArticleContent extends StatelessWidget {
|
||||
const ArticleContent({
|
||||
@@ -15,22 +15,51 @@ class ArticleContent extends StatelessWidget {
|
||||
|
||||
@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.insert is String) {
|
||||
return SelectableText(
|
||||
(item.insert as String).replaceAll('\n', '\n\n'),
|
||||
style: TextStyle(
|
||||
letterSpacing: 0.3,
|
||||
fontSize: FontSize.large.value,
|
||||
height: LineHeight.percent(125).size,
|
||||
fontWeight:
|
||||
item.attributes?.bold == true ? FontWeight.bold : null,
|
||||
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 ?? '',
|
||||
height: item.line?.pic?.height?.toDouble(),
|
||||
),
|
||||
);
|
||||
} else if (item.attributes?.clazz == 'normal-img') {
|
||||
} else if (item.pic != null) {
|
||||
return LayoutBuilder(
|
||||
builder: (_, constraints) => GestureDetector(
|
||||
onTap: () {
|
||||
@@ -39,8 +68,8 @@ class ArticleContent extends StatelessWidget {
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return ImagePreview(
|
||||
initialPage: 0,
|
||||
imgList: [item.insert.nativeImage?.url],
|
||||
initialPage: imgList.indexOf(item.pic!.pics!.first.url!),
|
||||
imgList: imgList,
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -48,22 +77,12 @@ class ArticleContent extends StatelessWidget {
|
||||
child: NetworkImgLayer(
|
||||
width: constraints.maxWidth,
|
||||
height: constraints.maxWidth *
|
||||
item.insert.nativeImage?.height /
|
||||
item.insert.nativeImage?.width,
|
||||
src: item.insert.nativeImage?.url,
|
||||
item.pic!.pics!.first.height! /
|
||||
item.pic!.pics!.first.width!,
|
||||
src: item.pic!.pics!.first.url,
|
||||
),
|
||||
),
|
||||
);
|
||||
// return image(
|
||||
// constrainedWidth,
|
||||
// [
|
||||
// ImageModel(
|
||||
// width: item.insert.nativeImage?.width,
|
||||
// height: item.insert.nativeImage?.height,
|
||||
// url: item.insert.nativeImage?.url,
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
} else {
|
||||
return const SizedBox.shrink();
|
||||
// return Text('unsupported content');
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:PiliPalaX/common/widgets/article_content.dart';
|
||||
import 'package:PiliPalaX/models/dynamics/article_content_model.dart';
|
||||
import 'package:html/dom.dart';
|
||||
import 'package:html/parser.dart';
|
||||
@@ -116,9 +115,11 @@ class HtmlHttp {
|
||||
final jsonString = match.group(1);
|
||||
if (jsonString != null) {
|
||||
try {
|
||||
opusContent = jsonDecode(jsonString)['readInfo']['content'];
|
||||
dynamic json = jsonDecode(jsonString);
|
||||
opusContent = json['readInfo']['content'];
|
||||
try {
|
||||
opusContent = (jsonDecode(opusContent)['ops'] as List)
|
||||
opusContent = (json['readInfo']?['opus']?['content']
|
||||
?['paragraphs'] as List)
|
||||
.map((item) => ArticleContentModel.fromJson(item))
|
||||
.toList();
|
||||
isJsonContent = true;
|
||||
|
||||
@@ -1,72 +1,218 @@
|
||||
class ArticleContentModel {
|
||||
ArticleContentModel({
|
||||
this.attributes,
|
||||
this.insert,
|
||||
this.paraType,
|
||||
this.text,
|
||||
this.format,
|
||||
this.line,
|
||||
});
|
||||
Attributes? attributes;
|
||||
dynamic insert;
|
||||
int? paraType;
|
||||
Text? text;
|
||||
Format? format;
|
||||
Line? line;
|
||||
Pic? pic;
|
||||
|
||||
ArticleContentModel.fromJson(Map<String, dynamic> json) {
|
||||
attributes = json['attributes'] == null
|
||||
? null
|
||||
: Attributes.fromJson(json['attributes']);
|
||||
insert = json['insert'] == null
|
||||
? null
|
||||
: json['attributes']?['class'] == 'normal-img'
|
||||
? Insert.fromJson(json['insert'])
|
||||
: json['insert'];
|
||||
paraType = json['para_type'];
|
||||
text = json['text'] == null ? null : Text.fromJson(json['text']);
|
||||
format = json['format'] == null ? null : Format.fromJson(json['format']);
|
||||
line = json['line'] == null ? null : Line.fromJson(json['line']);
|
||||
pic = json['pic'] == null ? null : Pic.fromJson(json['pic']);
|
||||
}
|
||||
}
|
||||
|
||||
class Insert {
|
||||
Insert({
|
||||
this.nativeImage,
|
||||
});
|
||||
NativeImage? nativeImage;
|
||||
|
||||
Insert.fromJson(Map<String, dynamic> json) {
|
||||
nativeImage = json['native-image'] == null
|
||||
? null
|
||||
: NativeImage.fromJson(json['native-image']);
|
||||
}
|
||||
}
|
||||
|
||||
class NativeImage {
|
||||
NativeImage({
|
||||
this.alt,
|
||||
class Pic {
|
||||
Pic({
|
||||
this.url,
|
||||
this.width,
|
||||
this.height,
|
||||
this.size,
|
||||
this.status,
|
||||
this.pics,
|
||||
this.style,
|
||||
});
|
||||
String? url;
|
||||
int? width;
|
||||
int? height;
|
||||
double? size;
|
||||
List<Pic>? pics;
|
||||
int? style;
|
||||
|
||||
dynamic alt;
|
||||
dynamic url;
|
||||
dynamic width;
|
||||
dynamic height;
|
||||
dynamic size;
|
||||
dynamic status;
|
||||
|
||||
NativeImage.fromJson(Map<String, dynamic> json) {
|
||||
alt = json['alt'];
|
||||
Pic.fromJson(Map<String, dynamic> json) {
|
||||
url = json['url'];
|
||||
width = json['width'];
|
||||
height = json['height'];
|
||||
size = json['size'];
|
||||
status = json['status'];
|
||||
pics = (json['pics'] as List<dynamic>?)
|
||||
?.map((item) => Pic.fromJson(item))
|
||||
.toList();
|
||||
style = json['style'];
|
||||
}
|
||||
}
|
||||
|
||||
class Attributes {
|
||||
Attributes({
|
||||
this.clazz,
|
||||
class Line {
|
||||
Line({
|
||||
this.pic,
|
||||
});
|
||||
String? clazz;
|
||||
bool? bold;
|
||||
Pic? pic;
|
||||
|
||||
Attributes.fromJson(Map<String, dynamic> json) {
|
||||
clazz = json['class'];
|
||||
bold = json['bold'];
|
||||
Line.fromJson(Map<String, dynamic> json) {
|
||||
pic = json['pic'] == null ? null : Pic.fromJson(json['pic']);
|
||||
}
|
||||
}
|
||||
|
||||
class Format {
|
||||
Format({
|
||||
this.align,
|
||||
});
|
||||
int? align;
|
||||
|
||||
Format.fromJson(Map<String, dynamic> json) {
|
||||
align = json['align'];
|
||||
}
|
||||
}
|
||||
|
||||
class Text {
|
||||
Text({
|
||||
this.nodes,
|
||||
});
|
||||
List<Nodes>? nodes;
|
||||
|
||||
Text.fromJson(Map<String, dynamic> json) {
|
||||
nodes = (json['nodes'] as List<dynamic>?)
|
||||
?.map((item) => Nodes.fromJson(item))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
class Nodes {
|
||||
Nodes({
|
||||
this.nodeType,
|
||||
this.word,
|
||||
});
|
||||
int? nodeType;
|
||||
Word? word;
|
||||
|
||||
Nodes.fromJson(Map<String, dynamic> json) {
|
||||
nodeType = json['node_type'];
|
||||
word = json['word'] == null ? null : Word.fromJson(json['word']);
|
||||
}
|
||||
}
|
||||
|
||||
class Word {
|
||||
Word({
|
||||
this.words,
|
||||
this.fontSize,
|
||||
this.style,
|
||||
this.color,
|
||||
});
|
||||
String? words;
|
||||
int? fontSize;
|
||||
Style? style;
|
||||
String? color;
|
||||
|
||||
Word.fromJson(Map<String, dynamic> json) {
|
||||
words = json['words'];
|
||||
fontSize = json['font_size'];
|
||||
style = json['style'] == null ? null : Style.fromJson(json['style']);
|
||||
color = json['color'];
|
||||
}
|
||||
}
|
||||
|
||||
class Style {
|
||||
Style({
|
||||
this.bold,
|
||||
this.italic,
|
||||
this.strikethrough,
|
||||
});
|
||||
bool? bold;
|
||||
bool? italic;
|
||||
bool? strikethrough;
|
||||
|
||||
Style.fromJson(Map<String, dynamic> json) {
|
||||
bold = json['bold'];
|
||||
italic = json['italic'];
|
||||
strikethrough = json['strikethrough'];
|
||||
}
|
||||
}
|
||||
|
||||
// class ArticleContentModel {
|
||||
// ArticleContentModel({
|
||||
// this.attributes,
|
||||
// this.insert,
|
||||
// });
|
||||
// Attributes? attributes;
|
||||
// dynamic insert;
|
||||
|
||||
// ArticleContentModel.fromJson(Map<String, dynamic> json) {
|
||||
// attributes = json['attributes'] == null
|
||||
// ? null
|
||||
// : Attributes.fromJson(json['attributes']);
|
||||
// insert = json['insert'] == null
|
||||
// ? null
|
||||
// : json['attributes']?['class'] == 'normal-img'
|
||||
// ? Insert.fromJson(json['insert'])
|
||||
// : json['insert'];
|
||||
// }
|
||||
// }
|
||||
|
||||
// class Insert {
|
||||
// Insert({
|
||||
// this.nativeImage,
|
||||
// });
|
||||
// NativeImage? nativeImage;
|
||||
|
||||
// Insert.fromJson(Map<String, dynamic> json) {
|
||||
// nativeImage = json['native-image'] == null
|
||||
// ? null
|
||||
// : NativeImage.fromJson(json['native-image']);
|
||||
// }
|
||||
// }
|
||||
|
||||
// class NativeImage {
|
||||
// NativeImage({
|
||||
// this.alt,
|
||||
// this.url,
|
||||
// this.width,
|
||||
// this.height,
|
||||
// this.size,
|
||||
// this.status,
|
||||
// });
|
||||
|
||||
// dynamic alt;
|
||||
// dynamic url;
|
||||
// dynamic width;
|
||||
// dynamic height;
|
||||
// dynamic size;
|
||||
// dynamic status;
|
||||
|
||||
// NativeImage.fromJson(Map<String, dynamic> json) {
|
||||
// alt = json['alt'];
|
||||
// url = json['url'];
|
||||
// width = json['width'];
|
||||
// height = json['height'];
|
||||
// size = json['size'];
|
||||
// status = json['status'];
|
||||
// }
|
||||
// }
|
||||
|
||||
// class Attributes {
|
||||
// Attributes({
|
||||
// this.clazz,
|
||||
// this.bold,
|
||||
// this.color,
|
||||
// this.italic,
|
||||
// this.strike,
|
||||
// });
|
||||
// String? clazz;
|
||||
// bool? bold;
|
||||
// String? color;
|
||||
// bool? italic;
|
||||
// bool? strike;
|
||||
|
||||
// Attributes.fromJson(Map<String, dynamic> json) {
|
||||
// clazz = json['class'];
|
||||
// bold = json['bold'];
|
||||
// color = json['color'];
|
||||
// italic = json['italic'];
|
||||
// strike = json['strike'];
|
||||
// }
|
||||
// }
|
||||
|
||||
Reference in New Issue
Block a user