feat: render more stuff better

This commit is contained in:
Matyáš Caras 2023-04-03 17:07:27 +02:00
parent 27dbbb9221
commit e6989dc264
3 changed files with 178 additions and 16 deletions

View file

@ -9,6 +9,7 @@ import 'package:voyagehandbook/api/classes.dart';
import 'package:voyagehandbook/util/styles.dart';
import 'package:voyagehandbook/util/widgets/warning.dart';
import 'package:html_unescape/html_unescape_small.dart';
import 'package:voyagehandbook/views/pageview.dart';
import 'package:widget_zoom/widget_zoom.dart';
/*
@ -33,8 +34,9 @@ class PageRenderer {
final ColorScheme scheme;
final double height;
final double width;
final BuildContext context;
PageRenderer(this.scheme, this.height, this.width);
PageRenderer(this.scheme, this.height, this.width, this.context);
/// Used to create Widgets from raw HTML from WM API
ListView renderFromPageHTML(RawPage page) {
@ -184,6 +186,9 @@ class PageRenderer {
switch (element.localName) {
case "p":
case "link":
if (element
.getElementsByClassName("mw-kartographer-maplink")
.isNotEmpty) break;
out.add(
RichText(
text: TextSpan(children: _renderText(element.innerHtml)),
@ -207,6 +212,54 @@ class PageRenderer {
case "section":
out.addAll(_renderSection(element));
break;
case "dl":
var dd = element.getElementsByTagName("dd").first;
var link = RegExp(r'<a .+? href="\.\/(.+?)".+?>(.+?)<', dotAll: true)
.firstMatch(dd.innerHtml);
if (link == null) {
break; // TODO: handle `dd` which are not "see also" links
}
out.add(
Row(
children: [
const Text(
"See also:",
style: TextStyle(),
),
const SizedBox(
width: 5,
),
GestureDetector(
onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ArticleView(
pageKey: link.group(1)!, name: link.group(2)!),
),
),
child: Text(
link.group(2)!,
style: const TextStyle(
fontStyle: FontStyle.italic,
decoration: TextDecoration.underline),
),
)
],
),
);
out.add(
const SizedBox(
height: 5,
),
);
break;
case "ul":
out.add(_renderList(element));
out.add(
const SizedBox(
height: 10,
),
);
break;
case "div":
if (element.attributes["class"] != null &&
element.attributes["class"] == "pp_cautionbox") {
@ -277,9 +330,14 @@ class PageRenderer {
height: 10,
),
);
} else if (element.id == "thumbinner") {
var imgs = element.getElementsByTagName("img");
if (imgs.isEmpty) break;
} else if (element.classes.contains("mw-kartographer-container")) {
var imgs = element
.getElementsByTagName("div")
.first
.getElementsByTagName("a")
.first
.getElementsByTagName("img");
if (imgs.isEmpty) break; // load maps that have a static image
var img = imgs[0];
var cap = element.getElementsByClassName("thumbcaption")[0];
out.add(const SizedBox(
@ -296,13 +354,22 @@ class PageRenderer {
),
),
);
out.add(const SizedBox(
height: 3,
));
out.add(Text(cap.text));
out.add(const SizedBox(
height: 10,
));
out.add(
const SizedBox(
height: 3,
),
);
out.add(
Text(
cap.text,
textAlign: TextAlign.center,
),
);
out.add(
const SizedBox(
height: 10,
),
);
}
break;
default:
@ -426,4 +493,91 @@ class PageRenderer {
content.add(TextSpan(text: noFormatting.last)); // add last
return content;
}
final _extraColorsLight = {
"blue": const Color.fromARGB(255, 34, 34, 157),
"red": const Color.fromARGB(255, 152, 33, 33)
};
final _extraColorsDark = {
"blue": const Color.fromARGB(255, 84, 95, 247),
"red": const Color.fromARGB(255, 242, 69, 69)
};
SingleChildScrollView _renderList(dom.Element element) {
var out = <Widget>[];
var i = 0;
for (var item in element.getElementsByTagName("li")) {
i++;
String? title = (item.getElementsByClassName("listing-name").isNotEmpty)
? item.getElementsByClassName("listing-name")[0].text
: null;
Color bubbleColor;
if (item.innerHtml.contains("background: #0000FF")) {
bubbleColor =
(MediaQuery.of(context).platformBrightness == Brightness.dark)
? _extraColorsDark["blue"]!
: _extraColorsLight["blue"]!;
} else if (item.innerHtml.contains("background: #800000")) {
bubbleColor =
(MediaQuery.of(context).platformBrightness == Brightness.dark)
? _extraColorsDark["red"]!
: _extraColorsLight["red"]!;
} else {
bubbleColor = scheme.secondary;
}
var rest = (title != null)
? item.text.replaceAll(item.getElementsByTagName("span")[0].text, "")
: item.text;
out.add(const SizedBox(
height: 5,
));
out.add(
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8), color: bubbleColor),
width: 30,
height: 30,
child: Text(
i.toString(),
style: TextStyle(
color: scheme.background,
fontWeight: FontWeight.bold,
fontSize: 17),
textAlign: TextAlign.center,
),
),
const SizedBox(
width: 10,
),
RichText(
text: TextSpan(
children: [
if (title != null)
TextSpan(
text: title,
style: const TextStyle(fontWeight: FontWeight.bold),
),
TextSpan(text: rest)
],
),
)
],
),
);
}
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: out,
),
);
}
}

View file

@ -95,9 +95,11 @@ class _HomeViewState extends State<HomeView> {
width: MediaQuery.of(context).size.width * 0.9,
height: 50,
child: InkWell(
onTap: () => Navigator.of(context).push(MaterialPageRoute(
builder: (c) =>
ArticleView(pageKey: r["key"], name: r["name"]))),
onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (c) => ArticleView(pageKey: r["key"], name: r["name"]),
),
)..then((_) => load()),
child: Align(
alignment: Alignment.center,
child: Text(

View file

@ -77,8 +77,11 @@ class _ArticleViewState extends State<ArticleView> {
}
void loadPage() async {
var renderer = PageRenderer(Theme.of(context).colorScheme,
MediaQuery.of(context).size.height, MediaQuery.of(context).size.width);
var renderer = PageRenderer(
Theme.of(context).colorScheme,
MediaQuery.of(context).size.height,
MediaQuery.of(context).size.width,
context);
try {
_content = [
SizedBox(
@ -107,5 +110,8 @@ class _ArticleViewState extends State<ArticleView> {
void addToRecents() {
StorageAccess.addToRecents(widget.name, widget.pageKey);
if (kDebugMode) {
print("Added ${widget.name} to recent");
}
}
}