diff --git a/lib/augment.dart b/lib/augment.dart index 2b8c5de..8b8fa60 100644 --- a/lib/augment.dart +++ b/lib/augment.dart @@ -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'; diff --git a/lib/collapsableEmailsAndroid.dart b/lib/collapsableEmailsAndroid.dart index 64f2cc8..d89afb4 100644 --- a/lib/collapsableEmailsAndroid.dart +++ b/lib/collapsableEmailsAndroid.dart @@ -7,13 +7,19 @@ import 'package:markdown/markdown.dart' as md; class CollapsableEmails extends StatefulWidget { final List thread; // email id's in the form xyz@gmail.com - final List threadHTML; + // final List threadHTML; + final List 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 createState() => _CollapsableEmailsState(); @@ -40,21 +46,41 @@ class _CollapsableEmailsState extends State { }; List tagsCollected = []; - String markdown = ''; + List allMarkdown = []; List> sentinel = []; int level = 0; AugmentTree zoomTreeRoot = AugmentTree(); - late AugmentTree currentZoomNode; + // late AugmentTree currentZoomNode; + late List currentZoomTree = []; bool zoomOut = false; bool zoomIn = true; + late List 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 { 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 { } } - void _markdown2Tree(String text) { + void _markdown2Tree(List text) { print("started markdown2tree"); - final List 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 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 { }); } - 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 { 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 { }, ); } + 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 { 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(), ], ); diff --git a/lib/emailViewAndroid.dart b/lib/emailViewAndroid.dart index 33eedd3..7b257a2 100644 --- a/lib/emailViewAndroid.dart +++ b/lib/emailViewAndroid.dart @@ -43,6 +43,9 @@ class _EmailViewState extends State { void _scrollToNumber(String spanId) { // AugmentClasses.handleJump(spanId); } + void _viewSpecs(String command){ + + } @override Widget build(BuildContext context) { @@ -56,7 +59,9 @@ class _EmailViewState extends State { children: [ EmailToolbar( onButtonPressed: () => {}, - onJumpToSpan: _scrollToNumber + onJumpToNumbering: _scrollToNumber, + onViewspecs: _viewSpecs, + ), Row( children: [ @@ -98,7 +103,7 @@ class _EmailViewState extends State { Expanded( child: CollapsableEmails( thread: widget.messages, - threadHTML: widget.emailContent, + threadMarkdown: widget.emailContent, threadIDs: widget.id, ), ),