From de3d7f8bfc9a559e5f1565f842789d216b17c045 Mon Sep 17 00:00:00 2001 From: juan Date: Tue, 10 Jun 2025 14:58:34 -0400 Subject: [PATCH] works, and disabled zoom out button at root, and zoom in, when nodes don't have any children --- lib/collapsableEmailsWeb.dart | 354 +++++++++++++++------------------- 1 file changed, 157 insertions(+), 197 deletions(-) diff --git a/lib/collapsableEmailsWeb.dart b/lib/collapsableEmailsWeb.dart index b748daf..4dca67b 100644 --- a/lib/collapsableEmailsWeb.dart +++ b/lib/collapsableEmailsWeb.dart @@ -53,17 +53,20 @@ class _CollapsableEmailsState extends State { String markdown = ''; List> sentinel = []; int level = 0; - AugmentTree root = AugmentTree(); + AugmentTree zoomTreeRoot = AugmentTree(); + late AugmentTree currentZoomNode; + bool zoomOut = false; + bool zoomIn = true; @override void initState() { super.initState(); _markdownConverter(); // _registerViewFactory(widget.threadHTML); - // _serializableData(widget.threadIDs); // this + _serializableData(widget.threadIDs); // this _markdown2Tree(markdown); _keyListener(); - _buildForZooms(level); + _buildForZooms(); } @override @@ -111,6 +114,7 @@ class _CollapsableEmailsState extends State { } tree.children = [newNode]; } else { + newNode.parent = tree; tree.children.add(newNode); } // } else{ // so the node should go high @@ -131,12 +135,12 @@ class _CollapsableEmailsState extends State { return; } - print("> ${node2add.tag}"); + // print("> ${node2add.tag}"); _add2Tree(tree.children.last, node2add); } else if ((hirarchyDict[node2add.tag] ?? -1) == (hirarchyDict[tree.children.last.ogTag] ?? -1)) { - print("equals??"); + // print("equals??"); tree.children.add(newNode); newNode.parent = tree; } @@ -145,8 +149,6 @@ class _CollapsableEmailsState extends State { void _markdown2Tree(String text) { print("started markdown2tree"); - int highest = 0; - AugmentTree zoomTreeRoot = AugmentTree(); final List nakedList = md.Document().parseLines(text.split('\n')); List pList = []; List h1List = []; @@ -169,46 +171,23 @@ class _CollapsableEmailsState extends State { } else if (node.tag == 'h2') { // i dont add any since i dont have it, maybe the function makes sense h2List.add(node.textContent); + _add2Tree(zoomTreeRoot, node); // fix this } else if (node.tag == 'h3') { h3List.add(node.textContent); - root.children.add(temp); _add2Tree(zoomTreeRoot, node); } else if (node.tag == 'h4') { h4List.add(node.textContent); //this broke it _add2Tree(zoomTreeRoot, node); // change to temp - if (root.children.isNotEmpty) { - root.children.last.children.add(temp); - } } else if (node.tag == 'h5') { h5List.add(node.textContent); print(node.textContent); _add2Tree(zoomTreeRoot, node); - if (root.children.last.children.isNotEmpty) { - print("h5 index ${root.children.last.children.length}"); - root.children.last.children.last.children.add(temp); - print( - "h5 after index length ${root.children.last.children.last.children.length}"); - } } else if (node.tag == 'h6') { h6List.add(node.textContent); - if (root.children.last.children.isNotEmpty) { - print( - "h6 index ${root.children.last.children.last.children.length}"); - root.children.last.children.last.children.add(temp); - print(node.textContent); - _add2Tree(zoomTreeRoot, node); - } - // root.children.last.children.last.children.add(temp); + _add2Tree(zoomTreeRoot, node); // fix this } else if (node.tag == 'p' || node.tag == 'ul' || node.tag == 'li') { pList.add(node.textContent); _add2Tree(zoomTreeRoot, node); // fix this - - if (root.children.isEmpty) { - root.children.add(temp); - } else if (root.children.last.children.isNotEmpty) { - //perhaps recursive - root.children.last.children.last.children.add(temp); - } } } } @@ -216,31 +195,32 @@ class _CollapsableEmailsState extends State { this.sentinel = [h1List, h2List, h3List, h4List, h5List, h6List, pList]; sentinel.removeWhere((hList) => hList.isEmpty); - print('algorithm adding: '); - print("first layer: ${zoomTreeRoot.children}"); - print("first node: ${zoomTreeRoot.children[0].data}"); //good - print("second layer: ${zoomTreeRoot.children.last.children}"); //good - print( - "first node: ${zoomTreeRoot.children.last.children.first.data}"); //good - for (int n = 1; n < zoomTreeRoot.children.last.children.length - 1; n++) { - //good - print(zoomTreeRoot.children.last.children[n].data); - } - print("last node: ${zoomTreeRoot.children.last.children.last.data}"); //good - print("third layer"); - for (int thirdLayer = 0; - thirdLayer < zoomTreeRoot.children.last.children.length; - thirdLayer++) { - print(zoomTreeRoot.children.last.children[thirdLayer].children); - } - print("third layer contents first"); //not sure + // print('algorithm adding: '); + // print("first layer: ${zoomTreeRoot.children}"); + // print("first node: ${zoomTreeRoot.children[0].data}"); //good + // print("second layer: ${zoomTreeRoot.children.last.children}"); //good + // print( + // "first node: ${zoomTreeRoot.children.last.children.first.data}"); //good + // for (int n = 1; n < zoomTreeRoot.children.last.children.length - 1; n++) { + // //good + // print(zoomTreeRoot.children.last.children[n].data); + // } + // print("last node: ${zoomTreeRoot.children.last.children.last.data}"); //good + // print("third layer"); + // for (int thirdLayer = 0; + // thirdLayer < zoomTreeRoot.children.last.children.length; + // thirdLayer++) { + // print(zoomTreeRoot.children.last.children[thirdLayer].children); + // } + // print("third layer contents first"); //not sure - print(zoomTreeRoot.children.last.children[5].children[0].data); //good - for (int contentsOf4 = 1; - contentsOf4 < zoomTreeRoot.children.last.children[5].children.length; - contentsOf4++) { - print(zoomTreeRoot.children.last.children[5].children[contentsOf4].data); - } + // print(zoomTreeRoot.children.last.children[5].children[0].data); //good + // for (int contentsOf4 = 1; + // contentsOf4 < zoomTreeRoot.children.last.children[5].children.length; + // contentsOf4++) { + // print(zoomTreeRoot.children.last.children[5].children[contentsOf4].data); + // } + currentZoomNode = zoomTreeRoot; if (!mounted) return; setState(() { _isLoaded = true; @@ -256,57 +236,67 @@ class _CollapsableEmailsState extends State { setState(() { level = (level - 1).clamp(0, sentinel.length - 1); }); - // _buildForZooms(level + 1); //probably need a level? } else if (keyEvent.key == "b") { print("b"); setState(() { level = (level + 1).clamp(0, sentinel.length - 1); }); - // _buildForZooms(level - 1); //probably need a level? } } - void _registerViewFactory(List currentContent) async { - // setState(() { //update to do item per item - // each item to have itsviewtype ID - // is this necessarey here?? - - //could just move to collapsable - - for (var emailHTML in widget.threadHTML) { - String viewTypeId = 'email-${DateTime.now().millisecondsSinceEpoch}'; - - final ghost = web.document.createElement('div') as web.HTMLDivElement - ..style.visibility = 'hidden' - ..style.position = 'absolute' - ..style.width = '100%' - ..style.overflow = 'auto' - ..innerHTML = emailHTML - .toJS; // temporarily index because it has to do all of them - web.document.body?.append(ghost); - await Future.delayed(Duration(milliseconds: 10)); - - final heightOfEmail = ghost.scrollHeight; - ghost.remove(); - - final HTMLsnippet = web.document.createElement('div') - as web.HTMLDivElement - ..id = viewTypeId - ..innerHTML = emailHTML - .toJS; // temporarily index because it has to do all of them - HTMLsnippet.style - ..width = '100%' - ..height = '${heightOfEmail}px' - ..overflow = 'auto' - ..scrollBehavior = 'smooth'; - - ui.platformViewRegistry.registerViewFactory( - viewTypeId, - (int viewId) => HTMLsnippet, - ); - viewtypeIDs.add(viewTypeId); - heightOfViewTypes.add(heightOfEmail); + void _goToChildren(int index) async { + final target = currentZoomNode.children[index]; + if (target.children.isNotEmpty) { + setState(() { + currentZoomNode = 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) { + setState(() { + currentZoomNode = currentZoomNode.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 { @@ -361,7 +351,6 @@ class _CollapsableEmailsState extends State { } } else if (keyEvent.key == 'w') { print("you pressed 'w'"); - // getTopLevel(); } } @@ -376,79 +365,56 @@ class _CollapsableEmailsState extends State { web.window.document.addEventListener('keydown', _listener!); } - // void getTopLevel() { - // print("started top"); - // int highest = 0; - // AugmentTree zoomTreeRoot = AugmentTree(); - // // zoomTreeRoot.data = emailsHTML[0]; // whole thing - - // while (highest < hirarchy.length - 1) { - // var highestElement = web.document.querySelectorAll(hirarchy[highest]); - // print("nodelist $highestElement"); - - // if (highestElement.isNull || highestElement.length == 0) { - // //from h1, h2, h3, ..., p. - // highest += 1; - // print(hirarchy[highest]); - // } else { - // AugmentTree newLevel = AugmentTree(); // list of children of each level - // for (int i = 0; i < highestElement.length; i++) { - // print(highestElement.item(i)?.textContent); - - // tagsCollected - // .add(highestElement.item(i)?.textContent ?? "nameless subtitle"); - // newLevel.children - // .add(highestElement.item(i)?.textContent ?? "nameless subtitle"); - // } - // // traverse to last node and add new level to it - // // next - // if (zoomTreeRoot.node == null) { - // zoomTreeRoot.node = newLevel; - // } else { - // AugmentTree temp = zoomTreeRoot; - // while (true) { - // //get to the last and assign node = last node - // if (temp.node != null) { - // temp = temp.node!; - // } else { - // temp.node = newLevel; - // break; - // } - // } - // } - - // highest += 1; - // } - // } - // print("out safely"); - // print(tagsCollected); //instead of a list make a tree - // print(zoomTreeRoot.children); - // print(zoomTreeRoot.node?.children); - // print(zoomTreeRoot.node?.node?.children); - // print(zoomTreeRoot.node?.node?.node?.children); - // } - - Widget _buildForZooms(int lvl) { - this.level = lvl; - if (lvl < 0 || lvl >= sentinel.length) { - return Center(child: Text("No content at level $lvl")); + Widget _buildForZooms({Key? key}) { + if (!_isLoaded) { + return const Center(child: CircularProgressIndicator()); // loading screen } + final canZoomOut = currentZoomNode.parent != null; + return ListView.builder( - itemCount: this.sentinel[level].length, + key: key, + itemCount: currentZoomNode.children.length, itemBuilder: (context, index) { + final childNode = currentZoomNode.children[index]; + final canZoomIn = childNode.children.isNotEmpty; + return Padding( padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 6.0), child: Material( elevation: 1, borderRadius: BorderRadius.circular(12), color: Theme.of(context).colorScheme.surface, - surfaceTintColor: Theme.of(context).colorScheme.surfaceTint, + surfaceTintColor: Theme.of(context).colorScheme.surfaceBright, child: Padding( padding: const EdgeInsets.all(16.0), - child: MarkdownBlock( - data: sentinel[level][index], // one string of markdown - config: MarkdownConfig - .darkConfig, // or lightConfig depending on theme + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Wrap( + spacing: 4.0, + children: [ + OutlinedButton( + onPressed: + canZoomOut ? () => _goToParent() : null, + child: Icon(Icons.north_west_sharp), + ), + OutlinedButton( + onPressed: + canZoomIn ? () => _goToChildren(index) : null, + child: Icon(Icons.south_east_sharp), + ), + ], + ), + SizedBox(width: 12.0), + Expanded( + child: MarkdownBlock( + data: currentZoomNode + .children[index].data, // one string of markdown + config: MarkdownConfig + .darkConfig, // or lightConfig depending on theme + ), + ), + ], ), ), ), @@ -462,43 +428,37 @@ class _CollapsableEmailsState extends State { return _isLoaded ? Column(children: [ Expanded( - // child: MarkdownWidget(data: markdown), //hmmm - child: _buildForZooms(level), + child: ListView.builder( + itemCount: emailsInThread.length, + itemBuilder: (context, index) { + final isExpanded = _expandedEmails + .contains(index); //check if email is expanded + return Column( + children: [ + ListTile( + title: Text(emailsInThread[index].from), + trailing: Text(emailsInThread[index].date), + onTap: () { + setState(() { + if (isExpanded) { + _expandedEmails.remove(index); + } else { + _expandedEmails.add(index); + } + }); + }, + ), + if (isExpanded) + SizedBox( + height: 800, + child: + _buildForZooms(key: ValueKey(currentZoomNode))), + Divider(), + ], + ); + }, + ), ) - - // Expanded( - // child: ListView.builder( - // itemCount: widget.thread.length, - // itemBuilder: (context, index) { - // final isExpanded = _expandedEmails - // .contains(index); //check if email is expanded - // return Column( - // children: [ - // ListTile( - // title: Text(emailsInThread[index].from), - // trailing: Text(emailsInThread[index].date), - // onTap: () { - // setState(() { - // if (isExpanded) { - // _expandedEmails.remove(index); - // } else { - // _expandedEmails.add(index); - // } - // }); - // }, - // ), - // if (isExpanded) - // SizedBox( - // height: heightOfViewTypes[index].toDouble(), - // child: HtmlElementView( - // key: UniqueKey(), viewType: viewtypeIDs[index]), - // ), - // Divider(), - // ], - // ); - // }, - // ), - // ) ]) : const Center(child: CircularProgressIndicator()); }