From e6989dc264e738b70ee41deadf5962eb7ad58741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maty=C3=A1=C5=A1=20Caras?= Date: Mon, 3 Apr 2023 17:07:27 +0200 Subject: [PATCH] feat: render more stuff better --- lib/util/render.dart | 176 +++++++++++++++++++++++++++++++++++++--- lib/views/home.dart | 8 +- lib/views/pageview.dart | 10 ++- 3 files changed, 178 insertions(+), 16 deletions(-) diff --git a/lib/util/render.dart b/lib/util/render.dart index e0cdc32..e09a830 100644 --- a/lib/util/render.dart +++ b/lib/util/render.dart @@ -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'(.+?)<', 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 = []; + 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, + ), + ); + } } diff --git a/lib/views/home.dart b/lib/views/home.dart index 47a2ec9..f4ef6e8 100644 --- a/lib/views/home.dart +++ b/lib/views/home.dart @@ -95,9 +95,11 @@ class _HomeViewState extends State { 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( diff --git a/lib/views/pageview.dart b/lib/views/pageview.dart index 58cfa32..ee9debe 100644 --- a/lib/views/pageview.dart +++ b/lib/views/pageview.dart @@ -77,8 +77,11 @@ class _ArticleViewState extends State { } 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 { void addToRecents() { StorageAccess.addToRecents(widget.name, widget.pageKey); + if (kDebugMode) { + print("Added ${widget.name} to recent"); + } } }