307 lines
8.6 KiB
Dart
307 lines
8.6 KiB
Dart
//data structures
|
|
|
|
import 'dart:typed_data';
|
|
import 'package:markdown/markdown.dart' as md;
|
|
|
|
class GetThreadResponse {
|
|
final int id;
|
|
final List<String> messages;
|
|
final String subject;
|
|
final DateTime date;
|
|
final String from_name;
|
|
final String from_address;
|
|
final List<MailAddress> 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<String, dynamic> json) {
|
|
var toList = json['to'] as List<dynamic>;
|
|
|
|
return GetThreadResponse(
|
|
id: json['id'],
|
|
messages: List<String>.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<String, dynamic> 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<MailAddress> to;
|
|
final List<MailAddress> 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<String, dynamic> 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<String, dynamic> json) {
|
|
return AttachmentInfo(
|
|
name: json['name'],
|
|
size: json['size'],
|
|
path: json['path'],
|
|
);
|
|
}
|
|
}
|
|
|
|
class AttachmentInfoList extends Iterable<AttachmentInfo> {
|
|
final List<AttachmentInfo> _attachments;
|
|
|
|
AttachmentInfoList(this._attachments);
|
|
|
|
factory AttachmentInfoList.fromJsonList(List<Map<String, dynamic>> jsonList) {
|
|
return AttachmentInfoList(
|
|
jsonList.map((json) => AttachmentInfo.fromJson(json)).toList());
|
|
}
|
|
|
|
@override
|
|
Iterator<AttachmentInfo> 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<String, dynamic> json) {
|
|
return AttachmentResponse(
|
|
name: json["name"],
|
|
data: Uint8List.fromList(List<int>.from(json["data"])));
|
|
}
|
|
}
|
|
|
|
class AugmentTree {
|
|
List<AugmentTree> children = [];
|
|
|
|
String data = '';
|
|
AugmentTree? parent;
|
|
String ogTag = '';
|
|
String numbering = '';
|
|
Map<String, int> 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<md.Node> 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<String, String> json) {
|
|
return MarkdownParsed(
|
|
text: json['md'] ?? '',
|
|
);
|
|
}
|
|
}
|
|
|
|
//should make an md to tree class/struct
|
|
|
|
// make a for loop of rows with markdown
|