import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; import 'dart:ui_web' as ui; import 'dart:html' as html; import 'augment.dart'; import 'dart:js' as js; //data structure class MailAddress { final String? name; final String address; MailAddress({this.name, required this.address}); factory MailAddress.fromJson(Map json) { return MailAddress( name: json['name'], address: json['address'], ); } @override String toString() { // TODO: implement toString return '${name} <${address}>'; } } //data structure class SerializableMessage { final String name; final String from; final List to; final List cc; final String hash; // final String path; 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, required this.id, required this.in_reply_to, }); factory SerializableMessage.fromJson(Map 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 EmailPage extends StatefulWidget { const EmailPage({super.key}); final String title = 'Emails'; @override State createState() => _EmailPageState(); } class _EmailPageState extends State { List emails = []; void _displayEmailsFromFolder(String folder) async { // Map> messagesMap = {}; List allEmails = []; try { var url = Uri.http( '127.0.0.1:3001', 'sorted_threads_by_date', {'folder': folder}); var response = await http.get(url); print(response.body); // Map json = jsonDecode(response.body); original // json.forEach((key, value) { // List messages = (value as List) // .map((item) => SerializableMessage.fromJson(item)) // .toList(); // messagesMap[key] = messages; // }); // new shit if (response.statusCode == 200) { List json = jsonDecode(response.body); for (var item in json.take(1)) { //each item in the json is a date if (item.length > 1 && item[0] is String && item[1] is List) { List threadIDs = List.from(item[1]); for (var threadId in threadIDs) { print(threadId); await fetchThreadMessages(threadId, allEmails); } //TODO: get exact thread with new api endpoint from chosen thread? } } } else { throw Exception('Failed to load threads'); } } catch (e) { print('_displayEmailsFromFolder caught error: $e'); } print("Done"); setState(() { emails.clear(); // emails = messagesMap.values.toList().expand((list) => list).toList(); emails.addAll(allEmails); ; }); } // Future fetchThreads(AboutDialog){ // } Future fetchThreadMessages( int threadId, List allEmails) async { try { var url = Uri.http( '127.0.0.1:3001', 'get_thread_messages', {'id': threadId.toString()}); var response = await http.get(url); if (response.statusCode == 200) { List messagesJson = jsonDecode(response.body); List messages = messagesJson.map((mj) => SerializableMessage.fromJson(mj)).toList(); allEmails.addAll(messages); } else { throw Exception( 'Failed to fetch thread messages for thread ID: $threadId'); } } catch (e) { print('Error fetching thread messages: $e'); } } Future _getEmailContent(String id) async { String content = r""" """; try { var url = Uri.http('127.0.0.1:3001', 'email', {'id': id}); var response = await http.get(url); if (response.statusCode == 200) { content = response.body; } } catch (e) { print('_getEmailContent caught error: $e'); } return content; } Future> _getDrawerItems() async { List drawerItems = []; try { var url = Uri.http('127.0.0.1:3001', 'folders'); var response = await http.get(url); drawerItems = List.from(json.decode(response.body)); } catch (e) { print('_getDrawerItems caught error: $e'); } List drawerWidgets = []; for (String item in drawerItems) { drawerWidgets.add( ListTile( leading: Icon(Icons.mail), title: Text(item), onTap: () { _displayEmailsFromFolder(item); Navigator.pop(context); }, ), ); } return drawerWidgets; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: Text(widget.title), ), drawer: Drawer( child: FutureBuilder>( future: _getDrawerItems(), // call the async function to get the future builder: (BuildContext context, AsyncSnapshot> snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { // While data is loading, show a progress indicator return Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { // If something went wrong, show an error message return Center(child: Text('Error: ${snapshot.error}')); } else { // When data is fetched successfully, display the items return ListView( padding: EdgeInsets.zero, children: snapshot.data!, // Unwrap the data once confirmed it's there ); } }, ), ), body: EmailListScreen( emails: emails, getEmailContent: _getEmailContent, // getJsonEmail: _getThreadMessagesJson ), ); } } class EmailListScreen extends StatelessWidget { final List emails; final Future Function(String) getEmailContent; EmailListScreen({ required this.emails, required this.getEmailContent, }); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Emails'), ), body: ListView.separated( itemCount: emails.length, itemBuilder: (context, index) { return ListTile( title: Text(emails[index].from, style: TextStyle(fontWeight: FontWeight.bold)), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(emails[index].subject), ], ), trailing: Text(emails[index].date.toString()), onTap: () async { String emailContent = await getEmailContent(emails[index].id); String from = emails[index].from.toString(); String name = emails[index].name.toString(); String to = emails[index].to.toString(); String cc = emails[index].cc.toString(); String hash = emails[index].hash.toString(); String subject = emails[index].subject.toString(); String date = emails[index].date.toString(); String uid = emails[index].uid.toString(); String list = emails[index].list.toString(); String id = emails[index].id.toString(); String in_reply_to = emails[index].in_reply_to.toString(); // String jsonbuilt = Navigator.push( context, MaterialPageRoute( builder: (context) => EmailView( emailContent: emailContent, // jsonEmail: jsonContent, from: from, name: name, to: to, cc: cc, hash: hash, subject: subject, date: date, uid: uid, list: list, id: id, in_reply_to: in_reply_to, )), ); }); }, separatorBuilder: (context, index) { return Divider(); }, ), ); } } class EmailView extends StatefulWidget { final String emailContent; // final String jsonEmail; final String from; final String name; final String to; final String cc; final String hash; final String subject; final String date; final String uid; final String list; final String id; final String in_reply_to; const EmailView( {Key? key, required this.emailContent, // required this.jsonEmail, required this.from, required this.name, required this.to, required this.cc, required this.hash, required this.subject, required this.date, required this.uid, required this.list, required this.id, required this.in_reply_to}) : super(key: key); @override _EmailViewState createState() => _EmailViewState(); } class _EmailViewState extends State { late Key iframeKey; late String currentContent; late String viewTypeId; TextEditingController _jumpController = TextEditingController(); @override void initState() { super.initState(); String currentContent = widget.emailContent; viewTypeId = "iframe-${DateTime.now().millisecondsSinceEpoch}"; _registerViewFactory(currentContent); } void _registerViewFactory(String currentContent) { setState(() { viewTypeId = 'iframe-${DateTime.now().millisecondsSinceEpoch}'; ui.platformViewRegistry.registerViewFactory( viewTypeId, (int viewId) => html.IFrameElement() ..width = '100%' ..height = '100%' ..srcdoc = currentContent ..style.border = 'none'); }); } void _scrollToNumber(String spanId) { AugmentClasses.handleJump(spanId); } // void _invisibility(String ) @override Widget build(BuildContext context) { // print(currentContent); return Scaffold( appBar: AppBar( title: Text(widget.name), ), body: Column( children: [ EmailToolbar( onJumpToSpan: _scrollToNumber, onButtonPressed: () => {}, // AugmentClasses.handleJump(viewTypeId, '1'); // print("button got pressed?"); // _registerViewFactory(r""" //

Welcome to My Website

//

This is a simple HTML page.

//

What is HTML?

//

HTML (HyperText Markup Language) is the most basic building block of the Web. It defines the meaning and structure of web content. Other technologies besides HTML are generally used to describe a web page's appearance/presentation (CSS) or functionality/behavior (JavaScript).

//

Here's a simple list:

//
    //
  • HTML elements are the building blocks of HTML pages
  • //
  • HTML uses tags like <tag> to organize and format content
  • //
  • CSS is used with HTML to style pages
  • //
//

Copyright © 2023

// """); // print("change"); // widget.emailContent = r" // " // }, ), Row( // title of email children: [ Text( widget.subject, style: TextStyle(fontSize: 30), ), ], ), Row( children: [ Text( 'from ${widget.name}', style: TextStyle(fontSize: 18), ), Text( '<${widget.from}>', style: TextStyle(fontSize: 18), ), Spacer(), Text( '${widget.date}', textAlign: TextAlign.right, ) ], ), // TODO: make a case where if one of these is the user's email it just says me :))))) Row( children: [ Text( 'to ${widget.to.toString()}', style: TextStyle(fontSize: 15), ) ], ), Expanded( child: HtmlElementView( key: UniqueKey(), viewType: viewTypeId, ), ), ], )); } }