//data structures import 'dart:typed_data'; import 'package:markdown/markdown.dart' as md; class GetThreadResponse { final int id; final List messages; final String subject; final DateTime date; final String from_name; final String from_address; final List to; late bool seen; GetThreadResponse({ required this.id, required this.messages, required this.subject, required this.date, required this.from_name, required this.from_address, required this.to, required this.seen, }); factory GetThreadResponse.fromJson(Map json) { var toList = json['to'] as List; return GetThreadResponse( id: json['id'], messages: List.from(json['messages']), subject: json['subject'], date: DateTime.parse(json['date']), from_name: json['from_name'], from_address: json['from_address'], to: toList.map((i) => MailAddress.fromJson(i)).toList(), seen: json['seen']); } } class MailAddress { final String? name; final String address; MailAddress({this.name, required this.address}); factory MailAddress.fromJson(Map json) { return MailAddress( name: json['name'], address: json['address'], ); } @override String toString() { // TODO: implement toString return '${name} <${address}>'; } } // //old data structure class SerializableMessage { final String name; final String from; final List to; final List cc; final String hash; final String subject; final String date; final int uid; final String list; final String id; final String in_reply_to; SerializableMessage({ required this.name, required this.from, required this.to, required this.cc, required this.hash, required this.subject, required this.date, required this.uid, required this.list, //email list??? required this.id, required this.in_reply_to, }); factory SerializableMessage.fromJson(Map json) { var toList = json['to'] as List; var ccList = json['cc'] as List; return SerializableMessage( name: json['name'], from: json['from'], // to: json['name', 'address'] to: toList.map((i) => MailAddress.fromJson(i)).toList(), cc: ccList.map((i) => MailAddress.fromJson(i)).toList(), // path: json['path'], hash: json['hash'], subject: json['subject'], date: json['date'], uid: json['uid'], list: json['list'], id: json['id'], in_reply_to: json['in_reply_to'], ); } } class AttachmentInfo { final String name; final int size; final String path; AttachmentInfo({required this.name, required this.size, required this.path}); factory AttachmentInfo.fromJson(Map json) { return AttachmentInfo( name: json['name'], size: json['size'], path: json['path'], ); } } class AttachmentInfoList extends Iterable { final List _attachments; AttachmentInfoList(this._attachments); factory AttachmentInfoList.fromJsonList(List> jsonList) { return AttachmentInfoList( jsonList.map((json) => AttachmentInfo.fromJson(json)).toList()); } @override Iterator get iterator => _attachments.iterator; @override String toString() => _attachments.toString(); } class AttachmentResponse { final name; final Uint8List data; AttachmentResponse({required this.name, required this.data}); factory AttachmentResponse.fromJson(Map json) { return AttachmentResponse( name: json["name"], data: Uint8List.fromList(List.from(json["data"]))); } } class AugmentTree { List children = []; String data = ''; AugmentTree? parent; String ogTag = ''; String numbering = ''; Map hirarchyDict = { "h1": 1, "h2": 2, "h3": 3, "h4": 4, "h5": 5, "h6": 6, "p": 8, "ul": 8, "li": 8, }; AugmentTree(); AugmentTree.fromMD(String rawMD) { //makes raw MD into an augmentTree print("started markdown2tree"); final List nakedList = md.Document().parseLines(rawMD.split( '\n')); //emails md is the index of the email in the thread, since this only handles one thus it shall be removed // AugmentTree zoomTreeRoot = AugmentTree(); for (var node in nakedList) { //maybe do an add function, but isn't this it? if (node is md.Element) { AugmentTree temp = AugmentTree(); temp.data = node.textContent; temp.ogTag = node.tag; if (hirarchyDict.containsKey(node.tag)) { // make this O(1) _add2Tree(this, node); // print(node); } } } this.addNumbering(); } void _add2Tree(AugmentTree tree, md.Element node2add) { // adds node to its corresponding place AugmentTree newNode = AugmentTree(); newNode.setData(node2add.textContent); newNode.ogTag = node2add.tag; // cases, //1. a node that comes is lower than the root.children last, if so it goes beneath it if (tree.children.isEmpty) { // new level to be created when totally empty tree.children.add(newNode); newNode.parent = tree; } else if (tree.children.isNotEmpty && tree.children.last.ogTag.isNotEmpty) { if ((hirarchyDict[node2add.tag] ?? -1) < // e.g. new node is h1 and old is h2, heapify (hirarchyDict[tree.children.last.ogTag] ?? -1)) { //have to figure out the borthers //assuming it all goes right if ((hirarchyDict[node2add.tag] ?? -1) == -1 || (hirarchyDict[tree.children.last.ogTag] ?? -1) == -1) { print( 'failed and got -1 at _add2Tree \n ${hirarchyDict[node2add.tag] ?? -1} < ${hirarchyDict[tree.children.last.ogTag] ?? -1}'); return; } else if (tree.children.last.parent == null) { // becomes the new top level for (AugmentTree brother in tree.children) { brother.parent = newNode; } tree.children = [newNode]; } else { newNode.parent = tree; tree.children.add(newNode); } } else if ((hirarchyDict[node2add.tag] ?? -1) > // go down e.g. new node is h3 and old is h2 or something (hirarchyDict[tree.children.last.ogTag] ?? -1)) { if ((hirarchyDict[node2add.tag] ?? -1) == -1 || (hirarchyDict[tree.children.last.ogTag] ?? -1) == -1) { print( 'failed and got -1 at _add2Tree \n ${hirarchyDict[node2add.tag] ?? -1} > ${hirarchyDict[tree.children.last.ogTag] ?? -1}'); print("-1 ${tree.children.last.ogTag}"); return; } _add2Tree(tree.children.last, node2add); } else if ((hirarchyDict[node2add.tag] ?? -1) == (hirarchyDict[tree.children.last.ogTag] ?? -1)) { tree.children.add(newNode); newNode.parent = tree; } } } void setData(String data) { this.data = data; } static String _intToLetter(int index) { return String.fromCharCode('a'.runes.first + index); } void addNumbering({String prefix = ''}) { //if called in root, numbers them all for (int i = 0; i < children.length; i++) { final child = children[i]; String childNumbering; bool parentIsLettered = prefix.contains(RegExp(r'[a-z]')); if (prefix.isEmpty) { parentIsLettered = false; } else { parentIsLettered = prefix.runes.last >= 'a'.runes.first && prefix.runes.last <= 'z'.runes.first; } if (prefix.isEmpty) { // Top-level children (direct children of the original root being numbered) get 1, 2, 3... childNumbering = (i + 1).toString(); } else if (parentIsLettered) { // Deeper children get '1a', '1b', '2a', '2b', etc. childNumbering = '$prefix${i + 1}'; } else { childNumbering = '$prefix${_intToLetter(i)}'; } child.numbering = childNumbering; // Recursively call for children child.addNumbering(prefix: childNumbering); } } } //perhaps make a struct that builds augment tree, since its so complex and needs to be like recursive class MarkdownParsed { //struct for holding the MD given in endpoint //not used final String text; MarkdownParsed({required this.text}); factory MarkdownParsed.fromJson(Map json) { return MarkdownParsed( text: json['md'] ?? '', ); } } //should make an md to tree class/struct // make a for loop of rows with markdown