402 lines
12 KiB
Dart
402 lines
12 KiB
Dart
// this file should handle most of the API calls
|
|
// it also builds some widgets, but it will be modulated later
|
|
|
|
import 'package:crab_ui/structs.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:http/http.dart' as http;
|
|
import 'dart:convert';
|
|
import 'dart:ui_web' as ui;
|
|
import 'augment.dart';
|
|
import 'dart:html' as html;
|
|
|
|
//data structure
|
|
class MailAddress {
|
|
final String? name;
|
|
final String address;
|
|
MailAddress({this.name, required this.address});
|
|
|
|
factory MailAddress.fromJson(Map<String, dynamic> json) {
|
|
return MailAddress(
|
|
name: json['name'],
|
|
address: json['address'],
|
|
);
|
|
}
|
|
|
|
@override
|
|
String toString() {
|
|
// TODO: implement toString
|
|
return '${name} <${address}>';
|
|
}
|
|
}
|
|
|
|
class EmailPage extends StatefulWidget {
|
|
// email widget
|
|
const EmailPage({super.key});
|
|
final String title = 'Emails';
|
|
|
|
@override
|
|
State<EmailPage> createState() => EmailPageState();
|
|
}
|
|
|
|
class EmailPageState extends State<EmailPage> {
|
|
List emails = [];
|
|
|
|
void _displayEmailsFromFolder(String folder) async {
|
|
List<GetThreadResponse> allEmails = []; //all the emails
|
|
|
|
try {
|
|
var url = Uri.http('127.0.0.1:3001', 'sorted_threads_by_date',
|
|
{'folder': folder, 'limit': '10', 'offset': '0'});
|
|
var response = await http.get(url);
|
|
print(response);
|
|
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<int> threadIDs = List<int>.from(item[1]);
|
|
for (var threadId in threadIDs) {
|
|
await fetchThreads(threadId, allEmails);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
throw Exception('Failed to load threads');
|
|
}
|
|
} catch (e) {
|
|
print('_displayEmailsFromFolder caught error: $e');
|
|
}
|
|
print("Done");
|
|
|
|
setState(() {
|
|
emails = allEmails;
|
|
});
|
|
}
|
|
|
|
Future<void> fetchThreads(
|
|
int threadId, List<GetThreadResponse> allEmails) async {
|
|
try {
|
|
var url =
|
|
Uri.http('127.0.0.1:3001', 'get_thread', {'id': threadId.toString()});
|
|
var response = await http.get(url);
|
|
|
|
if (response.statusCode == 200) {
|
|
Map<String, dynamic> messagesJson = jsonDecode(response.body);
|
|
GetThreadResponse threadResponse =
|
|
GetThreadResponse.fromJson(messagesJson);
|
|
|
|
allEmails.add(threadResponse);
|
|
} else {
|
|
throw Exception(
|
|
'Failed to fetch thread messages for thread ID: $threadId');
|
|
}
|
|
} catch (e) {
|
|
print('Error fetching thread messages: $e');
|
|
}
|
|
}
|
|
|
|
Future<String> _getEmailContent(List<String> IDs) async {
|
|
String content = r"""
|
|
""";
|
|
|
|
try {
|
|
//attaches email after email from a thread
|
|
for (var id in IDs) {
|
|
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;
|
|
content += "<p>end of mail</p><br><br><br>";
|
|
}
|
|
}
|
|
} catch (e) {
|
|
print('_getEmailContent caught error: $e');
|
|
}
|
|
return content;
|
|
}
|
|
|
|
// void _addMailBox async(BuildContext context){
|
|
// //add email folder
|
|
// showDialog(context: context, builder: builder)
|
|
// }
|
|
|
|
Future<List<Widget>> getDrawerItems(BuildContext context) async {
|
|
List<String> drawerItems = [];
|
|
|
|
try {
|
|
var url = Uri.http('127.0.0.1:3001', 'folders');
|
|
var response = await http.get(url);
|
|
drawerItems = List<String>.from(json.decode(response.body));
|
|
} catch (e) {
|
|
print('getDrawerItems caught error: $e');
|
|
}
|
|
|
|
List<Widget> drawerWidgets = []; // email folders
|
|
|
|
for (String item in drawerItems) {
|
|
drawerWidgets.add(
|
|
ListTile(
|
|
leading: Icon(Icons.mail),
|
|
title: Text(item),
|
|
onTap: () {
|
|
_displayEmailsFromFolder(item);
|
|
Navigator.pop(context);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
drawerWidgets.add(ListTile(
|
|
leading: Icon(Icons.add),
|
|
onTap: () {
|
|
// _addMailBox(context);
|
|
print('adding folder');
|
|
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<List<Widget>>(
|
|
future: getDrawerItems(
|
|
context), // call the async function to get the future
|
|
builder:
|
|
(BuildContext context, AsyncSnapshot<List<Widget>> 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 {
|
|
//this is the bulding of the drawer with all emails
|
|
// try to only get the subject and id, date, sender to make it faster
|
|
final List emails;
|
|
final Future<String> Function(List<String>) getEmailContent;
|
|
|
|
EmailListScreen({
|
|
required this.emails,
|
|
required this.getEmailContent,
|
|
});
|
|
// instead of getting the entire email, just the from, text, subject, and id
|
|
@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_name,
|
|
style: TextStyle(fontWeight: FontWeight.bold)),
|
|
subtitle: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(emails[index].subject),
|
|
],
|
|
),
|
|
trailing: Text(emails[index].date.toString()),
|
|
//here we assign each part of json to a var, this could be changed so it only happens,
|
|
// when clicking on email for modularity
|
|
onTap: () async {
|
|
String emailContent =
|
|
await getEmailContent(emails[index].messages);
|
|
String fromName = emails[index].from_name.toString();
|
|
String fromAddress = emails[index].from_address.toString();
|
|
String to = emails[index].to.toString();
|
|
String subject = emails[index].subject.toString();
|
|
String date = emails[index].date.toString();
|
|
String id = emails[index].id.toString();
|
|
|
|
Navigator.push(
|
|
context,
|
|
MaterialPageRoute(
|
|
builder: (context) => EmailView(
|
|
emailContent: emailContent,
|
|
from: fromAddress,
|
|
name: fromName,
|
|
to: to,
|
|
subject: subject,
|
|
date: date,
|
|
id: id,
|
|
)),
|
|
);
|
|
});
|
|
},
|
|
separatorBuilder: (context, index) {
|
|
return Divider();
|
|
},
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class EmailView extends StatefulWidget {
|
|
final String emailContent;
|
|
final String from;
|
|
final String name;
|
|
final String to;
|
|
final String subject;
|
|
final String date;
|
|
final String id;
|
|
|
|
const EmailView({
|
|
Key? key,
|
|
required this.emailContent,
|
|
required this.from,
|
|
required this.name,
|
|
required this.to,
|
|
required this.subject,
|
|
required this.date,
|
|
required this.id,
|
|
}) : super(key: key);
|
|
@override
|
|
_EmailViewState createState() => _EmailViewState();
|
|
}
|
|
|
|
class _EmailViewState extends State<EmailView> {
|
|
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);
|
|
}
|
|
|
|
// TODO: 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"""
|
|
// <h1>Welcome to My Website</h1>
|
|
// <p>This is a simple HTML page.</p>
|
|
// <h2>What is HTML?</h2>
|
|
// <p>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).</p>
|
|
// <h3>Here's a simple list:</h3>
|
|
// <ul>
|
|
// <li>HTML elements are the building blocks of HTML pages</li>
|
|
// <li>HTML uses tags like <code><tag></code> to organize and format content</li>
|
|
// <li>CSS is used with HTML to style pages</li>
|
|
// </ul>
|
|
// <p>Copyright © 2023</p>
|
|
// """);
|
|
// 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,
|
|
),
|
|
),
|
|
],
|
|
));
|
|
}
|
|
}
|