api_service.dart 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. // import 'dart:ffi';
  2. import 'package:flutter/material.dart';
  3. import 'package:http/http.dart' as http;
  4. import 'dart:convert';
  5. import 'dart:ui_web' as ui;
  6. import 'dart:html' as html;
  7. class MailAddress {
  8. final String? name;
  9. final String address;
  10. MailAddress({this.name, required this.address});
  11. factory MailAddress.fromJson(Map<String, dynamic> json) {
  12. return MailAddress(
  13. name: json['name'],
  14. address: json['address'],
  15. );
  16. }
  17. }
  18. class SerializableMessage {
  19. final String name;
  20. final String from;
  21. final List<MailAddress> to;
  22. final List<MailAddress> cc;
  23. final String hash;
  24. // final String path;
  25. final String subject;
  26. final String date;
  27. final int uid;
  28. final String list;
  29. final String id;
  30. final String in_reply_to;
  31. SerializableMessage({
  32. required this.name,
  33. required this.from,
  34. required this.to,
  35. required this.cc,
  36. required this.hash,
  37. required this.subject,
  38. required this.date,
  39. required this.uid,
  40. required this.list,
  41. required this.id,
  42. required this.in_reply_to,
  43. });
  44. factory SerializableMessage.fromJson(Map<String, dynamic> json) {
  45. var toList = json['to'] as List;
  46. var ccList = json['cc'] as List;
  47. return SerializableMessage(
  48. name: json['name'],
  49. from: json['from'],
  50. // to: json['name', 'address']
  51. to: toList.map((i) => MailAddress.fromJson(i)).toList(),
  52. cc: ccList.map((i) => MailAddress.fromJson(i)).toList(),
  53. // path: json['path'],
  54. hash: json['hash'],
  55. subject: json['subject'],
  56. date: json['date'],
  57. uid: json['uid'],
  58. list: json['list'],
  59. id: json['id'],
  60. in_reply_to: json['in_reply_to'],
  61. );
  62. }
  63. }
  64. class EmailPage extends StatefulWidget {
  65. const EmailPage({super.key});
  66. final String title = 'Emails';
  67. @override
  68. State<EmailPage> createState() => _EmailPageState();
  69. }
  70. class _EmailPageState extends State<EmailPage> {
  71. List emails = [];
  72. void _displayEmailsFromFolder(String folder) async {
  73. // Map<String, List<SerializableMessage>> messagesMap = {};
  74. List<SerializableMessage> allEmails = [];
  75. try {
  76. var url = Uri.http(
  77. '127.0.0.1:3001', 'sorted_threads_by_date', {'folder': folder});
  78. var response = await http.get(url);
  79. // print(response.body);
  80. // Map<String, dynamic> json = jsonDecode(response.body); original
  81. // json.forEach((key, value) {
  82. // List<SerializableMessage> messages = (value as List)
  83. // .map((item) => SerializableMessage.fromJson(item))
  84. // .toList();
  85. // messagesMap[key] = messages;
  86. // });
  87. // new shit
  88. if (response.statusCode == 200) {
  89. List<dynamic> json = jsonDecode(response.body);
  90. for (var item in json) {
  91. if (item.length > 1 && item[0] is String && item[1] is List) {
  92. // print('Date: ${item[0]}, Threads: ${item[1]}');
  93. List<int> threadIDs = List<int>.from(item[1]);
  94. for (var threadId in threadIDs) {
  95. await fetchThreadMessages(threadId, allEmails);
  96. }
  97. }
  98. }
  99. } else {
  100. throw Exception('Failed to load threads');
  101. }
  102. } catch (e) {
  103. print('_displayEmailsFromFolder caught error: $e');
  104. }
  105. setState(() {
  106. emails.clear();
  107. // emails = messagesMap.values.toList().expand((list) => list).toList();
  108. emails.addAll(allEmails);
  109. // print(emails);
  110. ;
  111. });
  112. }
  113. Future<void> fetchThreadMessages(
  114. int threadId, List<SerializableMessage> allEmails) async {
  115. try {
  116. var url = Uri.http(
  117. '127.0.0.1:3001', 'get_thread_messages', {'id': threadId.toString()});
  118. // print(url);
  119. var response = await http.get(url);
  120. // print(response.body);
  121. if (response.statusCode == 200) {
  122. List<dynamic> messagesJson = jsonDecode(response.body);
  123. List<SerializableMessage> messages =
  124. messagesJson.map((mj) => SerializableMessage.fromJson(mj)).toList();
  125. allEmails.addAll(messages);
  126. } else {
  127. throw Exception(
  128. 'Failed to fetch thread messages for thread ID: $threadId');
  129. }
  130. } catch (e) {
  131. print('Error fetching thread messages: $e');
  132. }
  133. }
  134. // Future<void> getEmailJson(String threadId) async {
  135. // // List< jsonTypeShit = "";
  136. // try {
  137. // var url = Uri.http(
  138. // '127.0.0.1:3001', 'get_thread_messages', {'id': threadId.toString()});
  139. // // print(url);
  140. // var response = await http.get(url);
  141. // // print(response.body);
  142. // if (response.statusCode == 200) {
  143. // List<dynamic> messagesJson = jsonDecode(response.body);
  144. // print(messagesJson);
  145. // print("1");
  146. // List<SerializableMessage> messages =
  147. // messagesJson.map((mj) => SerializableMessage.fromJson(mj)).toList();
  148. // // allEmails.addAll(messages);
  149. // print(messages);
  150. // // jsonTypeShit = messages;
  151. // } else {
  152. // throw Exception(
  153. // 'Failed to fetch thread messages for thread ID: $threadId');
  154. // }
  155. // } catch (e) {
  156. // print('Error fetching thread messages: $e');
  157. // }
  158. // // return(messages)
  159. // }
  160. Future<String> _getEmailContent(String id) async {
  161. String content = r"""
  162. """;
  163. String restcontent = "";
  164. try {
  165. var url = Uri.http('127.0.0.1:3001', 'email', {'id': id});
  166. // print(url);
  167. var response = await http.get(url);
  168. // print(response.body);
  169. if (response.statusCode == 200) {
  170. print('ok');
  171. content = response.body;
  172. try {
  173. var restUrl =
  174. Uri.http('127.0.0.1:3001', 'get_thread_messages', {'id': id});
  175. print(restUrl);
  176. var restresponse = await http.get(restUrl);
  177. print(restresponse.statusCode);
  178. if (restresponse.statusCode == 200) {
  179. print("ok squared");
  180. restcontent = restresponse.body;
  181. }
  182. } catch (i) {
  183. print('jsoncontent caught error: $i');
  184. }
  185. }
  186. } catch (e) {
  187. print('_getEmailContent caught error: $e');
  188. }
  189. // print(content);
  190. print(restcontent);
  191. return content;
  192. }
  193. Future<List<Widget>> _getDrawerItems() async {
  194. List<String> drawerItems = [];
  195. try {
  196. var url = Uri.http('127.0.0.1:3001', 'folders');
  197. var response = await http.get(url);
  198. drawerItems = List<String>.from(json.decode(response.body));
  199. } catch (e) {
  200. print('_getDrawerItems caught error: $e');
  201. }
  202. List<Widget> drawerWidgets = [];
  203. for (String item in drawerItems) {
  204. drawerWidgets.add(
  205. ListTile(
  206. leading: Icon(Icons.mail),
  207. title: Text(item),
  208. onTap: () {
  209. _displayEmailsFromFolder(item);
  210. Navigator.pop(context);
  211. },
  212. ),
  213. );
  214. }
  215. return drawerWidgets;
  216. }
  217. @override
  218. Widget build(BuildContext context) {
  219. return Scaffold(
  220. appBar: AppBar(
  221. backgroundColor: Theme.of(context).colorScheme.inversePrimary,
  222. title: Text(widget.title),
  223. ),
  224. drawer: Drawer(
  225. child: FutureBuilder<List<Widget>>(
  226. future:
  227. _getDrawerItems(), // call the async function to get the future
  228. builder:
  229. (BuildContext context, AsyncSnapshot<List<Widget>> snapshot) {
  230. if (snapshot.connectionState == ConnectionState.waiting) {
  231. // While data is loading, show a progress indicator
  232. return Center(child: CircularProgressIndicator());
  233. } else if (snapshot.hasError) {
  234. // If something went wrong, show an error message
  235. return Center(child: Text('Error: ${snapshot.error}'));
  236. } else {
  237. // When data is fetched successfully, display the items
  238. return ListView(
  239. padding: EdgeInsets.zero,
  240. children:
  241. snapshot.data!, // Unwrap the data once confirmed it's there
  242. );
  243. }
  244. },
  245. ),
  246. ),
  247. body: EmailListScreen(emails: emails, getEmailContent: _getEmailContent),
  248. );
  249. }
  250. }
  251. class EmailListScreen extends StatelessWidget {
  252. final List emails;
  253. final Future<String> Function(String) getEmailContent;
  254. EmailListScreen({required this.emails, required this.getEmailContent});
  255. @override
  256. Widget build(BuildContext context) {
  257. // print(emails);
  258. return Scaffold(
  259. appBar: AppBar(
  260. title: Text('Emails'),
  261. ),
  262. body: ListView.separated(
  263. itemCount: emails.length,
  264. itemBuilder: (context, index) {
  265. return ListTile(
  266. title: Text(emails[index].from,
  267. style: TextStyle(fontWeight: FontWeight.bold)),
  268. subtitle: Column(
  269. crossAxisAlignment: CrossAxisAlignment.start,
  270. children: [
  271. Text(emails[index].subject),
  272. ],
  273. ),
  274. trailing: Text(emails[index].date.toString()),
  275. onTap: () async {
  276. String emailContent = await getEmailContent(emails[index].id);
  277. Navigator.push(
  278. context,
  279. MaterialPageRoute(
  280. builder: (context) =>
  281. EmailView(emailContent: emailContent)),
  282. );
  283. });
  284. },
  285. separatorBuilder: (context, index) {
  286. return Divider();
  287. },
  288. ),
  289. );
  290. }
  291. }
  292. class EmailView extends StatefulWidget {
  293. final String emailContent;
  294. const EmailView({Key? key, required this.emailContent}) : super(key: key);
  295. @override
  296. _EmailViewState createState() => _EmailViewState();
  297. // @override
  298. // void initState(){
  299. // ui.platformViewRegistry.registerViewFactory(
  300. // 'html-view33',
  301. // (int viewId) => html.IFrameElement()
  302. // ..width = '100%'
  303. // ..height = '100%'
  304. // ..srcdoc = emailContent
  305. // ..style.border = 'none');
  306. }
  307. // @override
  308. // Widget build(BuildContext context) {
  309. // return Scaffold(
  310. // appBar: AppBar(
  311. // title: Text('Email Content'),
  312. // ),
  313. // // body: SingleChildScrollView(
  314. // // child: Padding(
  315. // // padding: const EdgeInsets.all(16.0),
  316. // // child: HtmlWidget(
  317. // // emailContent,
  318. // // onErrorBuilder: (context, element, error) =>
  319. // // Text('$element error: $error'),
  320. // // onLoadingBuilder: (context, element, loadingProgress) =>
  321. // // CircularProgressIndicator(),
  322. // // renderMode: RenderMode.column,
  323. // // // webView: true,
  324. // // ),
  325. // // ),
  326. // // ),
  327. // // body: Center(
  328. // // child: Html(
  329. // // data: emailContent
  330. // // )
  331. // // ,
  332. // // ),
  333. // body: Center(
  334. // child: HtmlElementView(viewType: 'html-view33',),
  335. // ),
  336. // );
  337. // }
  338. // }
  339. // class HtmlContentWidget
  340. // class HtmlIFrameView extends StatelessWidget {
  341. // final String emailContent;
  342. // const HtmlIFrameView({required this.emailContent});
  343. // @override
  344. // Widget build(BuildContext context) {
  345. // return HtmlElementView(viewType: 'html-view');
  346. // }
  347. // }
  348. // class HtmlElementView extends StatelessWidget {
  349. // final String emailContent;
  350. // const HtmlElementView({required this.emailContent});
  351. // @override
  352. // Widget build(BuildContext context) {
  353. // return IFrameElementWidget(emailContent: emailContent);
  354. // }
  355. // }
  356. // class IFrameElementWidget extends StatelessWidget {
  357. // final String emailContent;
  358. // const IFrameElementWidget({required this.emailContent});
  359. // @override
  360. // Widget build(BuildContext context) {
  361. // ui.platformViewRegistry.registerViewFactory(
  362. // 'html-view',
  363. // (int viewId) => html.IFrameElement()
  364. // ..width = '100%'
  365. // ..height = '100%'
  366. // ..srcdoc = emailContent
  367. // ..style.border = 'none',
  368. // );
  369. // return HtmlElementView(
  370. // viewType: 'html-view',
  371. // );
  372. // }
  373. // }
  374. class _EmailViewState extends State<EmailView> {
  375. @override
  376. void initState() {
  377. super.initState();
  378. ui.platformViewRegistry.registerViewFactory(
  379. 'html-view33',
  380. (int viewId) => html.IFrameElement()
  381. ..width = '100%'
  382. ..height = '100%'
  383. ..srcdoc = widget.emailContent
  384. ..style.border = 'none',
  385. );
  386. }
  387. @override
  388. Widget build(BuildContext context) {
  389. return Scaffold(
  390. appBar: AppBar(
  391. title: Text('email content'),
  392. ),
  393. body: HtmlElementView(
  394. viewType: 'html-view33',
  395. ),
  396. );
  397. }
  398. }