WIP: android/ios-adaption feature, markdown, and augment #6
@ -1,6 +1,5 @@
|
||||
import 'package:crab_ui/api_service.dart';
|
||||
import 'package:crab_ui/attachmentDownload.dart';
|
||||
import 'package:crab_ui/collapsableEmails.dart';
|
||||
import 'package:crab_ui/structs.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||
|
@ -7,13 +7,19 @@ import 'package:markdown/markdown.dart' as md;
|
||||
|
||||
class CollapsableEmails extends StatefulWidget {
|
||||
final List<String> thread; // email id's in the form xyz@gmail.com
|
||||
final List<String> threadHTML;
|
||||
// final List<String> threadHTML;
|
||||
final List<String> threadMarkdown;
|
||||
final String threadIDs;
|
||||
final String? targetJumpNumbering;
|
||||
final String? targetViewspecs;
|
||||
|
||||
CollapsableEmails(
|
||||
{required this.thread,
|
||||
required this.threadHTML,
|
||||
required this.threadIDs});
|
||||
required this.threadMarkdown,
|
||||
required this.threadIDs,
|
||||
this.targetJumpNumbering,
|
||||
this.targetViewspecs,
|
||||
});
|
||||
|
||||
@override
|
||||
State<CollapsableEmails> createState() => _CollapsableEmailsState();
|
||||
@ -40,21 +46,41 @@ class _CollapsableEmailsState extends State<CollapsableEmails> {
|
||||
};
|
||||
|
||||
List<String> tagsCollected = [];
|
||||
String markdown = '';
|
||||
List<String> allMarkdown = [];
|
||||
List<List<String>> sentinel = [];
|
||||
int level = 0;
|
||||
AugmentTree zoomTreeRoot = AugmentTree();
|
||||
late AugmentTree currentZoomNode;
|
||||
// late AugmentTree currentZoomNode;
|
||||
late List<AugmentTree> currentZoomTree = [];
|
||||
bool zoomOut = false;
|
||||
bool zoomIn = true;
|
||||
late List<AugmentTree> threadNodes = [];
|
||||
static bool leftNumbering = false;
|
||||
static bool rightNumbering = true;
|
||||
bool showWhole = false;
|
||||
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_markdownConverter();
|
||||
threadNodes = [];
|
||||
currentZoomTree = [];
|
||||
// _markdownConverter();
|
||||
_serializableData(widget.threadIDs); // this
|
||||
_markdown2Tree(markdown);
|
||||
_buildForZooms();
|
||||
_markdown2Tree(widget.threadMarkdown);
|
||||
}
|
||||
@override
|
||||
void didUpdateWidget(covariant CollapsableEmails oldWidget) {
|
||||
// TODO: implement didUpdateWidget
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.targetJumpNumbering != null &&
|
||||
widget.targetJumpNumbering != oldWidget.targetJumpNumbering) {
|
||||
_handleJump(widget.targetJumpNumbering!);
|
||||
}
|
||||
if (widget.targetViewspecs != null &&
|
||||
widget.targetViewspecs != oldWidget.targetViewspecs) {
|
||||
_handleViewspecs(widget.targetViewspecs!);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@ -62,10 +88,6 @@ class _CollapsableEmailsState extends State<CollapsableEmails> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _markdownConverter() async {
|
||||
markdown = html2md.convert(widget.threadHTML[0]);
|
||||
}
|
||||
|
||||
void _add2Tree(AugmentTree tree, md.Element node2add) {
|
||||
// adds node to its corresponding place
|
||||
AugmentTree newNode = AugmentTree();
|
||||
@ -119,83 +141,67 @@ class _CollapsableEmailsState extends State<CollapsableEmails> {
|
||||
}
|
||||
}
|
||||
|
||||
void _markdown2Tree(String text) {
|
||||
void _markdown2Tree(List<String> text) {
|
||||
print("started markdown2tree");
|
||||
final List<md.Node> nakedList = md.Document().parseLines(text.split('\n'));
|
||||
|
||||
for (var node in nakedList) {
|
||||
//maybe do an add function, but isn't this it?
|
||||
if (node is md.Element) {
|
||||
// print(node.textContent);
|
||||
AugmentTree temp = AugmentTree();
|
||||
temp.data = node.textContent;
|
||||
temp.ogTag = node.tag;
|
||||
if (hirarchyDict.containsKey(node.tag)) {
|
||||
_add2Tree(zoomTreeRoot, node);
|
||||
for (int emailsMD = 0; emailsMD < text.length; emailsMD++) {
|
||||
final List<md.Node> nakedList =
|
||||
md.Document().parseLines(text[emailsMD].split('\n'));
|
||||
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 (node.tag == 'h1') {
|
||||
// make this O(1)
|
||||
_add2Tree(zoomTreeRoot, node);
|
||||
} else if (node.tag == 'h2') {
|
||||
// i dont add any since i dont have it, maybe the function makes sense
|
||||
_add2Tree(zoomTreeRoot, node); // fix this
|
||||
} else if (node.tag == 'h3') {
|
||||
_add2Tree(zoomTreeRoot, node);
|
||||
} else if (node.tag == 'h4') {
|
||||
_add2Tree(zoomTreeRoot, node); // change to temp
|
||||
} else if (node.tag == 'h5') {
|
||||
_add2Tree(zoomTreeRoot, node);
|
||||
} else if (node.tag == 'h6') {
|
||||
_add2Tree(zoomTreeRoot, node); // fix this
|
||||
} else if (node.tag == 'p' || node.tag == 'ul' || node.tag == 'li') {
|
||||
_add2Tree(zoomTreeRoot, node); // fix this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentZoomNode = zoomTreeRoot;
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_isLoaded = true;
|
||||
});
|
||||
zoomTreeRoot.addNumbering();
|
||||
threadNodes.add(zoomTreeRoot);
|
||||
currentZoomTree.add(zoomTreeRoot);
|
||||
}
|
||||
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_isLoaded = true;
|
||||
});
|
||||
}
|
||||
|
||||
void _goToChildren(int index) async {
|
||||
final target = currentZoomNode.children[index];
|
||||
void _goToChildren(int indexThread, int index) async {
|
||||
final target = currentZoomTree[indexThread].children[index];
|
||||
if (target.children.isNotEmpty) {
|
||||
setState(() {
|
||||
currentZoomNode = target;
|
||||
currentZoomTree[indexThread] = target;
|
||||
});
|
||||
} else {
|
||||
print("This child has no further children.");
|
||||
}
|
||||
|
||||
// if (currentZoomNode.children.isNotEmpty) {
|
||||
// setState(() {
|
||||
// zoomIn = true;
|
||||
// zoomOut = true;
|
||||
// currentZoomNode = currentZoomNode.children[index];
|
||||
// if (currentZoomNode.children[index].children.isEmpty) {
|
||||
// print('disable in');
|
||||
// setState(() {
|
||||
// zoomIn = false;
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// } else {
|
||||
// print("disable zoom down");
|
||||
// setState(() {
|
||||
// zoomIn = false;
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
void _goToParent() async {
|
||||
if (currentZoomNode.parent != null) {
|
||||
void _goToParent(int indexThread) async {
|
||||
if (currentZoomTree[indexThread].parent != null) {
|
||||
setState(() {
|
||||
currentZoomNode = currentZoomNode.parent!;
|
||||
currentZoomTree[indexThread] = currentZoomTree[indexThread].parent!;
|
||||
});
|
||||
} else {
|
||||
print("Already at root.");
|
||||
}
|
||||
|
||||
// print("parent ${currentZoomNode.parent}");
|
||||
// print("parent ${currentZoomNode.parent!.parent}");
|
||||
// if (currentZoomNode.parent != null) {
|
||||
// setState(() {
|
||||
// currentZoomNode = currentZoomNode.parent!;
|
||||
// if (currentZoomNode.parent == null) {
|
||||
// setState(() {
|
||||
// zoomOut = false;
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// } else if (currentZoomNode.parent == null ||
|
||||
// currentZoomNode.parent!.parent == null) {
|
||||
// print("disable zoom up");
|
||||
}
|
||||
|
||||
void _serializableData(String threadID) async {
|
||||
@ -207,19 +213,23 @@ class _CollapsableEmailsState extends State<CollapsableEmails> {
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildForZooms({Key? key}) {
|
||||
Widget _buildForZooms(int indexThread) {
|
||||
// IF I GIVE IT THE INDEX????
|
||||
if (!_isLoaded) {
|
||||
return const Center(child: CircularProgressIndicator()); // loading screen
|
||||
}
|
||||
final canZoomOut = currentZoomNode.parent != null;
|
||||
|
||||
final AugmentTree currentZoomNodeForThisEmail =
|
||||
currentZoomTree[indexThread];
|
||||
|
||||
final canZoomOut = currentZoomNodeForThisEmail.parent != null;
|
||||
|
||||
return ListView.builder(
|
||||
key: key,
|
||||
itemCount: currentZoomNode.children.length,
|
||||
itemCount: currentZoomNodeForThisEmail.children.length,
|
||||
itemBuilder: (context, index) {
|
||||
final childNode = currentZoomNode.children[index];
|
||||
final childNode = currentZoomNodeForThisEmail.children[index];
|
||||
final canZoomIn = childNode.children.isNotEmpty;
|
||||
|
||||
// currentZoomNodeForThisEmail.addNumbering();
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 6.0),
|
||||
child: Material(
|
||||
@ -236,25 +246,46 @@ class _CollapsableEmailsState extends State<CollapsableEmails> {
|
||||
spacing: 4.0,
|
||||
children: [
|
||||
OutlinedButton(
|
||||
onPressed: canZoomOut ? () => _goToParent() : null,
|
||||
onPressed:
|
||||
canZoomOut ? () => _goToParent(indexThread) : null,
|
||||
child: Icon(Icons.north_west_sharp),
|
||||
),
|
||||
OutlinedButton(
|
||||
onPressed:
|
||||
canZoomIn ? () => _goToChildren(index) : null,
|
||||
onPressed: canZoomIn
|
||||
? () => _goToChildren(indexThread, index)
|
||||
: null,
|
||||
child: Icon(Icons.south_east_sharp),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(width: 12.0),
|
||||
if (leftNumbering)
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(0, 10, 5, 0),
|
||||
child: Text(
|
||||
childNode.numbering,
|
||||
style:
|
||||
TextStyle(color: Color(Colors.purple[400]!.value)),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: MarkdownBlock(
|
||||
data: currentZoomNode
|
||||
.children[index].data, // one string of markdown
|
||||
data: childNode.data,
|
||||
// data: currentZoomNode
|
||||
// .children[index].data, // one string of markdown
|
||||
config: MarkdownConfig
|
||||
.darkConfig, // or lightConfig depending on theme
|
||||
),
|
||||
),
|
||||
if (rightNumbering)
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(5, 10, 5, 0),
|
||||
child: Text(
|
||||
childNode.numbering,
|
||||
style:
|
||||
TextStyle(color: Color(Colors.purple[400]!.value)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -263,6 +294,100 @@ class _CollapsableEmailsState extends State<CollapsableEmails> {
|
||||
},
|
||||
);
|
||||
}
|
||||
void _handleJump(String queryNumbering) {
|
||||
print(queryNumbering);
|
||||
if (queryNumbering.isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Please enter a numbering to jump to.')),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final int targetEmailIndex = _expandedEmails.first;
|
||||
if (targetEmailIndex >= threadNodes.length) {
|
||||
// Error handling
|
||||
return;
|
||||
}
|
||||
|
||||
final AugmentTree rootOfCurrentEmail = threadNodes[targetEmailIndex];
|
||||
final AugmentTree? foundNode =
|
||||
_findNodeByNumbering(rootOfCurrentEmail, queryNumbering);
|
||||
|
||||
if (foundNode != null) {
|
||||
setState(() {
|
||||
currentZoomTree[targetEmailIndex] = foundNode; // Update the state
|
||||
});
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Numbering "$queryNumbering" not found.')),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _handleViewspecs(String viewspecsQuery) {
|
||||
print(viewspecsQuery);
|
||||
if (viewspecsQuery.isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Please enter the viewspecs.')),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final int targetEmailIndex = _expandedEmails.first;
|
||||
if (targetEmailIndex >= threadNodes.length) {
|
||||
// Error handling
|
||||
return;
|
||||
}
|
||||
|
||||
if (viewspecsQuery.contains('n')) {
|
||||
setState(() {
|
||||
leftNumbering = false; // Update the state
|
||||
rightNumbering = false;
|
||||
});
|
||||
}
|
||||
if (viewspecsQuery.contains('m')) {
|
||||
setState(() {
|
||||
rightNumbering = true;
|
||||
leftNumbering = true;
|
||||
});
|
||||
}
|
||||
if (viewspecsQuery.contains('H')) {
|
||||
setState(() {
|
||||
leftNumbering = !leftNumbering;
|
||||
});
|
||||
}
|
||||
if (viewspecsQuery.contains('G')) {
|
||||
setState(() {
|
||||
rightNumbering = !rightNumbering;
|
||||
});
|
||||
}
|
||||
if (viewspecsQuery.contains('w')) {
|
||||
setState(() {
|
||||
showWhole = true;
|
||||
});
|
||||
}
|
||||
|
||||
// else {
|
||||
// ScaffoldMessenger.of(context).showSnackBar(
|
||||
// SnackBar(content: Text('Numbering "$viewspecsQuery" not found.')),
|
||||
// );
|
||||
// }
|
||||
}
|
||||
|
||||
AugmentTree? _findNodeByNumbering(AugmentTree root, String numbering) {
|
||||
//recursively finds the node you mentioned
|
||||
// to find the AugmentTree node corresponding to the `numbering`.
|
||||
if (root.numbering == numbering) {
|
||||
return root;
|
||||
}
|
||||
for (var child in root.children) {
|
||||
final found = _findNodeByNumbering(child, numbering);
|
||||
if (found != null) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -294,9 +419,10 @@ class _CollapsableEmailsState extends State<CollapsableEmails> {
|
||||
constraints: BoxConstraints(
|
||||
minHeight: 100,
|
||||
maxHeight:
|
||||
MediaQuery.of(context).size.height * 0.6),
|
||||
child:
|
||||
_buildForZooms(key: ValueKey(currentZoomNode))),
|
||||
MediaQuery.of(context).size.height * 0.6,
|
||||
),
|
||||
child: _buildForZooms(index),
|
||||
),
|
||||
Divider(),
|
||||
],
|
||||
);
|
||||
|
@ -43,6 +43,9 @@ class _EmailViewState extends State<EmailView> {
|
||||
void _scrollToNumber(String spanId) {
|
||||
// AugmentClasses.handleJump(spanId);
|
||||
}
|
||||
void _viewSpecs(String command){
|
||||
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -56,7 +59,9 @@ class _EmailViewState extends State<EmailView> {
|
||||
children: [
|
||||
EmailToolbar(
|
||||
onButtonPressed: () => {},
|
||||
onJumpToSpan: _scrollToNumber
|
||||
onJumpToNumbering: _scrollToNumber,
|
||||
onViewspecs: _viewSpecs,
|
||||
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
@ -98,7 +103,7 @@ class _EmailViewState extends State<EmailView> {
|
||||
Expanded(
|
||||
child: CollapsableEmails(
|
||||
thread: widget.messages,
|
||||
threadHTML: widget.emailContent,
|
||||
threadMarkdown: widget.emailContent,
|
||||
threadIDs: widget.id,
|
||||
),
|
||||
),
|
||||
|
Loading…
Reference in New Issue
Block a user