import 'dart:js_interop'; import 'package:web/web.dart' as web; import 'package:flutter/material.dart'; import 'dart:ui_web' as ui; import 'api_service.dart'; import 'structs.dart'; class CollapsableEmails extends StatefulWidget { final List thread; // email id's in the form xyz@gmail.com final List threadHTML; final String threadIDs; CollapsableEmails( {required this.thread, required this.threadHTML, required this.threadIDs}); @override State createState() => _CollapsableEmailsState(); } class _CollapsableEmailsState extends State { List emailsHTML = []; //html of the emails in the thread // build attachments with the forldar name and id Set _expandedEmails = {}; //open emails List viewtypeIDs = []; //IDs of the viewtypes, order matters List heightOfViewTypes = []; //the height of each viewtype List emailsInThread = []; bool _isLoaded = false; @override void initState() { // TODO: implement initState super.initState(); _registerViewFactory(widget.threadHTML); _serializableData(widget.threadIDs); } 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 _serializableData(String threadID) async { emailsInThread = await ApiService().threadsInSerializable(threadID); print("done thread serializable"); if (!mounted) return; setState(() { _isLoaded = true; }); } @override Widget build(BuildContext context) { return _isLoaded ?Column(children: [ 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) // if(viewtypeIDs[index] == null || heightOfViewTypes[index] == null) // const SizedBox(height: 100, child: Center(child: CircularProgressIndicator())), SizedBox( height: heightOfViewTypes[index].toDouble(), child: HtmlElementView( key: UniqueKey(), viewType: viewtypeIDs[index]), ), Divider(), ], ); }, ), ) ]): const Center(child:CircularProgressIndicator()); } }