Reviewed-on: #3
This commit is contained in:
commit
4fa8e5b6fe
@ -1,20 +1,29 @@
|
||||
// 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 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||
|
||||
import '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;
|
||||
import 'dart:js' as js;
|
||||
|
||||
class ApiService {
|
||||
static String ip = "";
|
||||
static String port = "";
|
||||
static List<AttachmentResponse> threadAttachments = [];
|
||||
static String currFolder = "";
|
||||
static List<String> currThread = [];
|
||||
|
||||
Future<List<GetThreadResponse>> fetchEmailsFromFolder(
|
||||
String folder, int pagenitaion) async {
|
||||
// print(ip + " " + port);
|
||||
try {
|
||||
var url = Uri.http('$ip:$port', 'sorted_threads_by_date', {
|
||||
'folder': folder,
|
||||
@ -51,8 +60,8 @@ class ApiService {
|
||||
int threadId,
|
||||
List<GetThreadResponse> allEmails) async {
|
||||
try {
|
||||
var url =
|
||||
Uri.http('$ip:$port', 'get_thread', {'id': threadId.toString()});
|
||||
var url = Uri.http('${ApiService.ip}:${ApiService.port}', 'get_thread',
|
||||
{'id': threadId.toString()});
|
||||
var response = await http.get(url);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
@ -97,24 +106,34 @@ class ApiService {
|
||||
return [];
|
||||
}
|
||||
|
||||
Future<String> fetchEmailContent(List<String> IDs) async {
|
||||
//returns the html for the email, it gets used in emailView
|
||||
Future<String> fetchEmailContent(
|
||||
List<String> IDsString, String emailFolder) async {
|
||||
String content = r"""
|
||||
""";
|
||||
threadAttachments = [];
|
||||
|
||||
try {
|
||||
//attaches email after email from a thread
|
||||
for (var id in IDs) {
|
||||
for (var id in IDsString) {
|
||||
var url = Uri.http('$ip:$port', 'email', {'id': id});
|
||||
|
||||
var response = await http.get(url);
|
||||
|
||||
currThread.add(id);
|
||||
if (response.statusCode == 200) {
|
||||
content += response.body;
|
||||
try {
|
||||
getAttachmentsInfo("INBOX", id);
|
||||
List<AttachmentInfo> attachments = await getAttachmentsInfo(
|
||||
emailFolder, id);
|
||||
for (var attachment in attachments) {
|
||||
//TODO: for each attachment creaate at the bottom a widget for each individual one
|
||||
threadAttachments
|
||||
.add(await getAttachment(emailFolder, id, attachment.name));
|
||||
}
|
||||
} catch (innerError) {
|
||||
print('_getAttachment info caught error $innerError');
|
||||
}
|
||||
content +=
|
||||
"""<div id="JuanBedarramarker" style="width: 10px; height: 30px;"></div>""";
|
||||
content += "<hr>";
|
||||
}
|
||||
}
|
||||
@ -200,18 +219,21 @@ class ApiService {
|
||||
Future<List<AttachmentInfo>> getAttachmentsInfo(
|
||||
String folder, String email_id) async {
|
||||
try {
|
||||
var url = Uri.http('127.0.0.1:3001', 'get_attachments_info',
|
||||
{'folder': folder, 'email_id': email_id});
|
||||
print(url);
|
||||
var url = Uri.http('$ip:$port', 'get_attachments_info',
|
||||
{'folder': folder, 'id': email_id});
|
||||
// print(url);
|
||||
var response = await http.get(url);
|
||||
print("response $response");
|
||||
// print("response $response");
|
||||
if (response.statusCode == 200) {
|
||||
var result = response.body;
|
||||
// print(result);
|
||||
List<dynamic> attachmentList = json.decode(result);
|
||||
print("attachment list $attachmentList");
|
||||
// Map<String, dynamic> attachmentList = json.decode(result);
|
||||
|
||||
// print("attachment list $attachmentList");
|
||||
List<AttachmentInfo> attachments =
|
||||
attachmentList.map((al) => AttachmentInfo.fromJson(al)).toList();
|
||||
print("attachments $attachments");
|
||||
// print("attachments $attachments");
|
||||
|
||||
return attachments;
|
||||
}
|
||||
@ -220,6 +242,98 @@ class ApiService {
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
Future<AttachmentResponse> getAttachment(
|
||||
String folder, String email_id, String name) async {
|
||||
try {
|
||||
var url = Uri.http('$ip:$port', 'get_attachment',
|
||||
{'folder': folder, 'id': email_id, 'name': name});
|
||||
var response = await http.get(url);
|
||||
if (response.statusCode == 200) {
|
||||
var result = response.body;
|
||||
// print(result);
|
||||
Map<String, dynamic> attachmentData = json.decode(result);
|
||||
AttachmentResponse data = AttachmentResponse.fromJson(attachmentData);
|
||||
print("data $data");
|
||||
return data;
|
||||
}
|
||||
} catch (e) {
|
||||
print("getAttachment failed $e");
|
||||
}
|
||||
return AttachmentResponse(name: "error", data: Uint8List(0));
|
||||
}
|
||||
|
||||
Future<List<Map<String, dynamic>>> getMarkerPosition() async {
|
||||
//this is so we can put a widget right below each email, but the way how the email content is generated
|
||||
//leads to problems as for a) the html is added one right after the other in one iframe, b)
|
||||
// if it was multiple iframes then the scrolling to jump would not work as expected
|
||||
|
||||
|
||||
print("marker called");
|
||||
// JavaScript code embedded as a string
|
||||
String jsCode = '''
|
||||
(async function waitForIframeAndMarkers() {
|
||||
try {
|
||||
return await new Promise((resolve) => {
|
||||
const interval = setInterval(() => {
|
||||
console.log("⏳ Checking for iframe...");
|
||||
var iframe = document.getElementsByTagName('iframe')[0];
|
||||
if (iframe && iframe.contentDocument) {
|
||||
console.log("✅ Iframe found!");
|
||||
var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
|
||||
var markers = iframeDoc.querySelectorAll('[id^="JuanBedarramarker"]');
|
||||
if (markers.length > 0) {
|
||||
console.log(`✅ Found markers in the iframe.`);
|
||||
var positions = [];
|
||||
markers.forEach((marker) => {
|
||||
var rect = marker.getBoundingClientRect();
|
||||
positions.push({
|
||||
id: marker.id,
|
||||
x: rect.left + window.scrollX,
|
||||
y: rect.top + window.scrollY,
|
||||
});
|
||||
});
|
||||
console.log("📌 Marker positions:", positions);
|
||||
clearInterval(interval);
|
||||
resolve(JSON.stringify(positions)); // Ensure proper JSON string
|
||||
} else {
|
||||
console.log("❌ No markers found yet.");
|
||||
}
|
||||
} else {
|
||||
console.log("❌ Iframe not found or not loaded yet.");
|
||||
}
|
||||
}, 200);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("JS Error:", error);
|
||||
throw error; // Propagate error to Dart
|
||||
}
|
||||
})();
|
||||
''';
|
||||
|
||||
try {
|
||||
// Execute the JavaScript code using eval
|
||||
final result = await js.context.callMethod('eval', [jsCode]);
|
||||
|
||||
if (result != null && result is String) {
|
||||
print("Result received: $result");
|
||||
|
||||
// Parse the JSON string returned by JavaScript into a Dart list of maps
|
||||
final List<dynamic> parsedResult = jsonDecode(result);
|
||||
var positions = List<Map<String, dynamic>>.from(parsedResult);
|
||||
print("positions put on");
|
||||
print(positions);
|
||||
return positions;
|
||||
} else {
|
||||
print("result is null or not a string");
|
||||
}
|
||||
} catch (e, stackTrace) {
|
||||
print("Error executing JavaScript: $e");
|
||||
print(stackTrace);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
class EmailView extends StatefulWidget {
|
||||
@ -246,10 +360,18 @@ class EmailView extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _EmailViewState extends State<EmailView> {
|
||||
//html css rendering thing
|
||||
late Key iframeKey;
|
||||
late String currentContent;
|
||||
late String viewTypeId;
|
||||
Future<List<Map<String, dynamic>>>? _markerPositionsFuture;
|
||||
// TextEditingController _jumpController = TextEditingController();
|
||||
final hardcodedMarkers = [
|
||||
{'id': 'marker1', 'x': 50, 'y': 100},
|
||||
{'id': 'marker2', 'x': 150, 'y': 200},
|
||||
{'id': 'marker3', 'x': 250, 'y': 300},
|
||||
];
|
||||
ApiService _apiService = ApiService();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -257,6 +379,7 @@ class _EmailViewState extends State<EmailView> {
|
||||
String currentContent = widget.emailContent;
|
||||
viewTypeId = "iframe-${DateTime.now().millisecondsSinceEpoch}";
|
||||
_registerViewFactory(currentContent);
|
||||
_markerPositionsFuture = ApiService().getMarkerPosition();
|
||||
}
|
||||
|
||||
void _registerViewFactory(String currentContent) {
|
||||
@ -276,7 +399,7 @@ class _EmailViewState extends State<EmailView> {
|
||||
AugmentClasses.handleJump(spanId);
|
||||
}
|
||||
|
||||
// TODO: void _invisibility(String )
|
||||
// TODO: void _invisibility(String ) //to make purple numbers not visible
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -285,7 +408,9 @@ class _EmailViewState extends State<EmailView> {
|
||||
appBar: AppBar(
|
||||
title: Text(widget.name),
|
||||
),
|
||||
body: Column(
|
||||
body: Stack(
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
EmailToolbar(
|
||||
onJumpToSpan: _scrollToNumber,
|
||||
@ -309,8 +434,7 @@ class _EmailViewState extends State<EmailView> {
|
||||
// print("change");
|
||||
// widget.emailContent = r"
|
||||
|
||||
// "
|
||||
// },
|
||||
//
|
||||
),
|
||||
Row(
|
||||
// title of email
|
||||
@ -355,6 +479,71 @@ class _EmailViewState extends State<EmailView> {
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
// Overlay widgets dynamically based on marker positions
|
||||
FutureBuilder<List<Map<String, dynamic>>>(
|
||||
future: _markerPositionsFuture,
|
||||
builder: (context, snapshot) {
|
||||
print("FutureBuilder state: ${snapshot.connectionState}");
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return Center(child: CircularProgressIndicator());
|
||||
}
|
||||
if (snapshot.hasError) {
|
||||
print("Error in FutureBuilder: ${snapshot.error}");
|
||||
return Center(child: Text('error loading markers'));
|
||||
}
|
||||
if (snapshot.hasData && snapshot.data != null) {
|
||||
final markers = snapshot.data!;
|
||||
return Stack(
|
||||
children: markers.map((marker) {
|
||||
return Positioned(
|
||||
left: marker['x'].toDouble(),
|
||||
top: marker['y'].toDouble(),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
print('Tapped on ${marker['id']}');
|
||||
},
|
||||
child: Container(
|
||||
width: 50,
|
||||
height: 50,
|
||||
color: Colors.red,
|
||||
child: Center(
|
||||
child: Text(
|
||||
marker['id'],
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
}
|
||||
|
||||
return SizedBox.shrink(); // No markers found
|
||||
},
|
||||
),
|
||||
// Red widget overlay
|
||||
// Positioned(
|
||||
// left: 8, // Adjust based on your desired position
|
||||
// top: 100 + 44 + 5, // Adjust based on your desired position
|
||||
// child: IgnorePointer(
|
||||
// ignoring: true, // Ensures the iframe remains interactive
|
||||
// child: Container(
|
||||
// color: Colors.red,
|
||||
// width: 100,
|
||||
// height: 50,
|
||||
// child: Center(
|
||||
// child: Text(
|
||||
// 'Overlay',
|
||||
// style: TextStyle(color: Colors.white),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
));
|
||||
}
|
||||
}
|
||||
|
14
lib/attachmentDownload.dart
Normal file
14
lib/attachmentDownload.dart
Normal file
@ -0,0 +1,14 @@
|
||||
import 'dart:html' as html;
|
||||
import 'dart:io';
|
||||
import 'structs.dart';
|
||||
import 'package:file_saver/file_saver.dart';
|
||||
|
||||
class Attachmentdownload {
|
||||
Future<void> saveFile(AttachmentResponse attachment) async {
|
||||
await FileSaver.instance.saveFile(
|
||||
name: attachment.name.toString().substring(0, attachment.name.toString().lastIndexOf('.')),
|
||||
bytes: attachment.data,
|
||||
ext: attachment.name.toString().substring(attachment.name.toString().lastIndexOf('.')+1)
|
||||
);
|
||||
}
|
||||
}
|
103
lib/attachmentWidget.dart
Normal file
103
lib/attachmentWidget.dart
Normal file
@ -0,0 +1,103 @@
|
||||
import "dart:typed_data";
|
||||
|
||||
import "package:crab_ui/attachmentDownload.dart";
|
||||
import "package:crab_ui/structs.dart";
|
||||
import "package:flutter/material.dart";
|
||||
import 'package:pdfrx/pdfrx.dart';
|
||||
import 'package:photo_view/photo_view.dart';
|
||||
|
||||
class AttachmentWidget extends StatelessWidget {
|
||||
final AttachmentResponse attachment;
|
||||
AttachmentWidget({required this.attachment});
|
||||
|
||||
Widget attachmentViewer(AttachmentResponse att) {
|
||||
String extension = att.name
|
||||
.toString()
|
||||
.substring(att.name.toString().indexOf(".") + 1)
|
||||
.toLowerCase();
|
||||
if (extension == "jpg" || extension == "png") {
|
||||
return Image.memory(att.data);
|
||||
} else if (extension == "pdf") {
|
||||
return PdfViewer.data(Uint8List.fromList(att.data),
|
||||
sourceName: att.name,
|
||||
params: PdfViewerParams(
|
||||
enableTextSelection: true,
|
||||
scrollByMouseWheel: 0.5,
|
||||
annotationRenderingMode:
|
||||
PdfAnnotationRenderingMode.annotationAndForms,
|
||||
));
|
||||
}
|
||||
return Center(
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xff6C63FF),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black26,
|
||||
blurRadius: 10,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
"No preview available",
|
||||
style: TextStyle(
|
||||
color: Colors.white, fontSize: 18, decoration: TextDecoration.none),
|
||||
),
|
||||
SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
GestureDetector(
|
||||
child: ElevatedButton(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text("Download", style: TextStyle(color: Color(0xff2c3e50)),),
|
||||
Icon(Icons.download,
|
||||
color: Color(0xffb0b0b0),),
|
||||
]),
|
||||
onPressed: () => Attachmentdownload().saveFile(att),
|
||||
)),
|
||||
]),
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.black38,
|
||||
child: Stack(children: <Widget>[
|
||||
Container(
|
||||
color: Colors.white,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.fromLTRB(10, 20, 0, 10),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
CloseButton(onPressed: () => {Navigator.pop(context)}),
|
||||
Text(
|
||||
attachment.name
|
||||
.toString(), //its alr a string but incase ¯\(ツ)/¯ //update: i did that everywhere lol
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 20,
|
||||
decoration: TextDecoration
|
||||
.none), //TODO: personalize your fonts
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: attachmentViewer(attachment),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
]));
|
||||
}
|
||||
}
|
103
lib/augment.dart
103
lib/augment.dart
@ -1,6 +1,12 @@
|
||||
import 'package:crab_ui/api_service.dart';
|
||||
import 'package:crab_ui/attachmentDownload.dart';
|
||||
import 'package:crab_ui/structs.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||
import 'dart:html' as html;
|
||||
import 'dart:js' as js;
|
||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||
import 'attachmentWidget.dart';
|
||||
|
||||
class EmailToolbar extends StatefulWidget {
|
||||
final Function(String) onJumpToSpan;
|
||||
@ -64,8 +70,8 @@ class _DynamicClassesAugment extends State<EmailToolbar> {
|
||||
child: Text('Reload'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: AugmentClasses.handleImages,
|
||||
child: Text('Images'),
|
||||
onPressed: () => AugmentClasses.handleImages(context),
|
||||
child: Text('Attachments'),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
ElevatedButton(
|
||||
@ -206,6 +212,8 @@ class _DynamicClassesAugment extends State<EmailToolbar> {
|
||||
}
|
||||
|
||||
class AugmentClasses {
|
||||
ApiService _apiService = ApiService();
|
||||
static OverlayEntry? _overlayEntry;
|
||||
static void handleHome(BuildContext context) {
|
||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||
}
|
||||
@ -214,8 +222,96 @@ class AugmentClasses {
|
||||
print("reload");
|
||||
}
|
||||
|
||||
static void handleImages() {
|
||||
static void handleImages(BuildContext context) {
|
||||
print("Images button pressed");
|
||||
final overlay = Overlay.of(context);
|
||||
final renderBox = context.findRenderObject() as RenderBox;
|
||||
final offset = renderBox.localToGlobal(Offset.zero);
|
||||
|
||||
_overlayEntry = OverlayEntry(
|
||||
builder: (context) => Stack(
|
||||
children: [
|
||||
// Dimmed background
|
||||
Container(
|
||||
color: Colors.black54,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: MediaQuery.of(context).size.height,
|
||||
),
|
||||
// Focused content window
|
||||
PointerInterceptor(
|
||||
child: Center(
|
||||
child: Material(
|
||||
elevation: 8,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 400,
|
||||
maxHeight: 500,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
_buildHeader(context),
|
||||
const Divider(height: 1),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
children: _buildMenuItem(context),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
if (_overlayEntry != null) {
|
||||
overlay.insert(_overlayEntry!);
|
||||
}
|
||||
}
|
||||
|
||||
// Add missing widget builder methods
|
||||
static Widget _buildHeader(BuildContext context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
child:
|
||||
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||
Text(
|
||||
'Thread Attachments',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
CloseButton(
|
||||
onPressed: () {
|
||||
_overlayEntry?.remove();
|
||||
},
|
||||
),
|
||||
]));
|
||||
}
|
||||
|
||||
static List<Widget> _buildMenuItem(BuildContext context) {
|
||||
List<Widget> listOfFiles = [];
|
||||
for (AttachmentResponse file in ApiService.threadAttachments) {
|
||||
listOfFiles.add(
|
||||
ListTile (
|
||||
leading: Icon(Icons.file_present),
|
||||
title: Text(file.name.toString()),
|
||||
trailing: GestureDetector(
|
||||
child: Icon(Icons.download),
|
||||
onTap: () => Attachmentdownload().saveFile(file),
|
||||
),
|
||||
onTap: () {
|
||||
_overlayEntry?.remove();
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => AttachmentWidget(attachment: file)));
|
||||
}));
|
||||
}
|
||||
return listOfFiles;
|
||||
}
|
||||
|
||||
static void handleOpen() {
|
||||
@ -517,6 +613,7 @@ class AugmentClasses {
|
||||
}
|
||||
|
||||
static void disableIframePointerEvents() {
|
||||
//pretty sure these dont work
|
||||
final iframes = html.document.getElementsByTagName('iframe');
|
||||
for (var iframe in iframes) {
|
||||
if (iframe is html.Element) {
|
||||
|
@ -4,10 +4,12 @@ import 'structs.dart';
|
||||
|
||||
class EmailListScreen extends StatelessWidget {
|
||||
final List<GetThreadResponse> emails;
|
||||
final Future<String> Function(List<String>) getEmailContent;
|
||||
final Future<String> Function(List<String>, String) getEmailContent;
|
||||
final String folder;
|
||||
|
||||
EmailListScreen({required this.emails, required this.getEmailContent});
|
||||
|
||||
EmailListScreen({required this.emails, required this.getEmailContent, required this.folder});
|
||||
//fix the email list
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@ -24,7 +26,7 @@ class EmailListScreen extends StatelessWidget {
|
||||
),
|
||||
trailing: Text(email.date.toString()),
|
||||
onTap: () async {
|
||||
String emailContent = await getEmailContent(email.messages);
|
||||
String emailContent = await getEmailContent(email.messages, folder);
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
@ -51,7 +53,7 @@ class EmailListScreen extends StatelessWidget {
|
||||
// ignore: must_be_immutable
|
||||
class EmailPage extends StatefulWidget {
|
||||
EmailPage({Key? key}) : super(key: key);
|
||||
String selectedFolder = "INBOX";
|
||||
String selectedFolder = "INBOX"; //starter
|
||||
int offset = 0;
|
||||
int page = 1;
|
||||
|
||||
@ -62,11 +64,14 @@ class EmailPage extends StatefulWidget {
|
||||
class EmailPageState extends State<EmailPage> {
|
||||
final ApiService apiService = ApiService();
|
||||
List<GetThreadResponse> emails = [];
|
||||
int page = 1;
|
||||
bool isBackDisabled = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
widget.page = widget.page;
|
||||
widget.page = page;
|
||||
isBackDisabled = true;
|
||||
}
|
||||
|
||||
void updateSelectedFolder(String folder) {
|
||||
@ -86,11 +91,16 @@ class EmailPageState extends State<EmailPage> {
|
||||
setState(() {
|
||||
widget.offset += 50;
|
||||
widget.page += 1;
|
||||
isBackDisabled = false;
|
||||
});
|
||||
} else if (option == "back") {
|
||||
setState(() {
|
||||
widget.offset -= 50;
|
||||
widget.page -= 1;
|
||||
if (widget.page == 1) {
|
||||
isBackDisabled = true;
|
||||
print("back dis");
|
||||
}
|
||||
});
|
||||
}
|
||||
// print(currentPage);
|
||||
@ -119,6 +129,7 @@ class EmailPageState extends State<EmailPage> {
|
||||
body: EmailListScreen(
|
||||
emails: emails,
|
||||
getEmailContent: apiService.fetchEmailContent,
|
||||
folder: widget.selectedFolder,//try to grab from it directly
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
import 'package:crab_ui/folder_drawer.dart';
|
||||
import 'package:crab_ui/structs.dart';
|
||||
import 'folder_drawer.dart';
|
||||
import 'structs.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'api_service.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'email.dart';
|
||||
// import 'package:shared_preferences/shared_preferences.dart';
|
||||
// import 'serialize.dart';
|
||||
|
||||
class HomeScreen extends StatefulWidget {
|
||||
@ -119,7 +120,7 @@ class _HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
|
||||
body: ListView.separated(
|
||||
itemCount: result.length,
|
||||
itemBuilder: (context, index) {
|
||||
final email = result[index];
|
||||
final SerializableMessage email = result[index];
|
||||
return ListTile(
|
||||
title: Text(email.from,
|
||||
style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
@ -131,7 +132,7 @@ class _HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
|
||||
onTap: () async {
|
||||
// print('tapped');
|
||||
String emailContent =
|
||||
await apiService.fetchEmailContent([email.id]);
|
||||
await apiService.fetchEmailContent([email.id], email.list);
|
||||
// print('content below');
|
||||
// print(emailContent);
|
||||
Navigator.push(
|
||||
@ -341,7 +342,7 @@ class _HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
|
||||
children: [
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
_emailPageKey.currentState
|
||||
_emailPageKey.currentState!.isBackDisabled ? null: _emailPageKey.currentState
|
||||
?.updatePagenation('back');
|
||||
},
|
||||
child: Icon(Icons.navigate_before),
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'dart:convert';
|
||||
import 'package:crab_ui/api_service.dart';
|
||||
import 'package:crab_ui/home_page.dart';
|
||||
// import 'package:crab_ui/api_service.dart';
|
||||
import 'api_service.dart';
|
||||
import 'home_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
// import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
@ -11,7 +12,9 @@ class AuthService {
|
||||
Future<bool> isUserLoggedIn() async {
|
||||
try {
|
||||
final response =
|
||||
await http.get(Uri.parse('http://localhost:6823/read-config'));
|
||||
await http.get(Uri.http('localhost:6823', 'read-config'));
|
||||
// await http.get(Uri.parse('http://localhost:6823/read-config'));
|
||||
|
||||
print(response.statusCode);
|
||||
print(response.body);
|
||||
if (response.statusCode == 200) {
|
||||
@ -27,7 +30,9 @@ class AuthService {
|
||||
Map<String, dynamic> json = jsonDecode(jsonOuter);
|
||||
// print(json["is_logged_in"]);
|
||||
ApiService.ip = data['ip'];
|
||||
print("setting ip " + ApiService.ip);
|
||||
ApiService.port = data['port'];
|
||||
print("setting port " + data['port']);
|
||||
return json["is_logged_in"];
|
||||
}
|
||||
} catch (er) {
|
||||
@ -35,6 +40,7 @@ class AuthService {
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
print('caughtther');
|
||||
print(e);
|
||||
}
|
||||
return false;
|
||||
|
@ -61,7 +61,7 @@ class _SerializableMessageListScreenState extends State<SerializableMessageListS
|
||||
),
|
||||
trailing: Text(message.date),
|
||||
onTap: () async {
|
||||
String emailContent = await apiService.fetchEmailContent([message.id]);
|
||||
String emailContent = await apiService.fetchEmailContent([message.id], message.list);
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
|
@ -1,5 +1,7 @@
|
||||
//data structures
|
||||
|
||||
import 'dart:typed_data';
|
||||
|
||||
class GetThreadResponse {
|
||||
final int id;
|
||||
final List<String> messages;
|
||||
@ -76,7 +78,7 @@ class SerializableMessage {
|
||||
required this.subject,
|
||||
required this.date,
|
||||
required this.uid,
|
||||
required this.list,
|
||||
required this.list, //email list???
|
||||
required this.id,
|
||||
required this.in_reply_to,
|
||||
});
|
||||
@ -118,3 +120,29 @@ class AttachmentInfo {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AttachmentInfoList extends Iterable<AttachmentInfo> {
|
||||
final List<AttachmentInfo> _attachments;
|
||||
|
||||
AttachmentInfoList(this._attachments);
|
||||
|
||||
factory AttachmentInfoList.fromJsonList(List<Map<String, dynamic>> jsonList) {
|
||||
return AttachmentInfoList(jsonList.map((json) => AttachmentInfo.fromJson(json)).toList());
|
||||
}
|
||||
|
||||
@override
|
||||
Iterator<AttachmentInfo> get iterator => _attachments.iterator;
|
||||
|
||||
@override
|
||||
String toString() => _attachments.toString();
|
||||
}
|
||||
|
||||
class AttachmentResponse {
|
||||
final name;
|
||||
final Uint8List data;
|
||||
AttachmentResponse({required this.name, required this.data});
|
||||
|
||||
factory AttachmentResponse.fromJson(Map<String, dynamic> json) {
|
||||
return AttachmentResponse(name: json["name"], data: Uint8List.fromList(List<int>.from(json["data"])));
|
||||
}
|
||||
}
|
||||
|
@ -18,10 +18,15 @@ dependencies:
|
||||
encrypt: ^5.0.0
|
||||
pointycastle: ^3.4.0
|
||||
mime: ^1.0.3
|
||||
pointer_interceptor: ^0.10.1+2
|
||||
file_saver: ^0.2.14
|
||||
|
||||
|
||||
english_words: ^4.0.0
|
||||
provider: ^6.0.0
|
||||
intl: ^0.19.0
|
||||
pdfrx: ^1.0.94
|
||||
photo_view: ^0.15.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
Loading…
Reference in New Issue
Block a user