diff --git a/yuuna/.gitignore b/yuuna/.gitignore index a1345d01..73cdbb58 100644 --- a/yuuna/.gitignore +++ b/yuuna/.gitignore @@ -43,3 +43,6 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release + +# FVM Version Cache +.fvm/ \ No newline at end of file diff --git a/yuuna/lib/src/creator/enhancements/immersion_kit_enhancement.dart b/yuuna/lib/src/creator/enhancements/immersion_kit_enhancement.dart index 604798ae..67a1f2e4 100644 --- a/yuuna/lib/src/creator/enhancements/immersion_kit_enhancement.dart +++ b/yuuna/lib/src/creator/enhancements/immersion_kit_enhancement.dart @@ -26,6 +26,7 @@ class ImmersionKitResult { required this.wordList, required this.wordIndices, required this.calculateRange, + required this.longestExactMatch, }); /// The sentence in plain unformatted form. @@ -48,6 +49,9 @@ class ImmersionKitResult { TextRange? _calculatedRange; + /// How many consecutive characters match the search term exactly + int longestExactMatch; + /// Function to calculate the range of search term TextRange Function() calculateRange; @@ -236,6 +240,26 @@ class ImmersionKitEnhancement extends Enhancement { } } + int _longestExactRangeForResult({ + required List wordIndices, + required List wordList, + required String term, + required String text, + }) { + /// Start at the first character of the given cloze + int textPosition = wordList.sublist(0, wordIndices.first).join().length; + int termPosition = 0; + + while (textPosition < text.length && + termPosition < term.length && + term[termPosition] == text[textPosition]) { + termPosition++; + textPosition++; + } + + return termPosition; + } + /// Search the Massif API for example sentences and return a list of results. Future> searchForSentences({ required AppModel appModel, @@ -290,18 +314,23 @@ class ImmersionKitEnhancement extends Enhancement { String audioUrl = example['sound_url']; ImmersionKitResult result = ImmersionKitResult( - text: text, - source: source, - imageUrl: imageUrl, - audioUrl: audioUrl, - wordList: wordList, - wordIndices: wordIndices, - calculateRange: () => _getRangeFromIndexedList( - wordIndices: wordIndices, + text: text, + source: source, + imageUrl: imageUrl, + audioUrl: audioUrl, wordList: wordList, - term: searchTerm, - ), - ); + wordIndices: wordIndices, + calculateRange: () => _getRangeFromIndexedList( + wordIndices: wordIndices, + wordList: wordList, + term: searchTerm, + ), + longestExactMatch: _longestExactRangeForResult( + wordIndices: wordIndices, + wordList: wordList, + text: text, + term: searchTerm, + )); /// Sentence examples that are merely the word itself are pretty /// redundant. @@ -313,7 +342,7 @@ class ImmersionKitEnhancement extends Enhancement { /// Make sure series aren't too consecutive. results.shuffle(); - /// Results with images come first. + /// Sort by: has image -> has audio -> longest exact match -> shortest sentence results.sort((a, b) { int hasImage = (a.imageUrl.isNotEmpty ? -1 : 1) .compareTo(b.imageUrl.isNotEmpty ? -1 : 1); @@ -329,6 +358,13 @@ class ImmersionKitEnhancement extends Enhancement { return hasAudio; } + /// Sort by longest subterm + int longestMatch = b.longestExactMatch.compareTo(a.longestExactMatch); + + if (longestMatch != 0) { + return longestMatch; + } + return a.text.length.compareTo(b.text.length); }); diff --git a/yuuna/lib/src/creator/enhancements/massif_example_sentences_enhancement.dart b/yuuna/lib/src/creator/enhancements/massif_example_sentences_enhancement.dart index d076847d..769a9330 100644 --- a/yuuna/lib/src/creator/enhancements/massif_example_sentences_enhancement.dart +++ b/yuuna/lib/src/creator/enhancements/massif_example_sentences_enhancement.dart @@ -16,6 +16,7 @@ class MassifResult { required this.range, required this.source, required this.spans, + required this.longestExactMatch, }); /// The sentence in plain unformatted form. @@ -27,6 +28,9 @@ class MassifResult { /// A formatted widget which may contain highlighted text. List spans; + /// How many consecutive characters match the search term exactly + int longestExactMatch; + /// First selected range. TextRange range; @@ -102,6 +106,29 @@ class MassifExampleSentencesEnhancement extends Enhancement { ); } + int _longestExactRangeForResult({ + required int? start, + required String term, + required String text, + }) { + if (start == null) { + return 0; + } + + /// Start at the first character of the given cloze + int textPosition = start; + int termPosition = 0; + + while (textPosition < text.length && + termPosition < term.length && + term[termPosition] == text[textPosition]) { + termPosition++; + textPosition++; + } + + return termPosition; + } + /// Search the Massif API for example sentences and return a list of results. Future> searchForSentences({ required BuildContext context, @@ -209,11 +236,27 @@ class MassifExampleSentencesEnhancement extends Enhancement { } MassifResult result = MassifResult( - text: text, - range: range, - source: source, - spans: spans, - ); + text: text, + range: range, + source: source, + spans: spans, + longestExactMatch: _longestExactRangeForResult( + start: start, + term: searchTerm, + text: text, + )); + + /// Sort by: longest exact match -> shortest sentence + results.sort((a, b) { + /// Sort by longest subterm + int longestMatch = b.longestExactMatch.compareTo(a.longestExactMatch); + + if (longestMatch != 0) { + return longestMatch; + } + + return a.text.length.compareTo(b.text.length); + }); results.add(result); } diff --git a/yuuna/lib/src/dictionary/dictionary_entry.dart b/yuuna/lib/src/dictionary/dictionary_entry.dart index e29fba24..3f78dc18 100644 --- a/yuuna/lib/src/dictionary/dictionary_entry.dart +++ b/yuuna/lib/src/dictionary/dictionary_entry.dart @@ -61,6 +61,8 @@ class DictionaryEntry { @Index() final double popularity; + /// TODO: Add deflection + /// Returns all definitions bullet pointed if multiple, and returns the /// single definition if otherwise. String get compactDefinitions { diff --git a/yuuna/lib/src/dictionary/formats/yomichan_dictionary_format.dart b/yuuna/lib/src/dictionary/formats/yomichan_dictionary_format.dart index f5613e50..d15e2ddc 100644 --- a/yuuna/lib/src/dictionary/formats/yomichan_dictionary_format.dart +++ b/yuuna/lib/src/dictionary/formats/yomichan_dictionary_format.dart @@ -2,12 +2,10 @@ import 'dart:convert'; import 'dart:io'; import 'package:async_zip/async_zip.dart'; -import 'package:beautiful_soup_dart/beautiful_soup.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:html/dom.dart' as dom; import 'package:isar/isar.dart'; -import 'package:list_counter/list_counter.dart'; import 'package:path/path.dart' as path; import 'package:recase/recase.dart'; import 'package:yuuna/dictionary.dart'; @@ -56,32 +54,95 @@ class YomichanFormat extends DictionaryFormat { @override String getCustomDefinitionText(String meaning) { - final node = - StructuredContent.processContent(jsonDecode(meaning))?.toNode(); - if (node == null) { - return ''; - } + final mainBuffer = StringBuffer(); + final currentLineBuffer = StringBuffer(); + int indentationLevel = 0; + final node = StructuredContent.processContent(jsonDecode(meaning)); final document = dom.Document.html(''); document.body?.append(node); - for (final e in document.querySelectorAll('li')) { - final css = e.bs4.findParent('ul')?.attributes['style'] ?? ''; - final text = e.text; - final name = css - .split(';') - .firstWhere((e) => e.contains('list-style-type')) - .split(':') - .lastOrNull ?? - 'square'; - - final counterStyle = CounterStyleRegistry.lookup(name); - final counter = counterStyle.generateMarkerContent(0); - e.text = '$counter $text'; + + /// Remove tables and attributions + document.querySelectorAll('div > a, rt').forEach((e) => e.remove()); + + String getIndentation() { + return ' ' * indentationLevel; + } + + void flushBuffer() { + if (currentLineBuffer.isNotEmpty) { + mainBuffer.writeln('${getIndentation()}${currentLineBuffer.toString().trim()}'); + currentLineBuffer.clear(); + } + } + + /// Attempt at making plaintext as close to structured HTML as possible + /// 1. Handle lists and list items with proper indentation and bullets + /// 2. Process ruby tags without breaking lines to keep Japanese text + /// together + /// 3. Accumulate text nodes in the current line buffer + /// 4. Recursively process child nodes + /// 5. Flush the buffer at the end of block-level elements, except within + /// ruby tags + /// - Note: It flushes prematurely upon encountering highlighted span tags + /// within ruby tags, but it shouldn't be too big of a problem since + /// highlighted span tags are rare. + void processNode(dom.Node node, {bool inRuby = false}) { + if (node is dom.Element) { + if (node.localName == 'ul' || node.localName == 'ol') { + /// Start a new line for lists to maintain structure + flushBuffer(); + indentationLevel++; + for (var child in node.children) { + processNode(child); + } + indentationLevel--; + } else if (node.localName == 'li') { + /// Format list items with proper indentation and bullets + flushBuffer(); + currentLineBuffer.write(getIndentation()); + currentLineBuffer.write(indentationLevel > 1 ? '- ' : '• '); + for (var child in node.nodes) { + processNode(child); + } + flushBuffer(); + } else if (node.localName == 'ruby') { + /// Process ruby tags without breaking the line to keep Japanese text together + for (var child in node.nodes) { + processNode(child, inRuby: true); + } + } else { + /// Recursively process other elements + for (var child in node.nodes) { + processNode(child, inRuby: inRuby); + } + } + } else if (node is dom.Text) { + /// Add non-empty text to the current line + String text = node.text.trim(); + if (text.isNotEmpty) { + currentLineBuffer.write(text); + } + } + + /// End the current line after block-level elements, but not within ruby tags + /// This keeps inline elements together while separating block-level content + if (!inRuby && node.parent != null && + node == node.parent!.nodes.last && + node.parent!.localName != 'ul' && + node.parent!.localName != 'li' && + node.parent!.localName != 'ruby') { + flushBuffer(); + } + } + + /// Process the entire body to generate the full definition text + for (var child in document.body!.nodes) { + processNode(child); } - document.querySelectorAll('table').map((e) => e.remove()); - final html = document.body?.innerHtml ?? ''; - return BeautifulSoup(html).getText(separator: '\n'); + /// Trim any extra whitespace from the final output + return mainBuffer.toString().trim(); } /// Recursively get HTML for a structured content definition. @@ -269,10 +330,12 @@ void prepareEntriesYomichanFormat({ isar.dictionaryHeadings.putSync(heading); n++; - params.send(t.import_write_entry( - count: n, - total: total, - )); + if (n % 1000 == 0) { + params.send(t.import_write_entry( + count: n, + total: total, + )); + } } } else if (filename.startsWith('kanji_bank')) { List items = jsonDecode(file.readAsStringSync()); @@ -341,10 +404,12 @@ void prepareEntriesYomichanFormat({ isar.dictionaryHeadings.putSync(heading); n++; - params.send(t.import_write_entry( - count: n, - total: total, - )); + if (n % 1000 == 0) { + params.send(t.import_write_entry( + count: n, + total: total, + )); + } } } } diff --git a/yuuna/lib/src/dictionary/structured_content.dart b/yuuna/lib/src/dictionary/structured_content.dart index 2ca458d5..73bee1c3 100644 --- a/yuuna/lib/src/dictionary/structured_content.dart +++ b/yuuna/lib/src/dictionary/structured_content.dart @@ -1,211 +1,153 @@ -import 'package:dart_mappable/dart_mappable.dart'; import 'package:flutter_html/flutter_html.dart'; import 'package:html/dom.dart' as dom; -part 'structured_content.mapper.dart'; - -/// Used for handling nested content when decoding [StructuredContent]. -class ContentHook extends MappingHook { - /// Initialise this object. - const ContentHook(); - - @override - Object? beforeDecode(Object? value) { - if (value is String) { - return StructuredContentTextNode(text: value); - } else if (value is List) { - return StructuredContentChildContent( - children: value - .map(StructuredContent.processContent) - .whereType() - .toList(), - ); - } - - return value; +/// Helper class for processing Yomitan JSON structured content. +class StructuredContent { + /// Processes a JSON structured content object and returns a DOM node. + static dom.Node processContent(dynamic json) { + return _buildNode(json); } -} - -/// Wraps around all types of possible structured content. -@MappableClass(generateMethods: GenerateMethods.decode) -sealed class StructuredContent with StructuredContentMappable { - /// Initialise this object. - const StructuredContent({this.content}); - @MappableField(hook: ContentHook()) - - /// Nested content. - final StructuredContent? content; - - /// Handles nested content. - static StructuredContent? processContent(var content) { + static dom.Node _buildNode(dynamic content) { if (content is String) { - return StructuredContentTextNode(text: content); + return dom.Text(content); } else if (content is List) { - return StructuredContentChildContent( - children: content - .map(processContent) - .whereType() - .toList()); + final fragment = dom.DocumentFragment(); + for (var item in content) { + fragment.append(_buildNode(item)); + } + return fragment; } else if (content is Map) { - return StructuredContentMapper.fromMap(content); + return _createStructuredContentGenericElement(content); } - - return null; + return dom.Text(''); } - /// Convert this to a valid HTML node. - dom.Node toNode(); -} + static dom.Node _createStructuredContentGenericElement( + Map content) { + final tag = content['tag'] as String?; + if (tag == null) { + return dom.Text(''); + } -/// Represents a text node. -@MappableClass( - discriminatorValue: StructuredContentTextNode.checkType, -) -class StructuredContentTextNode extends StructuredContent - with StructuredContentTextNodeMappable { - /// Initialise this object. - const StructuredContentTextNode({required this.text}); - - /// Text for this node. - final String text; - - @override - dom.Node toNode() { - return dom.Text(text); + switch (tag) { + case 'br': + return _createStructuredContentElement( + tag, content, 'simple', false, false); + case 'ruby': + case 'rt': + case 'rp': + return _createStructuredContentElement( + tag, content, 'simple', true, false); + case 'table': + return _createStructuredContentTableElement(tag, content); + case 'thead': + case 'tbody': + case 'tfoot': + case 'tr': + return _createStructuredContentElement( + tag, content, 'table', true, false); + case 'th': + case 'td': + return _createStructuredContentElement( + tag, content, 'table-cell', true, true); + case 'div': + case 'span': + case 'ol': + case 'ul': + case 'li': + case 'details': + case 'summary': + return _createStructuredContentElement( + tag, content, 'simple', true, true); + case 'a': + return _createLinkElement(content); + case 'img': + return _createImageElement(content); + default: + return dom.Text(''); + } } - /// Discriminator logic. - static bool checkType(value) { - return value is Map && value['text'] != null; + static dom.Element _createStructuredContentTableElement( + String tag, Map content) { + final container = dom.Element.tag('div') + ..classes.add('gloss-sc-table-container'); + final table = + _createStructuredContentElement(tag, content, 'table', true, false); + container.append(table); + return container; } -} -/// An array of child content. -@MappableClass(discriminatorValue: StructuredContentChildContent.checkType) -class StructuredContentChildContent extends StructuredContent - with StructuredContentChildContentMappable { - /// Initialise this object. - const StructuredContentChildContent({required this.children}); - - /// Children to show. - final List children; - - @override - dom.Node toNode() { - final node = dom.Element.tag('div'); - for (final child in children) { - node.nodes.add(child.toNode()); + static dom.Element _createStructuredContentElement( + String tag, + Map content, + String type, + bool hasChildren, + bool hasStyle, + ) { + final node = dom.Element.tag(tag)..classes.add('gloss-sc-$tag'); + + _setAttributes(node, content); + + if (type == 'table-cell') { + if (content['colSpan'] != null) { + node.attributes['colspan'] = content['colSpan'].toString(); + } + if (content['rowSpan'] != null) { + node.attributes['rowspan'] = content['rowSpan'].toString(); + } } - return node; - } - - /// Discriminator logic. - static bool checkType(value) { - return value is List; - } -} + if (hasStyle && content['style'] != null) { + node.attributes['style'] = + _createStyle(content['style'] as Map); + } -/// Represents a line break tag. -@MappableClass(discriminatorValue: StructuredContentLineBreak.checkType) -class StructuredContentLineBreak extends StructuredContent - with StructuredContentLineBreakMappable { - /// Initialise this object. - StructuredContentLineBreak(); + if (hasChildren) { + _appendStructuredContent(node, content['content']); + } - @override - dom.Node toNode() { - return dom.Element.tag('br'); + return node; } - /// Discriminator logic. - static bool checkType(value) { - return value is Map && value['tag'] == 'br'; + static dom.Element _createLinkElement(Map content) { + final node = dom.Element.tag('a'); + if (content['href'] != null) { + node.attributes['href'] = content['href']; + } + _setAttributes(node, content); + _appendStructuredContent(node, content['content']); + return node; } -} -/// Represents an image tag. -@MappableClass(discriminatorValue: StructuredContentImage.checkType) -class StructuredContentImage extends StructuredContent - with StructuredContentImageMappable { - /// Initialise this object. - const StructuredContentImage({ - required this.path, - this.width, - this.height, - this.title, - this.description, - this.pixelated = false, - this.imageRendering = 'auto', - this.appearance = 'auto', - this.background = true, - this.collapsed = false, - this.collapsible = true, - this.verticalAlign, - this.sizeUnits, - }); - - /// Path to the image file in the archive. - final String path; - - /// Preferred width of the image. - final double? width; - - /// Preferred height of the image. - final double? height; - - /// Hover text for the image. - final String? title; - - /// Description of the image. - final String? description; - - /// Whether or not the image should appear pixelated at sizes larger than - /// the image's native resolution. - final bool pixelated; - - /// Controls how the image is rendered. The value of this field supersedes - /// the pixelated field. - final String imageRendering; - - /// Controls the appearance of the image. The "monochrome" value will mask - /// the opaque parts of the image using the current text color. - final String appearance; - - /// Whether or not a background color is displayed behind the image. - final bool background; - - /// Whether or not the image is collapsed by default. - final bool collapsed; - - /// Whether or not the image can be collapsed. - final bool collapsible; - - /// The vertical alignment of the image. - final String? verticalAlign; - - /// The units for the width and height. - final String? sizeUnits; - - @override - dom.Node toNode() { + static dom.Node _createImageElement(Map content) { final imageNode = dom.Element.tag('img'); + final path = content['path'] as String?; + if (path == null) { + return dom.Text(''); + } + final srcAttr = 'jidoujisho://$path'; - final widthAttr = (width != null) ? '$width${sizeUnits ?? ''}' : null; - final heightAttr = (height != null) ? '$height${sizeUnits ?? ''}' : null; - final altAttr = description; - - imageNode.attributes.addAll( - { - 'src': srcAttr, - if (altAttr != null) 'alt': altAttr, - if (widthAttr != null) 'width': widthAttr, - if (heightAttr != null) 'height': heightAttr, - }, - ); + final widthAttr = content['width'] != null + ? '${content['width']}${content['sizeUnits'] ?? ''}' + : null; + final heightAttr = content['height'] != null + ? '${content['height']}${content['sizeUnits'] ?? ''}' + : null; + final altAttr = content['description'] as String?; + + imageNode.attributes.addAll({ + 'src': srcAttr, + if (altAttr != null) 'alt': altAttr, + if (widthAttr != null) 'width': widthAttr, + if (heightAttr != null) 'height': heightAttr, + }); + + _setAttributes(imageNode, content); + final title = content['title'] as String?; if (title == null) { return imageNode; } else { @@ -221,322 +163,154 @@ class StructuredContentImage extends StructuredContent } } - /// Discriminator logic. - static bool checkType(value) { - return value is Map && (value['tag'] == 'img' || value['type'] == 'image'); - } -} - -/// Represents an image tag. -@MappableClass(discriminatorValue: StructuredContentLink.checkType) -class StructuredContentLink extends StructuredContent - with StructuredContentLinkMappable { - /// Initialise this object. - const StructuredContentLink({ - required this.href, - super.content, - this.lang, - }); - - /// The URL for the link. URLs starting with a ? are treated as internal - /// links to other dictionary content. - final String href; - - /// Defines the language of an element in the format defined by RFC 5646. - final String? lang; - - @override - dom.Node toNode() { - final linkNode = dom.Element.tag('a'); - - linkNode.attributes.addAll( - { - 'href': href, - if (lang != null) 'lang': lang!, - }, - ); - - if (content != null) { - linkNode.append(content!.toNode()); + // static dom.Node _createImageElement(Map content) { + // final imageNode = dom.Element.tag('img'); + // final path = content['path'] as String?; + // if (path == null) return dom.Text(''); + // + // final srcAttr = 'jidoujisho://$path'; + // final widthAttr = (width != null) ? '$width${sizeUnits ?? ''}' : null; + // final heightAttr = (height != null) ? '$height${sizeUnits ?? ''}' : null; + // final altAttr = content['description'] as String?; + // + // imageNode.attributes.addAll({ + // 'src': srcAttr, + // if (altAttr != null) 'alt': altAttr, + // if (widthAttr != null) 'width': widthAttr, + // if (heightAttr != null) 'height': heightAttr, + // }); + // + // _setAttributes(imageNode, content); + // + // final title = content['title'] as String?; + // if (title == null) { + // return imageNode; + // } else { + // final figureNode = dom.Element.tag('figure'); + // final figcaptionNode = dom.Element.tag('figcaption')..append(dom.Text(title)); + // + // figureNode + // ..append(imageNode) + // ..append(figcaptionNode); + // + // if (content['collapsible'] == true) { + // _makeCollapsible(figureNode, content['collapsed'] == true); + // } + // + // return figureNode; + // } + // } + + static void _setAttributes( + dom.Element element, Map content) { + if (content['lang'] != null) { + element.attributes['lang'] = content['lang']; } - - return linkNode; - } - - /// Discriminator logic. - static bool checkType(value) { - return value is Map && (value['tag'] == 'a'); - } -} - -/// Generic container tags. -@MappableClass(discriminatorValue: StructuredContentContainer.checkType) -class StructuredContentContainer extends StructuredContent - with StructuredContentContainerMappable { - /// Initialise this object. - const StructuredContentContainer({ - required this.tag, - super.content, - this.data, - this.lang, - }); - - /// [tag] must match one of these tags. - static List validTags = [ - 'ruby', - 'rt', - 'rp', - 'table', - 'thead', - 'tbody', - 'tfoot', - 'tr', - ]; - - /// Tag name. Must be any of the [validTags]. - final String tag; - - /// Additional attributes. - final Map? data; - - /// Defines the language of an element in the format defined by RFC 5646. - final String? lang; - - @override - dom.Node toNode() { - final containerNode = dom.Element.tag(tag); - - containerNode.attributes.addAll({ - if (data != null) ...data!, - if (lang != null) 'lang': lang!, - }); - - if (content != null) { - containerNode.append(content!.toNode()); + if (content['data'] is Map) { + final data = content['data'] as Map; + element.attributes.addAll( + data.map((key, value) => MapEntry('data-sc-$key', value.toString()))); + } + if (content['title'] != null) { + element.attributes['title'] = content['title']; } - - return containerNode; - } - - /// Discriminator logic. - static bool checkType(value) { - return value is Map && validTags.contains(value['tag']); } -} - -/// Stylable generic container tags. -@MappableClass(discriminatorValue: StructuredContentStyledContainer.checkType) -class StructuredContentStyledContainer extends StructuredContent - with StructuredContentStyledContainerMappable { - /// Initialise this object. - const StructuredContentStyledContainer({ - required this.tag, - super.content, - this.style, - this.data, - this.lang, - }); - - /// [tag] must match one of these tags. - static List validTags = [ - 'span', - 'div', - 'ol', - 'ul', - 'li', - ]; - - /// Tag name. Must be any of the [validTags]. - final String tag; - - /// Style for this container. - final StructuredContentStyle? style; - - /// Additional attributes. - final Map? data; - - /// Defines the language of an element in the format defined by RFC 5646. - final String? lang; - - @override - dom.Node toNode() { - final containerNode = dom.Element.tag(tag); - - containerNode.attributes.addAll({ - if (data != null) ...data!, - if (lang != null) 'lang': lang!, - if (style != null) 'style': style!.toInlineStyle() - }); + static void _appendStructuredContent(dom.Element node, dynamic content) { if (content != null) { - containerNode.append(content!.toNode()); + node.append(_buildNode(content)); } - - return containerNode; } - /// Discriminator logic. - static bool checkType(value) { - return value is Map && validTags.contains(value['tag']); - } -} - -/// Table tags. -@MappableClass(discriminatorValue: StructuredContentTableElement.checkType) -class StructuredContentTableElement extends StructuredContent - with StructuredContentTableElementMappable { - /// Initialise this object. - const StructuredContentTableElement({ - required this.tag, - super.content, - this.style, - this.data, - this.colSpan, - this.rowSpan, - this.lang, - }); - - /// [tag] must match one of these tags. - static List validTags = [ - 'td', - 'th', - ]; - - /// Tag name. Must be any of the [validTags]. - final String tag; - - /// Style for this node. - final StructuredContentStyle? style; - - /// Additional attributes. - final Map? data; - - /// Column span. - final int? colSpan; - - /// Row span. - final int? rowSpan; - - /// Defines the language of an element in the format defined by RFC 5646. - final String? lang; - - @override - dom.Node toNode() { - final node = dom.Element.tag(tag); - - node.attributes.addAll({ - if (data != null) ...data!, - if (lang != null) 'lang': lang!, - if (style != null) 'style': style!.toInlineStyle(), - if (colSpan != null) 'colspan': colSpan!.toString(), - if (rowSpan != null) 'rowSpan': rowSpan!.toString(), - }); + static String _createStyle(Map style) { + final styleAttributes = []; - if (content != null) { - node.append(content!.toNode()); + void addIfPresent(String cssProperty, String jsonKey) { + if (style[jsonKey] != null) { + styleAttributes.add('$cssProperty: ${style[jsonKey]}'); + } } - return node; - } + void addMarginPadding(String cssProperty, String jsonKey) { + if (style[jsonKey] is num || style[jsonKey] is String) { + styleAttributes.add('$cssProperty: ${style[jsonKey]}'); + } + } - /// Discriminator logic. - static bool checkType(value) { - return value is Map && validTags.contains(value['tag']); - } -} + List validListStyleTypes = + ListStyleType.values.map((e) => e.counterStyle).toList(); + List validTextDecorationStyles = [ + 'solid', + 'double', + 'dotted', + 'dashed', + 'wavy' + ]; + List validTextDecorationLines = [ + 'none', + 'underline', + 'overline', + 'line-through' + ]; + + addIfPresent('font-size', 'fontSize'); + addIfPresent('font-weight', 'fontWeight'); + addIfPresent('color', 'color'); + addIfPresent('background-color', 'backgroundColor'); + addIfPresent('text-align', 'textAlign'); + addIfPresent('vertical-align', 'verticalAlign'); + addIfPresent('white-space', 'whiteSpace'); + + addIfPresent('margin', 'margin'); + addMarginPadding('margin-top', 'marginTop'); + addMarginPadding('margin-right', 'marginRight'); + addMarginPadding('margin-bottom', 'marginBottom'); + addMarginPadding('margin-left', 'marginLeft'); + + addIfPresent('padding', 'padding'); + addMarginPadding('padding-top', 'paddingTop'); + addMarginPadding('padding-right', 'paddingRight'); + addMarginPadding('padding-bottom', 'paddingBottom'); + addMarginPadding('padding-left', 'paddingLeft'); + + if (style['textDecorationLine'] != null) { + final tdl = style['textDecorationLine']; + if (tdl is String && validTextDecorationLines.contains(tdl)) { + styleAttributes.add('text-decoration-line: $tdl'); + } else if (tdl is List) { + final validValues = tdl + .whereType() + .where(validTextDecorationLines.contains) + .toList(); + if (validValues.isNotEmpty) { + styleAttributes.add('text-decoration-line: ${validValues.join(' ')}'); + } + } + } -/// Used to resolve [StructuredContentStyle.textDecorationLine] which can be -/// a [List] or a [String]. -class TextDecorationLineHooker extends MappingHook { - /// Initialise this object. - const TextDecorationLineHooker(); + if (style['textDecorationStyle'] is String) { + final textDecorationStyle = style['textDecorationStyle']; + if (validTextDecorationStyles.contains(textDecorationStyle)) { + styleAttributes.add('text-decoration-style: $textDecorationStyle'); + } + } - @override - Object? beforeDecode(Object? value) { - if (value is String) { - return [value]; + if (style['listStyleType'] is String) { + final listStyleType = style['listStyleType']; + if (listStyleType == 'disc' || + !validListStyleTypes.contains(listStyleType)) { + styleAttributes.add('list-style-type: square'); + } else { + styleAttributes.add('list-style-type: $listStyleType'); + } } - return value; - } -} + /// text-emphasis is not supported by flutter_html, so let's just underline + /// instead + if (style['textEmphasis'] is String) { + styleAttributes.add('text-decoration-line: underline'); + } -/// Style for a [StructuredContent]. -@MappableClass() -class StructuredContentStyle with StructuredContentStyleMappable { - /// Initialise this object. - const StructuredContentStyle({ - this.fontStyle = 'normal', - this.fontWeight = 'normal', - this.fontSize = 'medium', - this.textDecorationLine = const [], - this.verticalAlign = 'baseline', - this.textAlign = 'start', - this.marginTop = 0, - this.marginLeft = 0, - this.marginRight = 0, - this.marginBottom = 0, - this.listStyleType = 'disc', - }); - - /// Valid list types. - static List validListStyleTypes = - ListStyleType.values.map((e) => e.counterStyle).toList(); - - /// Equivalent to 'font-style'. - final String fontStyle; - - /// Equivalent to 'font-weight'. - final String fontWeight; - - /// Equivalent to 'font-size'. - final String fontSize; - - /// Equivalent to 'text-decoration-line'. - @MappableField(hook: TextDecorationLineHooker()) - final List textDecorationLine; - - /// Equivalent to 'vertical-align'. - final String verticalAlign; - - /// Equivalent to 'text-align'. - final String textAlign; - - /// Equivalent to 'margin-top'. - final double marginTop; - - /// Equivalent to 'margin-left'. - final double marginLeft; - - /// Equivalent to 'margin-right'. - final double marginRight; - - /// Equivalent to 'margin-bottom'. - final double marginBottom; - - /// Equivalent to 'list-style-type'. - final String listStyleType; - - /// Convert this into a usable data map. - String toInlineStyle() { - final attributes = { - 'font-style': fontStyle, - 'font-weight': fontWeight, - 'font-size': fontSize, - 'text-decoration-line': textDecorationLine.join(' '), - 'vertical-align': verticalAlign, - 'text-align': textAlign, - 'margin-top': marginTop.toString(), - 'margin-left': marginLeft.toString(), - 'margin-right': marginRight.toString(), - 'margin-bottom': marginBottom.toString(), - 'list-style-type': listStyleType == 'disc' || - (!validListStyleTypes.contains(listStyleType)) - ? 'square' - : listStyleType - }; - - final style = attributes.entries.map((e) => '${e.key}:${e.value};').join(); - return style; + return styleAttributes.join('; '); } } diff --git a/yuuna/lib/src/dictionary/structured_content.mapper.dart b/yuuna/lib/src/dictionary/structured_content.mapper.dart deleted file mode 100644 index f81325cc..00000000 --- a/yuuna/lib/src/dictionary/structured_content.mapper.dart +++ /dev/null @@ -1,1626 +0,0 @@ -// coverage:ignore-file -// GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint -// ignore_for_file: unused_element - -part of 'structured_content.dart'; - -class StructuredContentMapper extends ClassMapperBase { - StructuredContentMapper._(); - - static StructuredContentMapper? _instance; - static StructuredContentMapper ensureInitialized() { - if (_instance == null) { - MapperContainer.globals.use(_instance = StructuredContentMapper._()); - StructuredContentTextNodeMapper.ensureInitialized(); - StructuredContentChildContentMapper.ensureInitialized(); - StructuredContentLineBreakMapper.ensureInitialized(); - StructuredContentImageMapper.ensureInitialized(); - StructuredContentLinkMapper.ensureInitialized(); - StructuredContentContainerMapper.ensureInitialized(); - StructuredContentStyledContainerMapper.ensureInitialized(); - StructuredContentTableElementMapper.ensureInitialized(); - StructuredContentMapper.ensureInitialized(); - } - return _instance!; - } - - @override - final String id = 'StructuredContent'; - - static StructuredContent? _$content(StructuredContent v) => v.content; - static const Field _f$content = - Field('content', _$content, opt: true, hook: ContentHook()); - - @override - final Map> fields = const { - #content: _f$content, - }; - - static StructuredContent _instantiate(DecodingData data) { - throw MapperException.missingConstructor('StructuredContent'); - } - - @override - final Function instantiate = _instantiate; - - static StructuredContent fromMap(Map map) { - return ensureInitialized().decodeMap(map); - } - - static StructuredContent fromJson(String json) { - return ensureInitialized().decodeJson(json); - } -} - -mixin StructuredContentMappable {} - -class StructuredContentTextNodeMapper - extends SubClassMapperBase { - StructuredContentTextNodeMapper._(); - - static StructuredContentTextNodeMapper? _instance; - static StructuredContentTextNodeMapper ensureInitialized() { - if (_instance == null) { - MapperContainer.globals - .use(_instance = StructuredContentTextNodeMapper._()); - StructuredContentMapper.ensureInitialized().addSubMapper(_instance!); - } - return _instance!; - } - - @override - final String id = 'StructuredContentTextNode'; - - static String _$text(StructuredContentTextNode v) => v.text; - static const Field _f$text = - Field('text', _$text); - static StructuredContent? _$content(StructuredContentTextNode v) => v.content; - static const Field _f$content = - Field('content', _$content, hook: ContentHook()); - - @override - final Map> fields = const { - #text: _f$text, - #content: _f$content, - }; - - @override - final String discriminatorKey = 'type'; - @override - final dynamic discriminatorValue = StructuredContentTextNode.checkType; - @override - late final ClassMapperBase superMapper = - StructuredContentMapper.ensureInitialized(); - - static StructuredContentTextNode _instantiate(DecodingData data) { - return StructuredContentTextNode(text: data.dec(_f$text)); - } - - @override - final Function instantiate = _instantiate; - - static StructuredContentTextNode fromMap(Map map) { - return ensureInitialized().decodeMap(map); - } - - static StructuredContentTextNode fromJson(String json) { - return ensureInitialized().decodeJson(json); - } -} - -mixin StructuredContentTextNodeMappable { - String toJson() { - return StructuredContentTextNodeMapper.ensureInitialized() - .encodeJson( - this as StructuredContentTextNode); - } - - Map toMap() { - return StructuredContentTextNodeMapper.ensureInitialized() - .encodeMap( - this as StructuredContentTextNode); - } - - StructuredContentTextNodeCopyWith - get copyWith => _StructuredContentTextNodeCopyWithImpl( - this as StructuredContentTextNode, $identity, $identity); - @override - String toString() { - return StructuredContentTextNodeMapper.ensureInitialized() - .stringifyValue(this as StructuredContentTextNode); - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (runtimeType == other.runtimeType && - StructuredContentTextNodeMapper.ensureInitialized() - .isValueEqual(this as StructuredContentTextNode, other)); - } - - @override - int get hashCode { - return StructuredContentTextNodeMapper.ensureInitialized() - .hashValue(this as StructuredContentTextNode); - } -} - -extension StructuredContentTextNodeValueCopy<$R, $Out> - on ObjectCopyWith<$R, StructuredContentTextNode, $Out> { - StructuredContentTextNodeCopyWith<$R, StructuredContentTextNode, $Out> - get $asStructuredContentTextNode => $base - .as((v, t, t2) => _StructuredContentTextNodeCopyWithImpl(v, t, t2)); -} - -abstract class StructuredContentTextNodeCopyWith< - $R, - $In extends StructuredContentTextNode, - $Out> implements ClassCopyWith<$R, $In, $Out> { - $R call({String? text}); - StructuredContentTextNodeCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( - Then<$Out2, $R2> t); -} - -class _StructuredContentTextNodeCopyWithImpl<$R, $Out> - extends ClassCopyWithBase<$R, StructuredContentTextNode, $Out> - implements - StructuredContentTextNodeCopyWith<$R, StructuredContentTextNode, $Out> { - _StructuredContentTextNodeCopyWithImpl(super.value, super.then, super.then2); - - @override - late final ClassMapperBase $mapper = - StructuredContentTextNodeMapper.ensureInitialized(); - @override - $R call({String? text}) => - $apply(FieldCopyWithData({if (text != null) #text: text})); - @override - StructuredContentTextNode $make(CopyWithData data) => - StructuredContentTextNode(text: data.get(#text, or: $value.text)); - - @override - StructuredContentTextNodeCopyWith<$R2, StructuredContentTextNode, $Out2> - $chain<$R2, $Out2>(Then<$Out2, $R2> t) => - _StructuredContentTextNodeCopyWithImpl($value, $cast, t); -} - -class StructuredContentChildContentMapper - extends SubClassMapperBase { - StructuredContentChildContentMapper._(); - - static StructuredContentChildContentMapper? _instance; - static StructuredContentChildContentMapper ensureInitialized() { - if (_instance == null) { - MapperContainer.globals - .use(_instance = StructuredContentChildContentMapper._()); - StructuredContentMapper.ensureInitialized().addSubMapper(_instance!); - StructuredContentMapper.ensureInitialized(); - } - return _instance!; - } - - @override - final String id = 'StructuredContentChildContent'; - - static List _$children(StructuredContentChildContent v) => - v.children; - static const Field> - _f$children = Field('children', _$children); - static StructuredContent? _$content(StructuredContentChildContent v) => - v.content; - static const Field - _f$content = Field('content', _$content, hook: ContentHook()); - - @override - final Map> fields = - const { - #children: _f$children, - #content: _f$content, - }; - - @override - final String discriminatorKey = 'type'; - @override - final dynamic discriminatorValue = StructuredContentChildContent.checkType; - @override - late final ClassMapperBase superMapper = - StructuredContentMapper.ensureInitialized(); - - static StructuredContentChildContent _instantiate(DecodingData data) { - return StructuredContentChildContent(children: data.dec(_f$children)); - } - - @override - final Function instantiate = _instantiate; - - static StructuredContentChildContent fromMap(Map map) { - return ensureInitialized().decodeMap(map); - } - - static StructuredContentChildContent fromJson(String json) { - return ensureInitialized().decodeJson(json); - } -} - -mixin StructuredContentChildContentMappable { - String toJson() { - return StructuredContentChildContentMapper.ensureInitialized() - .encodeJson( - this as StructuredContentChildContent); - } - - Map toMap() { - return StructuredContentChildContentMapper.ensureInitialized() - .encodeMap( - this as StructuredContentChildContent); - } - - StructuredContentChildContentCopyWith - get copyWith => _StructuredContentChildContentCopyWithImpl( - this as StructuredContentChildContent, $identity, $identity); - @override - String toString() { - return StructuredContentChildContentMapper.ensureInitialized() - .stringifyValue(this as StructuredContentChildContent); - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (runtimeType == other.runtimeType && - StructuredContentChildContentMapper.ensureInitialized() - .isValueEqual(this as StructuredContentChildContent, other)); - } - - @override - int get hashCode { - return StructuredContentChildContentMapper.ensureInitialized() - .hashValue(this as StructuredContentChildContent); - } -} - -extension StructuredContentChildContentValueCopy<$R, $Out> - on ObjectCopyWith<$R, StructuredContentChildContent, $Out> { - StructuredContentChildContentCopyWith<$R, StructuredContentChildContent, $Out> - get $asStructuredContentChildContent => $base.as( - (v, t, t2) => _StructuredContentChildContentCopyWithImpl(v, t, t2)); -} - -abstract class StructuredContentChildContentCopyWith< - $R, - $In extends StructuredContentChildContent, - $Out> implements ClassCopyWith<$R, $In, $Out> { - ListCopyWith<$R, StructuredContent, - ObjectCopyWith<$R, StructuredContent, StructuredContent>> get children; - $R call({List? children}); - StructuredContentChildContentCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( - Then<$Out2, $R2> t); -} - -class _StructuredContentChildContentCopyWithImpl<$R, $Out> - extends ClassCopyWithBase<$R, StructuredContentChildContent, $Out> - implements - StructuredContentChildContentCopyWith<$R, StructuredContentChildContent, - $Out> { - _StructuredContentChildContentCopyWithImpl( - super.value, super.then, super.then2); - - @override - late final ClassMapperBase $mapper = - StructuredContentChildContentMapper.ensureInitialized(); - @override - ListCopyWith<$R, StructuredContent, - ObjectCopyWith<$R, StructuredContent, StructuredContent>> - get children => ListCopyWith($value.children, - (v, t) => ObjectCopyWith(v, $identity, t), (v) => call(children: v)); - @override - $R call({List? children}) => - $apply(FieldCopyWithData({if (children != null) #children: children})); - @override - StructuredContentChildContent $make(CopyWithData data) => - StructuredContentChildContent( - children: data.get(#children, or: $value.children)); - - @override - StructuredContentChildContentCopyWith<$R2, StructuredContentChildContent, - $Out2> $chain<$R2, $Out2>( - Then<$Out2, $R2> t) => - _StructuredContentChildContentCopyWithImpl($value, $cast, t); -} - -class StructuredContentLineBreakMapper - extends SubClassMapperBase { - StructuredContentLineBreakMapper._(); - - static StructuredContentLineBreakMapper? _instance; - static StructuredContentLineBreakMapper ensureInitialized() { - if (_instance == null) { - MapperContainer.globals - .use(_instance = StructuredContentLineBreakMapper._()); - StructuredContentMapper.ensureInitialized().addSubMapper(_instance!); - } - return _instance!; - } - - @override - final String id = 'StructuredContentLineBreak'; - - static StructuredContent? _$content(StructuredContentLineBreak v) => - v.content; - static const Field _f$content = - Field('content', _$content, hook: ContentHook()); - - @override - final Map> fields = const { - #content: _f$content, - }; - - @override - final String discriminatorKey = 'type'; - @override - final dynamic discriminatorValue = StructuredContentLineBreak.checkType; - @override - late final ClassMapperBase superMapper = - StructuredContentMapper.ensureInitialized(); - - static StructuredContentLineBreak _instantiate(DecodingData data) { - return StructuredContentLineBreak(); - } - - @override - final Function instantiate = _instantiate; - - static StructuredContentLineBreak fromMap(Map map) { - return ensureInitialized().decodeMap(map); - } - - static StructuredContentLineBreak fromJson(String json) { - return ensureInitialized().decodeJson(json); - } -} - -mixin StructuredContentLineBreakMappable { - String toJson() { - return StructuredContentLineBreakMapper.ensureInitialized() - .encodeJson( - this as StructuredContentLineBreak); - } - - Map toMap() { - return StructuredContentLineBreakMapper.ensureInitialized() - .encodeMap( - this as StructuredContentLineBreak); - } - - StructuredContentLineBreakCopyWith - get copyWith => _StructuredContentLineBreakCopyWithImpl( - this as StructuredContentLineBreak, $identity, $identity); - @override - String toString() { - return StructuredContentLineBreakMapper.ensureInitialized() - .stringifyValue(this as StructuredContentLineBreak); - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (runtimeType == other.runtimeType && - StructuredContentLineBreakMapper.ensureInitialized() - .isValueEqual(this as StructuredContentLineBreak, other)); - } - - @override - int get hashCode { - return StructuredContentLineBreakMapper.ensureInitialized() - .hashValue(this as StructuredContentLineBreak); - } -} - -extension StructuredContentLineBreakValueCopy<$R, $Out> - on ObjectCopyWith<$R, StructuredContentLineBreak, $Out> { - StructuredContentLineBreakCopyWith<$R, StructuredContentLineBreak, $Out> - get $asStructuredContentLineBreak => $base - .as((v, t, t2) => _StructuredContentLineBreakCopyWithImpl(v, t, t2)); -} - -abstract class StructuredContentLineBreakCopyWith< - $R, - $In extends StructuredContentLineBreak, - $Out> implements ClassCopyWith<$R, $In, $Out> { - $R call(); - StructuredContentLineBreakCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( - Then<$Out2, $R2> t); -} - -class _StructuredContentLineBreakCopyWithImpl<$R, $Out> - extends ClassCopyWithBase<$R, StructuredContentLineBreak, $Out> - implements - StructuredContentLineBreakCopyWith<$R, StructuredContentLineBreak, - $Out> { - _StructuredContentLineBreakCopyWithImpl(super.value, super.then, super.then2); - - @override - late final ClassMapperBase $mapper = - StructuredContentLineBreakMapper.ensureInitialized(); - @override - $R call() => $apply(FieldCopyWithData({})); - @override - StructuredContentLineBreak $make(CopyWithData data) => - StructuredContentLineBreak(); - - @override - StructuredContentLineBreakCopyWith<$R2, StructuredContentLineBreak, $Out2> - $chain<$R2, $Out2>(Then<$Out2, $R2> t) => - _StructuredContentLineBreakCopyWithImpl($value, $cast, t); -} - -class StructuredContentImageMapper - extends SubClassMapperBase { - StructuredContentImageMapper._(); - - static StructuredContentImageMapper? _instance; - static StructuredContentImageMapper ensureInitialized() { - if (_instance == null) { - MapperContainer.globals.use(_instance = StructuredContentImageMapper._()); - StructuredContentMapper.ensureInitialized().addSubMapper(_instance!); - } - return _instance!; - } - - @override - final String id = 'StructuredContentImage'; - - static String _$path(StructuredContentImage v) => v.path; - static const Field _f$path = - Field('path', _$path); - static double? _$width(StructuredContentImage v) => v.width; - static const Field _f$width = - Field('width', _$width, opt: true); - static double? _$height(StructuredContentImage v) => v.height; - static const Field _f$height = - Field('height', _$height, opt: true); - static String? _$title(StructuredContentImage v) => v.title; - static const Field _f$title = - Field('title', _$title, opt: true); - static String? _$description(StructuredContentImage v) => v.description; - static const Field _f$description = - Field('description', _$description, opt: true); - static bool _$pixelated(StructuredContentImage v) => v.pixelated; - static const Field _f$pixelated = - Field('pixelated', _$pixelated, opt: true, def: false); - static String _$imageRendering(StructuredContentImage v) => v.imageRendering; - static const Field _f$imageRendering = - Field('imageRendering', _$imageRendering, opt: true, def: 'auto'); - static String _$appearance(StructuredContentImage v) => v.appearance; - static const Field _f$appearance = - Field('appearance', _$appearance, opt: true, def: 'auto'); - static bool _$background(StructuredContentImage v) => v.background; - static const Field _f$background = - Field('background', _$background, opt: true, def: true); - static bool _$collapsed(StructuredContentImage v) => v.collapsed; - static const Field _f$collapsed = - Field('collapsed', _$collapsed, opt: true, def: false); - static bool _$collapsible(StructuredContentImage v) => v.collapsible; - static const Field _f$collapsible = - Field('collapsible', _$collapsible, opt: true, def: true); - static String? _$verticalAlign(StructuredContentImage v) => v.verticalAlign; - static const Field _f$verticalAlign = - Field('verticalAlign', _$verticalAlign, opt: true); - static String? _$sizeUnits(StructuredContentImage v) => v.sizeUnits; - static const Field _f$sizeUnits = - Field('sizeUnits', _$sizeUnits, opt: true); - static StructuredContent? _$content(StructuredContentImage v) => v.content; - static const Field _f$content = - Field('content', _$content, hook: ContentHook()); - - @override - final Map> fields = const { - #path: _f$path, - #width: _f$width, - #height: _f$height, - #title: _f$title, - #description: _f$description, - #pixelated: _f$pixelated, - #imageRendering: _f$imageRendering, - #appearance: _f$appearance, - #background: _f$background, - #collapsed: _f$collapsed, - #collapsible: _f$collapsible, - #verticalAlign: _f$verticalAlign, - #sizeUnits: _f$sizeUnits, - #content: _f$content, - }; - - @override - final String discriminatorKey = 'type'; - @override - final dynamic discriminatorValue = StructuredContentImage.checkType; - @override - late final ClassMapperBase superMapper = - StructuredContentMapper.ensureInitialized(); - - static StructuredContentImage _instantiate(DecodingData data) { - return StructuredContentImage( - path: data.dec(_f$path), - width: data.dec(_f$width), - height: data.dec(_f$height), - title: data.dec(_f$title), - description: data.dec(_f$description), - pixelated: data.dec(_f$pixelated), - imageRendering: data.dec(_f$imageRendering), - appearance: data.dec(_f$appearance), - background: data.dec(_f$background), - collapsed: data.dec(_f$collapsed), - collapsible: data.dec(_f$collapsible), - verticalAlign: data.dec(_f$verticalAlign), - sizeUnits: data.dec(_f$sizeUnits)); - } - - @override - final Function instantiate = _instantiate; - - static StructuredContentImage fromMap(Map map) { - return ensureInitialized().decodeMap(map); - } - - static StructuredContentImage fromJson(String json) { - return ensureInitialized().decodeJson(json); - } -} - -mixin StructuredContentImageMappable { - String toJson() { - return StructuredContentImageMapper.ensureInitialized() - .encodeJson(this as StructuredContentImage); - } - - Map toMap() { - return StructuredContentImageMapper.ensureInitialized() - .encodeMap(this as StructuredContentImage); - } - - StructuredContentImageCopyWith - get copyWith => _StructuredContentImageCopyWithImpl( - this as StructuredContentImage, $identity, $identity); - @override - String toString() { - return StructuredContentImageMapper.ensureInitialized() - .stringifyValue(this as StructuredContentImage); - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (runtimeType == other.runtimeType && - StructuredContentImageMapper.ensureInitialized() - .isValueEqual(this as StructuredContentImage, other)); - } - - @override - int get hashCode { - return StructuredContentImageMapper.ensureInitialized() - .hashValue(this as StructuredContentImage); - } -} - -extension StructuredContentImageValueCopy<$R, $Out> - on ObjectCopyWith<$R, StructuredContentImage, $Out> { - StructuredContentImageCopyWith<$R, StructuredContentImage, $Out> - get $asStructuredContentImage => - $base.as((v, t, t2) => _StructuredContentImageCopyWithImpl(v, t, t2)); -} - -abstract class StructuredContentImageCopyWith< - $R, - $In extends StructuredContentImage, - $Out> implements ClassCopyWith<$R, $In, $Out> { - $R call( - {String? path, - double? width, - double? height, - String? title, - String? description, - bool? pixelated, - String? imageRendering, - String? appearance, - bool? background, - bool? collapsed, - bool? collapsible, - String? verticalAlign, - String? sizeUnits}); - StructuredContentImageCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( - Then<$Out2, $R2> t); -} - -class _StructuredContentImageCopyWithImpl<$R, $Out> - extends ClassCopyWithBase<$R, StructuredContentImage, $Out> - implements - StructuredContentImageCopyWith<$R, StructuredContentImage, $Out> { - _StructuredContentImageCopyWithImpl(super.value, super.then, super.then2); - - @override - late final ClassMapperBase $mapper = - StructuredContentImageMapper.ensureInitialized(); - @override - $R call( - {String? path, - Object? width = $none, - Object? height = $none, - Object? title = $none, - Object? description = $none, - bool? pixelated, - String? imageRendering, - String? appearance, - bool? background, - bool? collapsed, - bool? collapsible, - Object? verticalAlign = $none, - Object? sizeUnits = $none}) => - $apply(FieldCopyWithData({ - if (path != null) #path: path, - if (width != $none) #width: width, - if (height != $none) #height: height, - if (title != $none) #title: title, - if (description != $none) #description: description, - if (pixelated != null) #pixelated: pixelated, - if (imageRendering != null) #imageRendering: imageRendering, - if (appearance != null) #appearance: appearance, - if (background != null) #background: background, - if (collapsed != null) #collapsed: collapsed, - if (collapsible != null) #collapsible: collapsible, - if (verticalAlign != $none) #verticalAlign: verticalAlign, - if (sizeUnits != $none) #sizeUnits: sizeUnits - })); - @override - StructuredContentImage $make(CopyWithData data) => StructuredContentImage( - path: data.get(#path, or: $value.path), - width: data.get(#width, or: $value.width), - height: data.get(#height, or: $value.height), - title: data.get(#title, or: $value.title), - description: data.get(#description, or: $value.description), - pixelated: data.get(#pixelated, or: $value.pixelated), - imageRendering: data.get(#imageRendering, or: $value.imageRendering), - appearance: data.get(#appearance, or: $value.appearance), - background: data.get(#background, or: $value.background), - collapsed: data.get(#collapsed, or: $value.collapsed), - collapsible: data.get(#collapsible, or: $value.collapsible), - verticalAlign: data.get(#verticalAlign, or: $value.verticalAlign), - sizeUnits: data.get(#sizeUnits, or: $value.sizeUnits)); - - @override - StructuredContentImageCopyWith<$R2, StructuredContentImage, $Out2> - $chain<$R2, $Out2>(Then<$Out2, $R2> t) => - _StructuredContentImageCopyWithImpl($value, $cast, t); -} - -class StructuredContentLinkMapper - extends SubClassMapperBase { - StructuredContentLinkMapper._(); - - static StructuredContentLinkMapper? _instance; - static StructuredContentLinkMapper ensureInitialized() { - if (_instance == null) { - MapperContainer.globals.use(_instance = StructuredContentLinkMapper._()); - StructuredContentMapper.ensureInitialized().addSubMapper(_instance!); - StructuredContentMapper.ensureInitialized(); - } - return _instance!; - } - - @override - final String id = 'StructuredContentLink'; - - static String _$href(StructuredContentLink v) => v.href; - static const Field _f$href = - Field('href', _$href); - static StructuredContent? _$content(StructuredContentLink v) => v.content; - static const Field _f$content = - Field('content', _$content, opt: true, hook: ContentHook()); - static String? _$lang(StructuredContentLink v) => v.lang; - static const Field _f$lang = - Field('lang', _$lang, opt: true); - - @override - final Map> fields = const { - #href: _f$href, - #content: _f$content, - #lang: _f$lang, - }; - - @override - final String discriminatorKey = 'type'; - @override - final dynamic discriminatorValue = StructuredContentLink.checkType; - @override - late final ClassMapperBase superMapper = - StructuredContentMapper.ensureInitialized(); - - static StructuredContentLink _instantiate(DecodingData data) { - return StructuredContentLink( - href: data.dec(_f$href), - content: data.dec(_f$content), - lang: data.dec(_f$lang)); - } - - @override - final Function instantiate = _instantiate; - - static StructuredContentLink fromMap(Map map) { - return ensureInitialized().decodeMap(map); - } - - static StructuredContentLink fromJson(String json) { - return ensureInitialized().decodeJson(json); - } -} - -mixin StructuredContentLinkMappable { - String toJson() { - return StructuredContentLinkMapper.ensureInitialized() - .encodeJson(this as StructuredContentLink); - } - - Map toMap() { - return StructuredContentLinkMapper.ensureInitialized() - .encodeMap(this as StructuredContentLink); - } - - StructuredContentLinkCopyWith - get copyWith => _StructuredContentLinkCopyWithImpl( - this as StructuredContentLink, $identity, $identity); - @override - String toString() { - return StructuredContentLinkMapper.ensureInitialized() - .stringifyValue(this as StructuredContentLink); - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (runtimeType == other.runtimeType && - StructuredContentLinkMapper.ensureInitialized() - .isValueEqual(this as StructuredContentLink, other)); - } - - @override - int get hashCode { - return StructuredContentLinkMapper.ensureInitialized() - .hashValue(this as StructuredContentLink); - } -} - -extension StructuredContentLinkValueCopy<$R, $Out> - on ObjectCopyWith<$R, StructuredContentLink, $Out> { - StructuredContentLinkCopyWith<$R, StructuredContentLink, $Out> - get $asStructuredContentLink => - $base.as((v, t, t2) => _StructuredContentLinkCopyWithImpl(v, t, t2)); -} - -abstract class StructuredContentLinkCopyWith< - $R, - $In extends StructuredContentLink, - $Out> implements ClassCopyWith<$R, $In, $Out> { - $R call({String? href, StructuredContent? content, String? lang}); - StructuredContentLinkCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( - Then<$Out2, $R2> t); -} - -class _StructuredContentLinkCopyWithImpl<$R, $Out> - extends ClassCopyWithBase<$R, StructuredContentLink, $Out> - implements StructuredContentLinkCopyWith<$R, StructuredContentLink, $Out> { - _StructuredContentLinkCopyWithImpl(super.value, super.then, super.then2); - - @override - late final ClassMapperBase $mapper = - StructuredContentLinkMapper.ensureInitialized(); - @override - $R call({String? href, Object? content = $none, Object? lang = $none}) => - $apply(FieldCopyWithData({ - if (href != null) #href: href, - if (content != $none) #content: content, - if (lang != $none) #lang: lang - })); - @override - StructuredContentLink $make(CopyWithData data) => StructuredContentLink( - href: data.get(#href, or: $value.href), - content: data.get(#content, or: $value.content), - lang: data.get(#lang, or: $value.lang)); - - @override - StructuredContentLinkCopyWith<$R2, StructuredContentLink, $Out2> - $chain<$R2, $Out2>(Then<$Out2, $R2> t) => - _StructuredContentLinkCopyWithImpl($value, $cast, t); -} - -class StructuredContentContainerMapper - extends SubClassMapperBase { - StructuredContentContainerMapper._(); - - static StructuredContentContainerMapper? _instance; - static StructuredContentContainerMapper ensureInitialized() { - if (_instance == null) { - MapperContainer.globals - .use(_instance = StructuredContentContainerMapper._()); - StructuredContentMapper.ensureInitialized().addSubMapper(_instance!); - StructuredContentMapper.ensureInitialized(); - } - return _instance!; - } - - @override - final String id = 'StructuredContentContainer'; - - static String _$tag(StructuredContentContainer v) => v.tag; - static const Field _f$tag = - Field('tag', _$tag); - static StructuredContent? _$content(StructuredContentContainer v) => - v.content; - static const Field _f$content = - Field('content', _$content, opt: true, hook: ContentHook()); - static Map? _$data(StructuredContentContainer v) => v.data; - static const Field> _f$data = - Field('data', _$data, opt: true); - static String? _$lang(StructuredContentContainer v) => v.lang; - static const Field _f$lang = - Field('lang', _$lang, opt: true); - - @override - final Map> fields = const { - #tag: _f$tag, - #content: _f$content, - #data: _f$data, - #lang: _f$lang, - }; - - @override - final String discriminatorKey = 'type'; - @override - final dynamic discriminatorValue = StructuredContentContainer.checkType; - @override - late final ClassMapperBase superMapper = - StructuredContentMapper.ensureInitialized(); - - static StructuredContentContainer _instantiate(DecodingData data) { - return StructuredContentContainer( - tag: data.dec(_f$tag), - content: data.dec(_f$content), - data: data.dec(_f$data), - lang: data.dec(_f$lang)); - } - - @override - final Function instantiate = _instantiate; - - static StructuredContentContainer fromMap(Map map) { - return ensureInitialized().decodeMap(map); - } - - static StructuredContentContainer fromJson(String json) { - return ensureInitialized().decodeJson(json); - } -} - -mixin StructuredContentContainerMappable { - String toJson() { - return StructuredContentContainerMapper.ensureInitialized() - .encodeJson( - this as StructuredContentContainer); - } - - Map toMap() { - return StructuredContentContainerMapper.ensureInitialized() - .encodeMap( - this as StructuredContentContainer); - } - - StructuredContentContainerCopyWith - get copyWith => _StructuredContentContainerCopyWithImpl( - this as StructuredContentContainer, $identity, $identity); - @override - String toString() { - return StructuredContentContainerMapper.ensureInitialized() - .stringifyValue(this as StructuredContentContainer); - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (runtimeType == other.runtimeType && - StructuredContentContainerMapper.ensureInitialized() - .isValueEqual(this as StructuredContentContainer, other)); - } - - @override - int get hashCode { - return StructuredContentContainerMapper.ensureInitialized() - .hashValue(this as StructuredContentContainer); - } -} - -extension StructuredContentContainerValueCopy<$R, $Out> - on ObjectCopyWith<$R, StructuredContentContainer, $Out> { - StructuredContentContainerCopyWith<$R, StructuredContentContainer, $Out> - get $asStructuredContentContainer => $base - .as((v, t, t2) => _StructuredContentContainerCopyWithImpl(v, t, t2)); -} - -abstract class StructuredContentContainerCopyWith< - $R, - $In extends StructuredContentContainer, - $Out> implements ClassCopyWith<$R, $In, $Out> { - MapCopyWith<$R, String, String, ObjectCopyWith<$R, String, String>>? get data; - $R call( - {String? tag, - StructuredContent? content, - Map? data, - String? lang}); - StructuredContentContainerCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( - Then<$Out2, $R2> t); -} - -class _StructuredContentContainerCopyWithImpl<$R, $Out> - extends ClassCopyWithBase<$R, StructuredContentContainer, $Out> - implements - StructuredContentContainerCopyWith<$R, StructuredContentContainer, - $Out> { - _StructuredContentContainerCopyWithImpl(super.value, super.then, super.then2); - - @override - late final ClassMapperBase $mapper = - StructuredContentContainerMapper.ensureInitialized(); - @override - MapCopyWith<$R, String, String, ObjectCopyWith<$R, String, String>>? - get data => $value.data != null - ? MapCopyWith($value.data!, (v, t) => ObjectCopyWith(v, $identity, t), - (v) => call(data: v)) - : null; - @override - $R call( - {String? tag, - Object? content = $none, - Object? data = $none, - Object? lang = $none}) => - $apply(FieldCopyWithData({ - if (tag != null) #tag: tag, - if (content != $none) #content: content, - if (data != $none) #data: data, - if (lang != $none) #lang: lang - })); - @override - StructuredContentContainer $make(CopyWithData data) => - StructuredContentContainer( - tag: data.get(#tag, or: $value.tag), - content: data.get(#content, or: $value.content), - data: data.get(#data, or: $value.data), - lang: data.get(#lang, or: $value.lang)); - - @override - StructuredContentContainerCopyWith<$R2, StructuredContentContainer, $Out2> - $chain<$R2, $Out2>(Then<$Out2, $R2> t) => - _StructuredContentContainerCopyWithImpl($value, $cast, t); -} - -class StructuredContentStyledContainerMapper - extends SubClassMapperBase { - StructuredContentStyledContainerMapper._(); - - static StructuredContentStyledContainerMapper? _instance; - static StructuredContentStyledContainerMapper ensureInitialized() { - if (_instance == null) { - MapperContainer.globals - .use(_instance = StructuredContentStyledContainerMapper._()); - StructuredContentMapper.ensureInitialized().addSubMapper(_instance!); - StructuredContentMapper.ensureInitialized(); - StructuredContentStyleMapper.ensureInitialized(); - } - return _instance!; - } - - @override - final String id = 'StructuredContentStyledContainer'; - - static String _$tag(StructuredContentStyledContainer v) => v.tag; - static const Field _f$tag = - Field('tag', _$tag); - static StructuredContent? _$content(StructuredContentStyledContainer v) => - v.content; - static const Field - _f$content = Field('content', _$content, opt: true, hook: ContentHook()); - static StructuredContentStyle? _$style(StructuredContentStyledContainer v) => - v.style; - static const Field - _f$style = Field('style', _$style, opt: true); - static Map? _$data(StructuredContentStyledContainer v) => - v.data; - static const Field> - _f$data = Field('data', _$data, opt: true); - static String? _$lang(StructuredContentStyledContainer v) => v.lang; - static const Field _f$lang = - Field('lang', _$lang, opt: true); - - @override - final Map> fields = - const { - #tag: _f$tag, - #content: _f$content, - #style: _f$style, - #data: _f$data, - #lang: _f$lang, - }; - - @override - final String discriminatorKey = 'type'; - @override - final dynamic discriminatorValue = StructuredContentStyledContainer.checkType; - @override - late final ClassMapperBase superMapper = - StructuredContentMapper.ensureInitialized(); - - static StructuredContentStyledContainer _instantiate(DecodingData data) { - return StructuredContentStyledContainer( - tag: data.dec(_f$tag), - content: data.dec(_f$content), - style: data.dec(_f$style), - data: data.dec(_f$data), - lang: data.dec(_f$lang)); - } - - @override - final Function instantiate = _instantiate; - - static StructuredContentStyledContainer fromMap(Map map) { - return ensureInitialized().decodeMap(map); - } - - static StructuredContentStyledContainer fromJson(String json) { - return ensureInitialized() - .decodeJson(json); - } -} - -mixin StructuredContentStyledContainerMappable { - String toJson() { - return StructuredContentStyledContainerMapper.ensureInitialized() - .encodeJson( - this as StructuredContentStyledContainer); - } - - Map toMap() { - return StructuredContentStyledContainerMapper.ensureInitialized() - .encodeMap( - this as StructuredContentStyledContainer); - } - - StructuredContentStyledContainerCopyWith - get copyWith => _StructuredContentStyledContainerCopyWithImpl( - this as StructuredContentStyledContainer, $identity, $identity); - @override - String toString() { - return StructuredContentStyledContainerMapper.ensureInitialized() - .stringifyValue(this as StructuredContentStyledContainer); - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (runtimeType == other.runtimeType && - StructuredContentStyledContainerMapper.ensureInitialized() - .isValueEqual(this as StructuredContentStyledContainer, other)); - } - - @override - int get hashCode { - return StructuredContentStyledContainerMapper.ensureInitialized() - .hashValue(this as StructuredContentStyledContainer); - } -} - -extension StructuredContentStyledContainerValueCopy<$R, $Out> - on ObjectCopyWith<$R, StructuredContentStyledContainer, $Out> { - StructuredContentStyledContainerCopyWith<$R, StructuredContentStyledContainer, - $Out> - get $asStructuredContentStyledContainer => $base.as((v, t, t2) => - _StructuredContentStyledContainerCopyWithImpl(v, t, t2)); -} - -abstract class StructuredContentStyledContainerCopyWith< - $R, - $In extends StructuredContentStyledContainer, - $Out> implements ClassCopyWith<$R, $In, $Out> { - StructuredContentStyleCopyWith<$R, StructuredContentStyle, - StructuredContentStyle>? get style; - MapCopyWith<$R, String, String, ObjectCopyWith<$R, String, String>>? get data; - $R call( - {String? tag, - StructuredContent? content, - StructuredContentStyle? style, - Map? data, - String? lang}); - StructuredContentStyledContainerCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( - Then<$Out2, $R2> t); -} - -class _StructuredContentStyledContainerCopyWithImpl<$R, $Out> - extends ClassCopyWithBase<$R, StructuredContentStyledContainer, $Out> - implements - StructuredContentStyledContainerCopyWith<$R, - StructuredContentStyledContainer, $Out> { - _StructuredContentStyledContainerCopyWithImpl( - super.value, super.then, super.then2); - - @override - late final ClassMapperBase $mapper = - StructuredContentStyledContainerMapper.ensureInitialized(); - @override - StructuredContentStyleCopyWith<$R, StructuredContentStyle, - StructuredContentStyle>? - get style => $value.style?.copyWith.$chain((v) => call(style: v)); - @override - MapCopyWith<$R, String, String, ObjectCopyWith<$R, String, String>>? - get data => $value.data != null - ? MapCopyWith($value.data!, (v, t) => ObjectCopyWith(v, $identity, t), - (v) => call(data: v)) - : null; - @override - $R call( - {String? tag, - Object? content = $none, - Object? style = $none, - Object? data = $none, - Object? lang = $none}) => - $apply(FieldCopyWithData({ - if (tag != null) #tag: tag, - if (content != $none) #content: content, - if (style != $none) #style: style, - if (data != $none) #data: data, - if (lang != $none) #lang: lang - })); - @override - StructuredContentStyledContainer $make(CopyWithData data) => - StructuredContentStyledContainer( - tag: data.get(#tag, or: $value.tag), - content: data.get(#content, or: $value.content), - style: data.get(#style, or: $value.style), - data: data.get(#data, or: $value.data), - lang: data.get(#lang, or: $value.lang)); - - @override - StructuredContentStyledContainerCopyWith<$R2, - StructuredContentStyledContainer, $Out2> $chain<$R2, $Out2>( - Then<$Out2, $R2> t) => - _StructuredContentStyledContainerCopyWithImpl($value, $cast, t); -} - -class StructuredContentStyleMapper - extends ClassMapperBase { - StructuredContentStyleMapper._(); - - static StructuredContentStyleMapper? _instance; - static StructuredContentStyleMapper ensureInitialized() { - if (_instance == null) { - MapperContainer.globals.use(_instance = StructuredContentStyleMapper._()); - } - return _instance!; - } - - @override - final String id = 'StructuredContentStyle'; - - static String _$fontStyle(StructuredContentStyle v) => v.fontStyle; - static const Field _f$fontStyle = - Field('fontStyle', _$fontStyle, opt: true, def: 'normal'); - static String _$fontWeight(StructuredContentStyle v) => v.fontWeight; - static const Field _f$fontWeight = - Field('fontWeight', _$fontWeight, opt: true, def: 'normal'); - static String _$fontSize(StructuredContentStyle v) => v.fontSize; - static const Field _f$fontSize = - Field('fontSize', _$fontSize, opt: true, def: 'medium'); - static List _$textDecorationLine(StructuredContentStyle v) => - v.textDecorationLine; - static const Field> - _f$textDecorationLine = Field('textDecorationLine', _$textDecorationLine, - opt: true, def: const [], hook: TextDecorationLineHooker()); - static String _$verticalAlign(StructuredContentStyle v) => v.verticalAlign; - static const Field _f$verticalAlign = - Field('verticalAlign', _$verticalAlign, opt: true, def: 'baseline'); - static String _$textAlign(StructuredContentStyle v) => v.textAlign; - static const Field _f$textAlign = - Field('textAlign', _$textAlign, opt: true, def: 'start'); - static double _$marginTop(StructuredContentStyle v) => v.marginTop; - static const Field _f$marginTop = - Field('marginTop', _$marginTop, opt: true, def: 0); - static double _$marginLeft(StructuredContentStyle v) => v.marginLeft; - static const Field _f$marginLeft = - Field('marginLeft', _$marginLeft, opt: true, def: 0); - static double _$marginRight(StructuredContentStyle v) => v.marginRight; - static const Field _f$marginRight = - Field('marginRight', _$marginRight, opt: true, def: 0); - static double _$marginBottom(StructuredContentStyle v) => v.marginBottom; - static const Field _f$marginBottom = - Field('marginBottom', _$marginBottom, opt: true, def: 0); - static String _$listStyleType(StructuredContentStyle v) => v.listStyleType; - static const Field _f$listStyleType = - Field('listStyleType', _$listStyleType, opt: true, def: 'disc'); - - @override - final Map> fields = const { - #fontStyle: _f$fontStyle, - #fontWeight: _f$fontWeight, - #fontSize: _f$fontSize, - #textDecorationLine: _f$textDecorationLine, - #verticalAlign: _f$verticalAlign, - #textAlign: _f$textAlign, - #marginTop: _f$marginTop, - #marginLeft: _f$marginLeft, - #marginRight: _f$marginRight, - #marginBottom: _f$marginBottom, - #listStyleType: _f$listStyleType, - }; - - static StructuredContentStyle _instantiate(DecodingData data) { - return StructuredContentStyle( - fontStyle: data.dec(_f$fontStyle), - fontWeight: data.dec(_f$fontWeight), - fontSize: data.dec(_f$fontSize), - textDecorationLine: data.dec(_f$textDecorationLine), - verticalAlign: data.dec(_f$verticalAlign), - textAlign: data.dec(_f$textAlign), - marginTop: data.dec(_f$marginTop), - marginLeft: data.dec(_f$marginLeft), - marginRight: data.dec(_f$marginRight), - marginBottom: data.dec(_f$marginBottom), - listStyleType: data.dec(_f$listStyleType)); - } - - @override - final Function instantiate = _instantiate; - - static StructuredContentStyle fromMap(Map map) { - return ensureInitialized().decodeMap(map); - } - - static StructuredContentStyle fromJson(String json) { - return ensureInitialized().decodeJson(json); - } -} - -mixin StructuredContentStyleMappable { - String toJson() { - return StructuredContentStyleMapper.ensureInitialized() - .encodeJson(this as StructuredContentStyle); - } - - Map toMap() { - return StructuredContentStyleMapper.ensureInitialized() - .encodeMap(this as StructuredContentStyle); - } - - StructuredContentStyleCopyWith - get copyWith => _StructuredContentStyleCopyWithImpl( - this as StructuredContentStyle, $identity, $identity); - @override - String toString() { - return StructuredContentStyleMapper.ensureInitialized() - .stringifyValue(this as StructuredContentStyle); - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (runtimeType == other.runtimeType && - StructuredContentStyleMapper.ensureInitialized() - .isValueEqual(this as StructuredContentStyle, other)); - } - - @override - int get hashCode { - return StructuredContentStyleMapper.ensureInitialized() - .hashValue(this as StructuredContentStyle); - } -} - -extension StructuredContentStyleValueCopy<$R, $Out> - on ObjectCopyWith<$R, StructuredContentStyle, $Out> { - StructuredContentStyleCopyWith<$R, StructuredContentStyle, $Out> - get $asStructuredContentStyle => - $base.as((v, t, t2) => _StructuredContentStyleCopyWithImpl(v, t, t2)); -} - -abstract class StructuredContentStyleCopyWith< - $R, - $In extends StructuredContentStyle, - $Out> implements ClassCopyWith<$R, $In, $Out> { - ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>> - get textDecorationLine; - $R call( - {String? fontStyle, - String? fontWeight, - String? fontSize, - List? textDecorationLine, - String? verticalAlign, - String? textAlign, - double? marginTop, - double? marginLeft, - double? marginRight, - double? marginBottom, - String? listStyleType}); - StructuredContentStyleCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( - Then<$Out2, $R2> t); -} - -class _StructuredContentStyleCopyWithImpl<$R, $Out> - extends ClassCopyWithBase<$R, StructuredContentStyle, $Out> - implements - StructuredContentStyleCopyWith<$R, StructuredContentStyle, $Out> { - _StructuredContentStyleCopyWithImpl(super.value, super.then, super.then2); - - @override - late final ClassMapperBase $mapper = - StructuredContentStyleMapper.ensureInitialized(); - @override - ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>> - get textDecorationLine => ListCopyWith( - $value.textDecorationLine, - (v, t) => ObjectCopyWith(v, $identity, t), - (v) => call(textDecorationLine: v)); - @override - $R call( - {String? fontStyle, - String? fontWeight, - String? fontSize, - List? textDecorationLine, - String? verticalAlign, - String? textAlign, - double? marginTop, - double? marginLeft, - double? marginRight, - double? marginBottom, - String? listStyleType}) => - $apply(FieldCopyWithData({ - if (fontStyle != null) #fontStyle: fontStyle, - if (fontWeight != null) #fontWeight: fontWeight, - if (fontSize != null) #fontSize: fontSize, - if (textDecorationLine != null) #textDecorationLine: textDecorationLine, - if (verticalAlign != null) #verticalAlign: verticalAlign, - if (textAlign != null) #textAlign: textAlign, - if (marginTop != null) #marginTop: marginTop, - if (marginLeft != null) #marginLeft: marginLeft, - if (marginRight != null) #marginRight: marginRight, - if (marginBottom != null) #marginBottom: marginBottom, - if (listStyleType != null) #listStyleType: listStyleType - })); - @override - StructuredContentStyle $make(CopyWithData data) => StructuredContentStyle( - fontStyle: data.get(#fontStyle, or: $value.fontStyle), - fontWeight: data.get(#fontWeight, or: $value.fontWeight), - fontSize: data.get(#fontSize, or: $value.fontSize), - textDecorationLine: - data.get(#textDecorationLine, or: $value.textDecorationLine), - verticalAlign: data.get(#verticalAlign, or: $value.verticalAlign), - textAlign: data.get(#textAlign, or: $value.textAlign), - marginTop: data.get(#marginTop, or: $value.marginTop), - marginLeft: data.get(#marginLeft, or: $value.marginLeft), - marginRight: data.get(#marginRight, or: $value.marginRight), - marginBottom: data.get(#marginBottom, or: $value.marginBottom), - listStyleType: data.get(#listStyleType, or: $value.listStyleType)); - - @override - StructuredContentStyleCopyWith<$R2, StructuredContentStyle, $Out2> - $chain<$R2, $Out2>(Then<$Out2, $R2> t) => - _StructuredContentStyleCopyWithImpl($value, $cast, t); -} - -class StructuredContentTableElementMapper - extends SubClassMapperBase { - StructuredContentTableElementMapper._(); - - static StructuredContentTableElementMapper? _instance; - static StructuredContentTableElementMapper ensureInitialized() { - if (_instance == null) { - MapperContainer.globals - .use(_instance = StructuredContentTableElementMapper._()); - StructuredContentMapper.ensureInitialized().addSubMapper(_instance!); - StructuredContentMapper.ensureInitialized(); - StructuredContentStyleMapper.ensureInitialized(); - } - return _instance!; - } - - @override - final String id = 'StructuredContentTableElement'; - - static String _$tag(StructuredContentTableElement v) => v.tag; - static const Field _f$tag = - Field('tag', _$tag); - static StructuredContent? _$content(StructuredContentTableElement v) => - v.content; - static const Field - _f$content = Field('content', _$content, opt: true, hook: ContentHook()); - static StructuredContentStyle? _$style(StructuredContentTableElement v) => - v.style; - static const Field - _f$style = Field('style', _$style, opt: true); - static Map? _$data(StructuredContentTableElement v) => v.data; - static const Field> - _f$data = Field('data', _$data, opt: true); - static int? _$colSpan(StructuredContentTableElement v) => v.colSpan; - static const Field _f$colSpan = - Field('colSpan', _$colSpan, opt: true); - static int? _$rowSpan(StructuredContentTableElement v) => v.rowSpan; - static const Field _f$rowSpan = - Field('rowSpan', _$rowSpan, opt: true); - static String? _$lang(StructuredContentTableElement v) => v.lang; - static const Field _f$lang = - Field('lang', _$lang, opt: true); - - @override - final Map> fields = - const { - #tag: _f$tag, - #content: _f$content, - #style: _f$style, - #data: _f$data, - #colSpan: _f$colSpan, - #rowSpan: _f$rowSpan, - #lang: _f$lang, - }; - - @override - final String discriminatorKey = 'type'; - @override - final dynamic discriminatorValue = StructuredContentTableElement.checkType; - @override - late final ClassMapperBase superMapper = - StructuredContentMapper.ensureInitialized(); - - static StructuredContentTableElement _instantiate(DecodingData data) { - return StructuredContentTableElement( - tag: data.dec(_f$tag), - content: data.dec(_f$content), - style: data.dec(_f$style), - data: data.dec(_f$data), - colSpan: data.dec(_f$colSpan), - rowSpan: data.dec(_f$rowSpan), - lang: data.dec(_f$lang)); - } - - @override - final Function instantiate = _instantiate; - - static StructuredContentTableElement fromMap(Map map) { - return ensureInitialized().decodeMap(map); - } - - static StructuredContentTableElement fromJson(String json) { - return ensureInitialized().decodeJson(json); - } -} - -mixin StructuredContentTableElementMappable { - String toJson() { - return StructuredContentTableElementMapper.ensureInitialized() - .encodeJson( - this as StructuredContentTableElement); - } - - Map toMap() { - return StructuredContentTableElementMapper.ensureInitialized() - .encodeMap( - this as StructuredContentTableElement); - } - - StructuredContentTableElementCopyWith - get copyWith => _StructuredContentTableElementCopyWithImpl( - this as StructuredContentTableElement, $identity, $identity); - @override - String toString() { - return StructuredContentTableElementMapper.ensureInitialized() - .stringifyValue(this as StructuredContentTableElement); - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (runtimeType == other.runtimeType && - StructuredContentTableElementMapper.ensureInitialized() - .isValueEqual(this as StructuredContentTableElement, other)); - } - - @override - int get hashCode { - return StructuredContentTableElementMapper.ensureInitialized() - .hashValue(this as StructuredContentTableElement); - } -} - -extension StructuredContentTableElementValueCopy<$R, $Out> - on ObjectCopyWith<$R, StructuredContentTableElement, $Out> { - StructuredContentTableElementCopyWith<$R, StructuredContentTableElement, $Out> - get $asStructuredContentTableElement => $base.as( - (v, t, t2) => _StructuredContentTableElementCopyWithImpl(v, t, t2)); -} - -abstract class StructuredContentTableElementCopyWith< - $R, - $In extends StructuredContentTableElement, - $Out> implements ClassCopyWith<$R, $In, $Out> { - StructuredContentStyleCopyWith<$R, StructuredContentStyle, - StructuredContentStyle>? get style; - MapCopyWith<$R, String, String, ObjectCopyWith<$R, String, String>>? get data; - $R call( - {String? tag, - StructuredContent? content, - StructuredContentStyle? style, - Map? data, - int? colSpan, - int? rowSpan, - String? lang}); - StructuredContentTableElementCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( - Then<$Out2, $R2> t); -} - -class _StructuredContentTableElementCopyWithImpl<$R, $Out> - extends ClassCopyWithBase<$R, StructuredContentTableElement, $Out> - implements - StructuredContentTableElementCopyWith<$R, StructuredContentTableElement, - $Out> { - _StructuredContentTableElementCopyWithImpl( - super.value, super.then, super.then2); - - @override - late final ClassMapperBase $mapper = - StructuredContentTableElementMapper.ensureInitialized(); - @override - StructuredContentStyleCopyWith<$R, StructuredContentStyle, - StructuredContentStyle>? - get style => $value.style?.copyWith.$chain((v) => call(style: v)); - @override - MapCopyWith<$R, String, String, ObjectCopyWith<$R, String, String>>? - get data => $value.data != null - ? MapCopyWith($value.data!, (v, t) => ObjectCopyWith(v, $identity, t), - (v) => call(data: v)) - : null; - @override - $R call( - {String? tag, - Object? content = $none, - Object? style = $none, - Object? data = $none, - Object? colSpan = $none, - Object? rowSpan = $none, - Object? lang = $none}) => - $apply(FieldCopyWithData({ - if (tag != null) #tag: tag, - if (content != $none) #content: content, - if (style != $none) #style: style, - if (data != $none) #data: data, - if (colSpan != $none) #colSpan: colSpan, - if (rowSpan != $none) #rowSpan: rowSpan, - if (lang != $none) #lang: lang - })); - @override - StructuredContentTableElement $make(CopyWithData data) => - StructuredContentTableElement( - tag: data.get(#tag, or: $value.tag), - content: data.get(#content, or: $value.content), - style: data.get(#style, or: $value.style), - data: data.get(#data, or: $value.data), - colSpan: data.get(#colSpan, or: $value.colSpan), - rowSpan: data.get(#rowSpan, or: $value.rowSpan), - lang: data.get(#lang, or: $value.lang)); - - @override - StructuredContentTableElementCopyWith<$R2, StructuredContentTableElement, - $Out2> $chain<$R2, $Out2>( - Then<$Out2, $R2> t) => - _StructuredContentTableElementCopyWithImpl($value, $cast, t); -} diff --git a/yuuna/lib/src/pages/implementations/dictionary_structured_content_page.dart b/yuuna/lib/src/pages/implementations/dictionary_structured_content_page.dart index f35ab7f9..55f2f53d 100644 --- a/yuuna/lib/src/pages/implementations/dictionary_structured_content_page.dart +++ b/yuuna/lib/src/pages/implementations/dictionary_structured_content_page.dart @@ -12,6 +12,40 @@ import 'package:yuuna/dictionary.dart'; import 'package:yuuna/models.dart'; import 'package:yuuna/utils.dart'; +/// Wraps a [JidoujishoTag] around a span of text. +class JidoujishoTagExtension extends HtmlExtension { + + /// Create an instance of this extension. + const JidoujishoTagExtension(); + + @override + Set get supportedTags => {'span'}; + + @override + bool matches(ExtensionContext context) { + if (context.currentStep != CurrentStep.building) { + return false; + } + + /// Matching titles is a bit hacky, but it works for now. + return context.attributes.containsKey('data-sc-code') || + context.attributes['title'] == 'spelling and reading variants'; + } + + @override + InlineSpan build(ExtensionContext context) { + final text = context.element?.text; + final String infoText = context.attributes['title'] ?? 'no description'; + + return WidgetSpan( + child: JidoujishoTag( + text: '$text', + message: infoText, + backgroundColor: Colors.red.shade900) + ); + } +} + /// Provides and caches the processed HTML of a [DictionaryEntry] to improve /// performance. final dictionaryEntryHtmlProvider = @@ -19,15 +53,12 @@ final dictionaryEntryHtmlProvider = return entry.definitions .map((e) { try { - final node = - StructuredContent.processContent(jsonDecode(e))?.toNode(); - if (node == null) { - return ''; - } + final node = StructuredContent.processContent(jsonDecode(e)); final document = dom.Document.html(''); document.body?.append(node); final html = document.body?.innerHtml ?? ''; + print('Processed content: $html'); return html; } catch (_) { @@ -64,6 +95,13 @@ class DictionaryHtmlWidget extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { + /// Fixes Intrinsics not available for PlaceholderAlignment caused by nested + /// tables + /// Currently, the branch that fixes this also breaks nested lists text + /// alignment. + /// So we are using this workaround for now. + /// See https://github.com/Sub6Resources/flutter_html/pull/1306 for updates. + RenderObject.debugCheckingIntrinsics = true; final textColor = Theme.of(context).brightness == Brightness.dark ? Colors.white : Colors.black; @@ -74,11 +112,13 @@ class DictionaryHtmlWidget extends ConsumerWidget { final tableBorder = Border.all(color: textColor, width: tableWidth); final tableStyle = Style( border: tableBorder, + /// Hack for misaligned text in tables + padding: HtmlPaddings.only(right: 5), ); return Html( data: ref.watch(dictionaryEntryHtmlProvider(entry)), - shrinkWrap: true, + shrinkWrap: false, onAnchorTap: (url, attributes, element) { onSearch.call(attributes['query'] ?? element?.text ?? 'f'); }, @@ -89,15 +129,20 @@ class DictionaryHtmlWidget extends ConsumerWidget { ), 'td': tableStyle, 'th': tableStyle, - 'ul': Style( - padding: HtmlPaddings.zero, - ), - 'li': Style( - padding: HtmlPaddings.zero, + 'ul, ol': Style( + display: Display.block, + padding: HtmlPaddings.only(left: 0), ), + 'ul ul, ul ol, ol ul, ol ol': + Style(padding: HtmlPaddings.only(left: 15)), + 'ul ul ul, ul ul ol, ul ol ul, ul ol ol, ol ul ul, ol ul ol, ol ol ul, ol ol ol': + Style(padding: HtmlPaddings.only(left: 15)), 'a': Style(color: linkColor), + 'a ruby': Style(color: linkColor), + 'a ruby rt': Style(color: linkColor), }, extensions: [ + const JidoujishoTagExtension(), const TableHtmlExtension(), ImageExtension.inline( networkSchemas: {'jidoujisho'}, diff --git a/yuuna/lib/src/pages/implementations/dictionary_term_page.dart b/yuuna/lib/src/pages/implementations/dictionary_term_page.dart index 0ba629d6..feebbd0b 100644 --- a/yuuna/lib/src/pages/implementations/dictionary_term_page.dart +++ b/yuuna/lib/src/pages/implementations/dictionary_term_page.dart @@ -52,7 +52,7 @@ class DictionaryTermPage extends ConsumerWidget { /// Lists the order of dictionaries. final Map dictionaryNamesByOrder; - /// Optional footer foor use in [DictionaryHistoryPage]. + /// Optional footer for use in [DictionaryHistoryPage]. final Widget? footerWidget; /// Override color for card background color. diff --git a/yuuna/pubspec.lock b/yuuna/pubspec.lock index f3787284..2a025967 100644 --- a/yuuna/pubspec.lock +++ b/yuuna/pubspec.lock @@ -693,10 +693,10 @@ packages: dependency: transitive description: name: flutter_layout_grid - sha256: "3529b7aa7ed2cb9861a0bbaa5c14d4be2beaf5a070ce0176077159f80c5de094" + sha256: "88b4f8484a0874962e27c47733ad256aeb26acc694a9f029edbef771d301885a" url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.0.7" flutter_lints: dependency: "direct dev" description: @@ -2031,4 +2031,4 @@ packages: version: "2.0.1" sdks: dart: ">=3.1.0-185.0.dev <4.0.0" - flutter: ">=3.13.5" + flutter: ">=3.13.9" diff --git a/yuuna/pubspec.yaml b/yuuna/pubspec.yaml index abd09002..58a3fc6d 100644 --- a/yuuna/pubspec.yaml +++ b/yuuna/pubspec.yaml @@ -4,7 +4,7 @@ publish_to: 'none' version: 2.9.0+105 environment: sdk: ">=3.0.0<4.0.0" - flutter: "^3.13.5" + flutter: "^3.13.9" dependencies: async_zip: ^0.1.0 @@ -155,6 +155,12 @@ dependency_overrides: url: https://github.com/diegotori/wakelock ref: 40464c75e908f57f458597ef4912f5273ab89b1a path: wakelock_windows + # Fixes Intrinsics not available for PlaceholderAlignment caused by nested tables + # See https://github.com/flutter/flutter/issues/135912 +# flutter_html: +# git: +# url: https://github.com/Sub6Resources/flutter_html.git +# ref: 90550ddeab4eabf4f715d15e56c5a3da82c37373 dev_dependencies: build_runner: ^2.3.3 @@ -162,7 +168,7 @@ dev_dependencies: dependency_validator: ^3.0.0 flutter_lints: ^2.0.1 isar_generator: ^3.1.0+1 - + flutter_icons: android: "launcher_icon" ios: true