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; 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}>'; } } 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) { if (item.length > 1 && item[0] is String && item[1] is List) { List threadIDs = List.from(item[1]); for (var threadId in threadIDs) { await fetchThreadMessages(threadId, allEmails); } } } } else { throw Exception('Failed to load threads'); } } catch (e) { print('_displayEmailsFromFolder caught error: $e'); } setState(() { emails.clear(); // emails = messagesMap.values.toList().expand((list) => list).toList(); emails.addAll(allEmails); ; }); } 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; @override void initState() { super.initState(); print(widget.id); iframeKey = Key("iframe-${widget.id}"); ui.platformViewRegistry.registerViewFactory( // 'html-view33' iframeKey.toString(), (int viewId) => html.IFrameElement() ..width = '100%' ..height = '100%' ..srcdoc = widget.emailContent ..style.border = 'none', // ..style.width = '100%', // ..style.height = '100%' ); } @override Widget build(BuildContext context) { void _handleNumbering() { // Check if the iframe content window is accessible try { js.context.callMethod('applyNumberingVisibility'); } catch (e) { print('Error accessing iframe method: $e'); // Optionally, use postMessage for cross-origin communication // js.context['iframeElement'].contentWindow.postMessage(jsify({'action': 'toggleNumbering'}), '*'); } } return Scaffold( appBar: AppBar( title: Text(widget.name), ), body: Column( children: [ EmailToolbar(onButtonPressed: _handleNumbering), 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: iframeKey, viewType: iframeKey.toString(), // 'html-view33', ), ), ], )); } }