Compare commits
6 Commits
9ecf126869
...
7a6eea64e1
Author | SHA1 | Date | |
---|---|---|---|
7a6eea64e1 | |||
50528de0f2 | |||
36e6cbb2f1 | |||
8eeb0b013d | |||
04a871a293 | |||
152d744498 |
19
lib/SonicEmailViewAndroid.dart
Normal file
19
lib/SonicEmailViewAndroid.dart
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import 'structs.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class SonicEmailView extends StatefulWidget {
|
||||||
|
SerializableMessage email;
|
||||||
|
String emailHTML;
|
||||||
|
|
||||||
|
SonicEmailView({required this.email, required this.emailHTML});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_SonicEmailViewState createState() => _SonicEmailViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SonicEmailViewState extends State<SonicEmailView> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(body: Text("sonic email android"));
|
||||||
|
}
|
||||||
|
}
|
22
lib/SonicEmailViewStub.dart
Normal file
22
lib/SonicEmailViewStub.dart
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import 'structs.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class SonicEmailView extends StatefulWidget {
|
||||||
|
SerializableMessage email;
|
||||||
|
String emailHTML;
|
||||||
|
|
||||||
|
SonicEmailView({required this.email, required this.emailHTML});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_SonicEmailViewState createState() => _SonicEmailViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SonicEmailViewState extends State<SonicEmailView> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body:Text("sonic email stub")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
145
lib/SonicEmailViewWeb.dart
Normal file
145
lib/SonicEmailViewWeb.dart
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
import 'package:crab_ui/augment.dart';
|
||||||
|
import 'package:web/web.dart' as web;
|
||||||
|
import 'dart:ui_web' as ui;
|
||||||
|
import 'dart:js_interop';
|
||||||
|
import 'structs.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class SonicEmailView extends StatefulWidget {
|
||||||
|
SerializableMessage email;
|
||||||
|
String emailHTML;
|
||||||
|
|
||||||
|
SonicEmailView({required this.email, required this.emailHTML});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_SonicEmailViewState createState() => _SonicEmailViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SonicEmailViewState extends State<SonicEmailView> {
|
||||||
|
String viewTypeIDs = "";
|
||||||
|
int heightOFViewtype = 0;
|
||||||
|
bool _isLoaded = false;
|
||||||
|
|
||||||
|
void _scrollToNumber(String spanId) {
|
||||||
|
AugmentClasses.handleJump(spanId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _init() async {
|
||||||
|
await _registerViewFactory(widget.emailHTML);
|
||||||
|
if (!mounted) return;
|
||||||
|
setState(() {
|
||||||
|
_isLoaded = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _registerViewFactory(String currentContent) async {
|
||||||
|
// setState(() { //update to do item per item
|
||||||
|
// each item to have itsviewtype ID
|
||||||
|
// is this necessarey here??
|
||||||
|
|
||||||
|
//could just move to collapsable
|
||||||
|
|
||||||
|
// for (var emailHTML in widget.threadHTML) {
|
||||||
|
String viewTypeId = 'email-${DateTime.now().millisecondsSinceEpoch}';
|
||||||
|
|
||||||
|
final ghost = web.document.createElement('div') as web.HTMLDivElement
|
||||||
|
..style.visibility = 'hidden'
|
||||||
|
..style.position = 'absolute'
|
||||||
|
..style.width = '100%'
|
||||||
|
..style.overflow = 'auto'
|
||||||
|
..innerHTML = currentContent.toJS;
|
||||||
|
web.document.body?.append(ghost);
|
||||||
|
await Future.delayed(Duration(milliseconds: 10));
|
||||||
|
|
||||||
|
final heightOfEmail = ghost.scrollHeight;
|
||||||
|
ghost.remove();
|
||||||
|
|
||||||
|
final HTMLsnippet = web.document.createElement('div') as web.HTMLDivElement
|
||||||
|
..id = viewTypeId
|
||||||
|
..innerHTML = widget
|
||||||
|
.emailHTML.toJS; // temporarily index because it has to do all of them
|
||||||
|
HTMLsnippet.style
|
||||||
|
..width = '100%'
|
||||||
|
..height = '${heightOfEmail}px'
|
||||||
|
..overflow = 'auto'
|
||||||
|
..scrollBehavior = 'smooth';
|
||||||
|
|
||||||
|
ui.platformViewRegistry.registerViewFactory(
|
||||||
|
viewTypeId,
|
||||||
|
(int viewId) => HTMLsnippet,
|
||||||
|
);
|
||||||
|
this.viewTypeIDs = viewTypeId;
|
||||||
|
this.heightOFViewtype = heightOfEmail;
|
||||||
|
print(viewTypeIDs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return _isLoaded
|
||||||
|
? Scaffold(
|
||||||
|
appBar: AppBar(title: Text(widget.email.subject)),
|
||||||
|
body: Stack(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
EmailToolbar(
|
||||||
|
onButtonPressed: () => {},
|
||||||
|
onJumpToSpan: _scrollToNumber),
|
||||||
|
Row(
|
||||||
|
// title of email
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
widget.email.subject,
|
||||||
|
style: TextStyle(fontSize: 30),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'from ${widget.email.name}',
|
||||||
|
style: TextStyle(fontSize: 18),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'<${widget.email.from}>',
|
||||||
|
style: TextStyle(fontSize: 18),
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
|
Text(
|
||||||
|
'${widget.email.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.email.to.toString()}',
|
||||||
|
style: TextStyle(fontSize: 15),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
// child: SizedBox(
|
||||||
|
// height: heightOFViewtype.toDouble(),
|
||||||
|
child: HtmlElementView(
|
||||||
|
key: UniqueKey(), viewType: this.viewTypeIDs,
|
||||||
|
// ),
|
||||||
|
))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -4,19 +4,12 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
|
||||||
import 'collapsableEmails.dart';
|
|
||||||
|
|
||||||
import 'structs.dart';
|
import 'structs.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:ui_web' as ui;
|
|
||||||
import 'augment.dart';
|
|
||||||
// import 'dart:html' as html;
|
|
||||||
// import 'dart:js' as js;
|
|
||||||
import 'package:web/web.dart' as web;
|
|
||||||
import 'dart:js_interop' as js;
|
|
||||||
|
|
||||||
class ApiService {
|
class ApiService {
|
||||||
static String ip = "";
|
static String ip = "";
|
||||||
@ -422,237 +415,4 @@ class ApiService {
|
|||||||
|
|
||||||
// return [];
|
// return [];
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
class EmailView extends StatefulWidget {
|
|
||||||
final List<String> emailContent;
|
|
||||||
final String from;
|
|
||||||
final String name;
|
|
||||||
final String to;
|
|
||||||
final String subject;
|
|
||||||
final String date;
|
|
||||||
final String id;
|
|
||||||
final List<String> messages;
|
|
||||||
|
|
||||||
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,
|
|
||||||
required this.messages,
|
|
||||||
}) : super(key: key);
|
|
||||||
@override
|
|
||||||
_EmailViewState createState() => _EmailViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _EmailViewState extends State<EmailView> {
|
|
||||||
//html css rendering thing
|
|
||||||
late Key iframeKey;
|
|
||||||
late String currentContent;
|
|
||||||
late String viewTypeId; //make this a list too???
|
|
||||||
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},
|
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
print("thread id? ${widget.id}");
|
|
||||||
List<String> currentContent = widget
|
|
||||||
.emailContent; //html of the email/ actually entire thread, gives me little space to play in between
|
|
||||||
// i wonder if the other attributes change? because if so i have to add like some zooms in and out of the emails, as in collapse
|
|
||||||
// _registerViewFactory(currentContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// void _registerViewFactory(List<String> currentContent) { // i think this doesnt work anymore
|
|
||||||
// setState(() { //update to do item per item
|
|
||||||
// // each item to have itsviewtype ID
|
|
||||||
// // is this necessarey here??
|
|
||||||
|
|
||||||
// //could just move to collapsable
|
|
||||||
|
|
||||||
// viewTypeId = 'iframe-${DateTime.now().millisecondsSinceEpoch}';
|
|
||||||
// final emailHTML = web.document.createElement('div') as web.HTMLDivElement
|
|
||||||
// ..id = viewTypeId
|
|
||||||
// ..innerHTML = currentContent[0].toJS; // temporarily index because it has to do all of them
|
|
||||||
// emailHTML.style
|
|
||||||
// ..width = '100%'
|
|
||||||
// ..height = '100%'
|
|
||||||
// ..overflow = 'auto'
|
|
||||||
// ..scrollBehavior = 'smooth';
|
|
||||||
|
|
||||||
// ui.platformViewRegistry.registerViewFactory(
|
|
||||||
// viewTypeId,
|
|
||||||
// (int viewId) => emailHTML,
|
|
||||||
// );
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
void _scrollToNumber(String spanId) {
|
|
||||||
AugmentClasses.handleJump(spanId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: void _invisibility(String ) //to make purple numbers not visible
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
// print("thread id ${widget.id}");
|
|
||||||
ApiService.currThreadID = widget.id;
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text(widget.name),
|
|
||||||
),
|
|
||||||
body: Stack(
|
|
||||||
children: [
|
|
||||||
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: CollapsableEmails(
|
|
||||||
//change here
|
|
||||||
thread: widget.messages, //this wont work in serializable
|
|
||||||
threadHTML: widget.emailContent,
|
|
||||||
threadIDs: widget.id,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// Expanded(
|
|
||||||
// child: HtmlElementView(
|
|
||||||
// key: UniqueKey(),
|
|
||||||
// viewType: viewTypeId,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
|
|
||||||
// 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),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
],
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
7
lib/attachamentDownloadStub.dart
Normal file
7
lib/attachamentDownloadStub.dart
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import 'structs.dart';
|
||||||
|
|
||||||
|
class Attachmentdownload {
|
||||||
|
Future<void> saveFile(AttachmentResponse attachment) async {
|
||||||
|
print("stub attachment download");
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +1,3 @@
|
|||||||
import 'dart:html' as html;
|
export 'attachamentDownloadStub.dart'
|
||||||
import 'package:web/web.dart' as web;
|
if (dart.library.io) 'attachmentDownloadAndroid.dart';
|
||||||
import 'dart:io';
|
// if (dart.library.js_interop) 'attachmentDownloadWeb.dart';
|
||||||
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)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
7
lib/attachmentDownloadAndroid.dart
Normal file
7
lib/attachmentDownloadAndroid.dart
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import 'structs.dart';
|
||||||
|
|
||||||
|
class Attachmentdownload {
|
||||||
|
Future<void> saveFile(AttachmentResponse attachment) async {
|
||||||
|
print("android attachment download");
|
||||||
|
}
|
||||||
|
}
|
12
lib/attachmentDownloadWeb.dart
Normal file
12
lib/attachmentDownloadWeb.dart
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// 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)
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
@ -1,103 +1,3 @@
|
|||||||
import "dart:typed_data";
|
export 'attachmentWidgetStub.dart'
|
||||||
|
if (dart.library.js_interop) 'attachmentWidgetWeb.dart'
|
||||||
import "package:crab_ui/attachmentDownload.dart";
|
if (dart.library.io) 'attachmentWidgetAndroid.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),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
}
|
|
16
lib/attachmentWidgetAndroid.dart
Normal file
16
lib/attachmentWidgetAndroid.dart
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import "package:crab_ui/structs.dart";
|
||||||
|
import "package:flutter/material.dart";
|
||||||
|
|
||||||
|
|
||||||
|
class AttachmentWidget extends StatelessWidget {
|
||||||
|
final AttachmentResponse attachment;
|
||||||
|
AttachmentWidget({required this.attachment});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: Text("PDF EVENTUALLY ANDROID")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
14
lib/attachmentWidgetStub.dart
Normal file
14
lib/attachmentWidgetStub.dart
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'structs.dart';
|
||||||
|
|
||||||
|
class AttachmentWidget extends StatelessWidget{
|
||||||
|
final AttachmentResponse attachment;
|
||||||
|
AttachmentWidget({required this.attachment});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: Text("PDF EVENTUALLY, STUB")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
101
lib/attachmentWidgetWeb.dart
Normal file
101
lib/attachmentWidgetWeb.dart
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
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';
|
||||||
|
|
||||||
|
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),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
@ -1,14 +1,7 @@
|
|||||||
// import 'dart:ffi';
|
|
||||||
|
|
||||||
import 'package:crab_ui/api_service.dart';
|
import 'package:crab_ui/api_service.dart';
|
||||||
import 'package:crab_ui/attachmentDownload.dart';
|
import 'package:crab_ui/attachmentDownload.dart';
|
||||||
import 'package:crab_ui/structs.dart';
|
import 'package:crab_ui/structs.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:pdfrx/pdfrx.dart';
|
|
||||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
|
||||||
// import 'dart:html' as html;
|
|
||||||
// import 'dart:js' as js;
|
|
||||||
import 'package:web/web.dart' as web;
|
|
||||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||||
import 'attachmentWidget.dart';
|
import 'attachmentWidget.dart';
|
||||||
|
|
||||||
|
@ -1,132 +1,3 @@
|
|||||||
import 'dart:js_interop';
|
export 'collapsableEmailsStub.dart'
|
||||||
import 'package:web/web.dart' as web;
|
if (dart.library.io) 'collapsableEmailsAndroid.dart'
|
||||||
import 'package:flutter/material.dart';
|
if (dart.library.js_interop) 'collapsableEmailsWeb.dart';
|
||||||
import 'dart:ui_web' as ui;
|
|
||||||
import 'api_service.dart';
|
|
||||||
import 'structs.dart';
|
|
||||||
|
|
||||||
class CollapsableEmails extends StatefulWidget {
|
|
||||||
final List<String> thread; // email id's in the form xyz@gmail.com
|
|
||||||
final List<String> threadHTML;
|
|
||||||
final String threadIDs;
|
|
||||||
|
|
||||||
CollapsableEmails(
|
|
||||||
{required this.thread,
|
|
||||||
required this.threadHTML,
|
|
||||||
required this.threadIDs});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<CollapsableEmails> createState() => _CollapsableEmailsState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _CollapsableEmailsState extends State<CollapsableEmails> {
|
|
||||||
List<String> emailsHTML = []; //html of the emails in the thread
|
|
||||||
// build attachments with the forldar name and id
|
|
||||||
Set<int> _expandedEmails = {}; //open emails
|
|
||||||
List viewtypeIDs = []; //IDs of the viewtypes, order matters
|
|
||||||
List heightOfViewTypes = []; //the height of each viewtype
|
|
||||||
List<SerializableMessage> emailsInThread = [];
|
|
||||||
bool _isLoaded = false;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
// TODO: implement initState
|
|
||||||
super.initState();
|
|
||||||
_registerViewFactory(widget.threadHTML);
|
|
||||||
_serializableData(widget.threadIDs);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _registerViewFactory(List<String> currentContent) async {
|
|
||||||
// setState(() { //update to do item per item
|
|
||||||
// each item to have itsviewtype ID
|
|
||||||
// is this necessarey here??
|
|
||||||
|
|
||||||
//could just move to collapsable
|
|
||||||
|
|
||||||
for (var emailHTML in widget.threadHTML) {
|
|
||||||
String viewTypeId = 'email-${DateTime.now().millisecondsSinceEpoch}';
|
|
||||||
|
|
||||||
final ghost = web.document.createElement('div') as web.HTMLDivElement
|
|
||||||
..style.visibility = 'hidden'
|
|
||||||
..style.position = 'absolute'
|
|
||||||
..style.width = '100%'
|
|
||||||
..style.overflow = 'auto'
|
|
||||||
..innerHTML = emailHTML
|
|
||||||
.toJS; // temporarily index because it has to do all of them
|
|
||||||
web.document.body?.append(ghost);
|
|
||||||
await Future.delayed(Duration(milliseconds: 10));
|
|
||||||
|
|
||||||
final heightOfEmail = ghost.scrollHeight;
|
|
||||||
ghost.remove();
|
|
||||||
|
|
||||||
final HTMLsnippet = web.document.createElement('div')
|
|
||||||
as web.HTMLDivElement
|
|
||||||
..id = viewTypeId
|
|
||||||
..innerHTML = emailHTML
|
|
||||||
.toJS; // temporarily index because it has to do all of them
|
|
||||||
HTMLsnippet.style
|
|
||||||
..width = '100%'
|
|
||||||
..height = '${heightOfEmail}px'
|
|
||||||
..overflow = 'auto'
|
|
||||||
..scrollBehavior = 'smooth';
|
|
||||||
|
|
||||||
ui.platformViewRegistry.registerViewFactory(
|
|
||||||
viewTypeId,
|
|
||||||
(int viewId) => HTMLsnippet,
|
|
||||||
);
|
|
||||||
viewtypeIDs.add(viewTypeId);
|
|
||||||
heightOfViewTypes.add(heightOfEmail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _serializableData(String threadID) async {
|
|
||||||
emailsInThread = await ApiService().threadsInSerializable(threadID);
|
|
||||||
print("done thread serializable");
|
|
||||||
if (!mounted) return;
|
|
||||||
setState(() {
|
|
||||||
_isLoaded = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return _isLoaded
|
|
||||||
?Column(children: [
|
|
||||||
Expanded(
|
|
||||||
child: ListView.builder(
|
|
||||||
itemCount: widget.thread.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final isExpanded =
|
|
||||||
_expandedEmails.contains(index); //check if email is expanded
|
|
||||||
return Column(
|
|
||||||
children: [
|
|
||||||
ListTile(
|
|
||||||
title: Text(emailsInThread[index].from),
|
|
||||||
trailing: Text(emailsInThread[index].date),
|
|
||||||
onTap: () {
|
|
||||||
setState(() {
|
|
||||||
if (isExpanded) {
|
|
||||||
_expandedEmails.remove(index);
|
|
||||||
} else {
|
|
||||||
_expandedEmails.add(index);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
if (isExpanded)
|
|
||||||
// if(viewtypeIDs[index] == null || heightOfViewTypes[index] == null)
|
|
||||||
// const SizedBox(height: 100, child: Center(child: CircularProgressIndicator())),
|
|
||||||
SizedBox(
|
|
||||||
height: heightOfViewTypes[index].toDouble(),
|
|
||||||
child: HtmlElementView(
|
|
||||||
key: UniqueKey(), viewType: viewtypeIDs[index]),
|
|
||||||
),
|
|
||||||
Divider(),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
]): const Center(child:CircularProgressIndicator());
|
|
||||||
}
|
|
||||||
}
|
|
48
lib/collapsableEmailsAndroid.dart
Normal file
48
lib/collapsableEmailsAndroid.dart
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import 'structs.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
|
||||||
|
|
||||||
|
class CollapsableEmails extends StatefulWidget {
|
||||||
|
final List<String> thread; // email id's in the form xyz@gmail.com
|
||||||
|
final List<String> threadHTML;
|
||||||
|
final String threadIDs;
|
||||||
|
|
||||||
|
CollapsableEmails(
|
||||||
|
{required this.thread,
|
||||||
|
required this.threadHTML,
|
||||||
|
required this.threadIDs});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<CollapsableEmails> createState() => _CollapsableEmailsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CollapsableEmailsState extends State<CollapsableEmails> {
|
||||||
|
List<String> emailsHTML = []; //html of the emails in the thread
|
||||||
|
// build attachments with the forldar name and id
|
||||||
|
Set<int> _expandedEmails = {}; //open emails
|
||||||
|
List viewtypeIDs = []; //IDs of the viewtypes, order matters
|
||||||
|
List heightOfViewTypes = []; //the height of each viewtype
|
||||||
|
List<SerializableMessage> emailsInThread = [];
|
||||||
|
bool _isLoaded = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
//html
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: ListView(
|
||||||
|
children: [
|
||||||
|
HtmlWidget(
|
||||||
|
widget.threadHTML[0],
|
||||||
|
// renderMode: RenderMode.listView,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
23
lib/collapsableEmailsStub.dart
Normal file
23
lib/collapsableEmailsStub.dart
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import 'structs.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class CollapsableEmails extends StatefulWidget {
|
||||||
|
final List<String> thread; // email id's in the form xyz@gmail.com
|
||||||
|
final List<String> threadHTML;
|
||||||
|
final String threadIDs;
|
||||||
|
|
||||||
|
CollapsableEmails(
|
||||||
|
{required this.thread,
|
||||||
|
required this.threadHTML,
|
||||||
|
required this.threadIDs});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<CollapsableEmails> createState() => _CollapsableEmailsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CollapsableEmailsState extends State<CollapsableEmails> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(body: Text("collapsable stud"));
|
||||||
|
}
|
||||||
|
}
|
132
lib/collapsableEmailsWeb.dart
Normal file
132
lib/collapsableEmailsWeb.dart
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
import 'dart:js_interop';
|
||||||
|
import 'package:web/web.dart' as web;
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'dart:ui_web' as ui;
|
||||||
|
import 'api_service.dart';
|
||||||
|
import 'structs.dart';
|
||||||
|
|
||||||
|
class CollapsableEmails extends StatefulWidget {
|
||||||
|
final List<String> thread; // email id's in the form xyz@gmail.com
|
||||||
|
final List<String> threadHTML;
|
||||||
|
final String threadIDs;
|
||||||
|
|
||||||
|
CollapsableEmails(
|
||||||
|
{required this.thread,
|
||||||
|
required this.threadHTML,
|
||||||
|
required this.threadIDs});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<CollapsableEmails> createState() => _CollapsableEmailsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CollapsableEmailsState extends State<CollapsableEmails> {
|
||||||
|
List<String> emailsHTML = []; //html of the emails in the thread
|
||||||
|
// build attachments with the forldar name and id
|
||||||
|
Set<int> _expandedEmails = {}; //open emails
|
||||||
|
List viewtypeIDs = []; //IDs of the viewtypes, order matters
|
||||||
|
List heightOfViewTypes = []; //the height of each viewtype
|
||||||
|
List<SerializableMessage> emailsInThread = [];
|
||||||
|
bool _isLoaded = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
// TODO: implement initState
|
||||||
|
super.initState();
|
||||||
|
_registerViewFactory(widget.threadHTML);
|
||||||
|
_serializableData(widget.threadIDs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _registerViewFactory(List<String> currentContent) async {
|
||||||
|
// setState(() { //update to do item per item
|
||||||
|
// each item to have itsviewtype ID
|
||||||
|
// is this necessarey here??
|
||||||
|
|
||||||
|
//could just move to collapsable
|
||||||
|
|
||||||
|
for (var emailHTML in widget.threadHTML) {
|
||||||
|
String viewTypeId = 'email-${DateTime.now().millisecondsSinceEpoch}';
|
||||||
|
|
||||||
|
final ghost = web.document.createElement('div') as web.HTMLDivElement
|
||||||
|
..style.visibility = 'hidden'
|
||||||
|
..style.position = 'absolute'
|
||||||
|
..style.width = '100%'
|
||||||
|
..style.overflow = 'auto'
|
||||||
|
..innerHTML = emailHTML
|
||||||
|
.toJS; // temporarily index because it has to do all of them
|
||||||
|
web.document.body?.append(ghost);
|
||||||
|
await Future.delayed(Duration(milliseconds: 10));
|
||||||
|
|
||||||
|
final heightOfEmail = ghost.scrollHeight;
|
||||||
|
ghost.remove();
|
||||||
|
|
||||||
|
final HTMLsnippet = web.document.createElement('div')
|
||||||
|
as web.HTMLDivElement
|
||||||
|
..id = viewTypeId
|
||||||
|
..innerHTML = emailHTML
|
||||||
|
.toJS; // temporarily index because it has to do all of them
|
||||||
|
HTMLsnippet.style
|
||||||
|
..width = '100%'
|
||||||
|
..height = '${heightOfEmail}px'
|
||||||
|
..overflow = 'auto'
|
||||||
|
..scrollBehavior = 'smooth';
|
||||||
|
|
||||||
|
ui.platformViewRegistry.registerViewFactory(
|
||||||
|
viewTypeId,
|
||||||
|
(int viewId) => HTMLsnippet,
|
||||||
|
);
|
||||||
|
viewtypeIDs.add(viewTypeId);
|
||||||
|
heightOfViewTypes.add(heightOfEmail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _serializableData(String threadID) async {
|
||||||
|
emailsInThread = await ApiService().threadsInSerializable(threadID);
|
||||||
|
print("done thread serializable");
|
||||||
|
if (!mounted) return;
|
||||||
|
setState(() {
|
||||||
|
_isLoaded = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return _isLoaded
|
||||||
|
?Column(children: [
|
||||||
|
Expanded(
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: widget.thread.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final isExpanded =
|
||||||
|
_expandedEmails.contains(index); //check if email is expanded
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
title: Text(emailsInThread[index].from),
|
||||||
|
trailing: Text(emailsInThread[index].date),
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
if (isExpanded) {
|
||||||
|
_expandedEmails.remove(index);
|
||||||
|
} else {
|
||||||
|
_expandedEmails.add(index);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if (isExpanded)
|
||||||
|
// if(viewtypeIDs[index] == null || heightOfViewTypes[index] == null)
|
||||||
|
// const SizedBox(height: 100, child: Center(child: CircularProgressIndicator())),
|
||||||
|
SizedBox(
|
||||||
|
height: heightOfViewTypes[index].toDouble(),
|
||||||
|
child: HtmlElementView(
|
||||||
|
key: UniqueKey(), viewType: viewtypeIDs[index]),
|
||||||
|
),
|
||||||
|
Divider(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]): const Center(child:CircularProgressIndicator());
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:http/http.dart' as http;
|
// import 'package:http/http.dart' as http;
|
||||||
import 'package:flutter_html/flutter_html.dart';
|
// import 'package:flutter_html/flutter_html.dart';
|
||||||
|
|
||||||
class ContactsPage extends StatefulWidget {
|
class ContactsPage extends StatefulWidget {
|
||||||
const ContactsPage({super.key});
|
const ContactsPage({super.key});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
import 'api_service.dart';
|
import 'api_service.dart';
|
||||||
import 'structs.dart';
|
import 'structs.dart';
|
||||||
|
import 'emailView.dart';
|
||||||
|
|
||||||
class EmailListScreen extends StatelessWidget {
|
class EmailListScreen extends StatelessWidget {
|
||||||
final List<GetThreadResponse> emails;
|
final List<GetThreadResponse> emails;
|
||||||
|
3
lib/emailView.dart
Normal file
3
lib/emailView.dart
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export 'emailViewStub.dart'
|
||||||
|
if (dart.library.io) 'emailViewAndroid.dart'
|
||||||
|
if (dart.library.js_interop) 'emailViewWeb.dart';
|
95
lib/emailViewAndroid.dart
Normal file
95
lib/emailViewAndroid.dart
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import 'package:crab_ui/collapsableEmailsAndroid.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
// import 'dart:ui_web' as ui;
|
||||||
|
// import 'augment.dart';
|
||||||
|
// // import 'dart:js_interop' as js; //eventually for manipulating css
|
||||||
|
// import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||||
|
// import 'collapsableEmails.dart';
|
||||||
|
// import 'api_service.dart';
|
||||||
|
|
||||||
|
class EmailView extends StatefulWidget {
|
||||||
|
final List<String> emailContent;
|
||||||
|
final String from;
|
||||||
|
final String name;
|
||||||
|
final String to;
|
||||||
|
final String subject;
|
||||||
|
final String date;
|
||||||
|
final String id;
|
||||||
|
final List<String> messages;
|
||||||
|
|
||||||
|
const EmailView({
|
||||||
|
Key? key,
|
||||||
|
required this.emailContent,
|
||||||
|
required this.from,
|
||||||
|
required this.name, // tf is name
|
||||||
|
required this.to,
|
||||||
|
required this.subject,
|
||||||
|
required this.date,
|
||||||
|
required this.id,
|
||||||
|
required this.messages,
|
||||||
|
}) : super(key: key);
|
||||||
|
@override
|
||||||
|
_EmailViewState createState() => _EmailViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _EmailViewState extends State<EmailView> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(widget.name),
|
||||||
|
),
|
||||||
|
body: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
widget.subject,
|
||||||
|
style: TextStyle(fontSize: 15),
|
||||||
|
overflow: TextOverflow.visible,
|
||||||
|
softWrap: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'from ${widget.name}',
|
||||||
|
style: TextStyle(fontSize: 8),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'<${widget.from}>',
|
||||||
|
style: TextStyle(fontSize: 8),
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
|
Text(
|
||||||
|
widget.date,
|
||||||
|
textAlign: TextAlign.right,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'to ${widget.to.toString()}',
|
||||||
|
style: TextStyle(fontSize: 8),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: CollapsableEmails(
|
||||||
|
thread: widget.messages,
|
||||||
|
threadHTML: widget.emailContent,
|
||||||
|
threadIDs: widget.id,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
39
lib/emailViewStub.dart
Normal file
39
lib/emailViewStub.dart
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class EmailView extends StatefulWidget {
|
||||||
|
final List<String> emailContent;
|
||||||
|
final String from;
|
||||||
|
final String name;
|
||||||
|
final String to;
|
||||||
|
final String subject;
|
||||||
|
final String date;
|
||||||
|
final String id;
|
||||||
|
final List<String> messages;
|
||||||
|
|
||||||
|
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,
|
||||||
|
required this.messages,
|
||||||
|
}) : super(key: key);
|
||||||
|
@override
|
||||||
|
_EmailViewState createState() => _EmailViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _EmailViewState extends State<EmailView> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: Center(
|
||||||
|
child: Text(" emailview stub, not supported")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
241
lib/emailViewWeb.dart
Normal file
241
lib/emailViewWeb.dart
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'dart:ui_web' as ui;
|
||||||
|
import 'augment.dart';
|
||||||
|
// import 'dart:js_interop' as js; //eventually for manipulating css
|
||||||
|
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||||
|
import 'collapsableEmails.dart';
|
||||||
|
import 'api_service.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class EmailView extends StatefulWidget {
|
||||||
|
final List<String> emailContent;
|
||||||
|
final String from;
|
||||||
|
final String name;
|
||||||
|
final String to;
|
||||||
|
final String subject;
|
||||||
|
final String date;
|
||||||
|
final String id;
|
||||||
|
final List<String> messages;
|
||||||
|
|
||||||
|
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,
|
||||||
|
required this.messages,
|
||||||
|
}) : super(key: key);
|
||||||
|
@override
|
||||||
|
_EmailViewState createState() => _EmailViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _EmailViewState extends State<EmailView> {
|
||||||
|
//html css rendering thing
|
||||||
|
late Key iframeKey;
|
||||||
|
late String currentContent;
|
||||||
|
late String viewTypeId; //make this a list too???
|
||||||
|
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},
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
print("thread id? ${widget.id}");
|
||||||
|
List<String> currentContent = widget
|
||||||
|
.emailContent; //html of the email/ actually entire thread, gives me little space to play in between
|
||||||
|
// i wonder if the other attributes change? because if so i have to add like some zooms in and out of the emails, as in collapse
|
||||||
|
// _registerViewFactory(currentContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// void _registerViewFactory(List<String> currentContent) { // i think this doesnt work anymore
|
||||||
|
// setState(() { //update to do item per item
|
||||||
|
// // each item to have itsviewtype ID
|
||||||
|
// // is this necessarey here??
|
||||||
|
|
||||||
|
// //could just move to collapsable
|
||||||
|
|
||||||
|
// viewTypeId = 'iframe-${DateTime.now().millisecondsSinceEpoch}';
|
||||||
|
// final emailHTML = web.document.createElement('div') as web.HTMLDivElement
|
||||||
|
// ..id = viewTypeId
|
||||||
|
// ..innerHTML = currentContent[0].toJS; // temporarily index because it has to do all of them
|
||||||
|
// emailHTML.style
|
||||||
|
// ..width = '100%'
|
||||||
|
// ..height = '100%'
|
||||||
|
// ..overflow = 'auto'
|
||||||
|
// ..scrollBehavior = 'smooth';
|
||||||
|
|
||||||
|
// ui.platformViewRegistry.registerViewFactory(
|
||||||
|
// viewTypeId,
|
||||||
|
// (int viewId) => emailHTML,
|
||||||
|
// );
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
void _scrollToNumber(String spanId) {
|
||||||
|
AugmentClasses.handleJump(spanId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: void _invisibility(String ) //to make purple numbers not visible
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
// print("thread id ${widget.id}");
|
||||||
|
ApiService.currThreadID = widget.id;
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(widget.name),
|
||||||
|
),
|
||||||
|
body: Stack(
|
||||||
|
children: [
|
||||||
|
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: CollapsableEmails(
|
||||||
|
//change here
|
||||||
|
thread: widget.messages, //this wont work in serializable
|
||||||
|
threadHTML: widget.emailContent,
|
||||||
|
threadIDs: widget.id,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Expanded(
|
||||||
|
// child: HtmlElementView(
|
||||||
|
// key: UniqueKey(),
|
||||||
|
// viewType: viewTypeId,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
// 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),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,7 @@ import 'package:crab_ui/sonicEmailView.dart';
|
|||||||
|
|
||||||
import 'folder_drawer.dart';
|
import 'folder_drawer.dart';
|
||||||
import 'structs.dart';
|
import 'structs.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
// import 'package:flutter/widgets.dart';
|
||||||
import 'api_service.dart';
|
import 'api_service.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'email.dart';
|
import 'email.dart';
|
||||||
@ -266,40 +266,45 @@ class _HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
|
|||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Flexible(
|
||||||
width: 800,
|
child: ConstrainedBox(
|
||||||
height: 40,
|
constraints: BoxConstraints(
|
||||||
child: TextField(
|
maxWidth: 800,
|
||||||
decoration: InputDecoration(
|
),
|
||||||
hintText: 'Search...',
|
child: SizedBox(
|
||||||
border: OutlineInputBorder(),
|
height: 40,
|
||||||
prefixIcon: Icon(Icons.search),
|
child: TextField(
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: 'Search...',
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
prefixIcon: Icon(Icons.search),
|
||||||
|
),
|
||||||
|
onSubmitted: (value) {
|
||||||
|
if (value.isNotEmpty) {
|
||||||
|
_performSearch(value, _selectedOption);
|
||||||
|
}
|
||||||
|
//this is the input box i mentioned
|
||||||
|
// if (value == '') {
|
||||||
|
// setState(() {
|
||||||
|
// querySearches = false;
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// Future<List<String>> results = apiService
|
||||||
|
// .sonicSearch('INBOX', 20, 0, value);
|
||||||
|
// // print(value);
|
||||||
|
// print(results);
|
||||||
|
// setState(() {
|
||||||
|
// querySearches = true;
|
||||||
|
// });
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
onSubmitted: (value) {
|
|
||||||
if (value.isNotEmpty) {
|
|
||||||
_performSearch(value, _selectedOption);
|
|
||||||
}
|
|
||||||
//this is the input box i mentioned
|
|
||||||
// if (value == '') {
|
|
||||||
// setState(() {
|
|
||||||
// querySearches = false;
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// Future<List<String>> results = apiService
|
|
||||||
// .sonicSearch('INBOX', 20, 0, value);
|
|
||||||
// // print(value);
|
|
||||||
// print(results);
|
|
||||||
// setState(() {
|
|
||||||
// querySearches = true;
|
|
||||||
// });
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 16,
|
width: 8,
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
width: 80,
|
|
||||||
height: 40,
|
height: 40,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: _showOptionsSearchDialog,
|
onPressed: _showOptionsSearchDialog,
|
||||||
|
@ -1,145 +1,3 @@
|
|||||||
import 'package:crab_ui/augment.dart';
|
export 'SonicEmailViewStub.dart'
|
||||||
import 'package:web/web.dart' as web;
|
if (dart.library.js_interop) 'SonicEmailViewWeb.dart'
|
||||||
import 'dart:ui_web' as ui;
|
if (dart.library.io) 'SonicEmailViewAndroid.dart';
|
||||||
import 'dart:js_interop';
|
|
||||||
import 'structs.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class SonicEmailView extends StatefulWidget {
|
|
||||||
SerializableMessage email;
|
|
||||||
String emailHTML;
|
|
||||||
|
|
||||||
SonicEmailView({required this.email, required this.emailHTML});
|
|
||||||
|
|
||||||
@override
|
|
||||||
_SonicEmailViewState createState() => _SonicEmailViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _SonicEmailViewState extends State<SonicEmailView> {
|
|
||||||
String viewTypeIDs = "";
|
|
||||||
int heightOFViewtype = 0;
|
|
||||||
bool _isLoaded = false;
|
|
||||||
|
|
||||||
void _scrollToNumber(String spanId) {
|
|
||||||
AugmentClasses.handleJump(spanId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _init() async {
|
|
||||||
await _registerViewFactory(widget.emailHTML);
|
|
||||||
if (!mounted) return;
|
|
||||||
setState(() {
|
|
||||||
_isLoaded = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _registerViewFactory(String currentContent) async {
|
|
||||||
// setState(() { //update to do item per item
|
|
||||||
// each item to have itsviewtype ID
|
|
||||||
// is this necessarey here??
|
|
||||||
|
|
||||||
//could just move to collapsable
|
|
||||||
|
|
||||||
// for (var emailHTML in widget.threadHTML) {
|
|
||||||
String viewTypeId = 'email-${DateTime.now().millisecondsSinceEpoch}';
|
|
||||||
|
|
||||||
final ghost = web.document.createElement('div') as web.HTMLDivElement
|
|
||||||
..style.visibility = 'hidden'
|
|
||||||
..style.position = 'absolute'
|
|
||||||
..style.width = '100%'
|
|
||||||
..style.overflow = 'auto'
|
|
||||||
..innerHTML = currentContent.toJS;
|
|
||||||
web.document.body?.append(ghost);
|
|
||||||
await Future.delayed(Duration(milliseconds: 10));
|
|
||||||
|
|
||||||
final heightOfEmail = ghost.scrollHeight;
|
|
||||||
ghost.remove();
|
|
||||||
|
|
||||||
final HTMLsnippet = web.document.createElement('div') as web.HTMLDivElement
|
|
||||||
..id = viewTypeId
|
|
||||||
..innerHTML = widget
|
|
||||||
.emailHTML.toJS; // temporarily index because it has to do all of them
|
|
||||||
HTMLsnippet.style
|
|
||||||
..width = '100%'
|
|
||||||
..height = '${heightOfEmail}px'
|
|
||||||
..overflow = 'auto'
|
|
||||||
..scrollBehavior = 'smooth';
|
|
||||||
|
|
||||||
ui.platformViewRegistry.registerViewFactory(
|
|
||||||
viewTypeId,
|
|
||||||
(int viewId) => HTMLsnippet,
|
|
||||||
);
|
|
||||||
this.viewTypeIDs = viewTypeId;
|
|
||||||
this.heightOFViewtype = heightOfEmail;
|
|
||||||
print(viewTypeIDs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return _isLoaded
|
|
||||||
? Scaffold(
|
|
||||||
appBar: AppBar(title: Text(widget.email.subject)),
|
|
||||||
body: Stack(
|
|
||||||
children: [
|
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
EmailToolbar(
|
|
||||||
onButtonPressed: () => {},
|
|
||||||
onJumpToSpan: _scrollToNumber),
|
|
||||||
Row(
|
|
||||||
// title of email
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
widget.email.subject,
|
|
||||||
style: TextStyle(fontSize: 30),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'from ${widget.email.name}',
|
|
||||||
style: TextStyle(fontSize: 18),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'<${widget.email.from}>',
|
|
||||||
style: TextStyle(fontSize: 18),
|
|
||||||
),
|
|
||||||
Spacer(),
|
|
||||||
Text(
|
|
||||||
'${widget.email.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.email.to.toString()}',
|
|
||||||
style: TextStyle(fontSize: 15),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
// child: SizedBox(
|
|
||||||
// height: heightOFViewtype.toDouble(),
|
|
||||||
child: HtmlElementView(
|
|
||||||
key: UniqueKey(), viewType: this.viewTypeIDs,
|
|
||||||
// ),
|
|
||||||
))
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: const Center(
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
360
pubspec.lock
360
pubspec.lock
@ -25,6 +25,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.13.0"
|
version: "2.13.0"
|
||||||
|
audio_session:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: audio_session
|
||||||
|
sha256: "2b7fff16a552486d078bfc09a8cde19f426dc6d6329262b684182597bec5b1ac"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.25"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -33,6 +41,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.2"
|
version: "2.1.2"
|
||||||
|
cached_network_image:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cached_network_image
|
||||||
|
sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.4.1"
|
||||||
|
cached_network_image_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cached_network_image_platform_interface
|
||||||
|
sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.1.1"
|
||||||
|
cached_network_image_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cached_network_image_web
|
||||||
|
sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.1"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -41,6 +73,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.0"
|
version: "1.4.0"
|
||||||
|
chewie:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: chewie
|
||||||
|
sha256: "4d9554a8f87cc2dc6575dfd5ad20a4375015a29edd567fd6733febe6365e2566"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.11.3"
|
||||||
clock:
|
clock:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -73,6 +113,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.6"
|
version: "3.0.6"
|
||||||
|
csslib:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: csslib
|
||||||
|
sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.2"
|
||||||
|
cupertino_icons:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cupertino_icons
|
||||||
|
sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.8"
|
||||||
|
dbus:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dbus
|
||||||
|
sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.11"
|
||||||
encrypt:
|
encrypt:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -113,11 +177,27 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.0.1"
|
version: "7.0.1"
|
||||||
|
fixnum:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: fixnum
|
||||||
|
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_cache_manager:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_cache_manager
|
||||||
|
sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.4.1"
|
||||||
flutter_layout_grid:
|
flutter_layout_grid:
|
||||||
dependency: "direct overridden"
|
dependency: "direct overridden"
|
||||||
description:
|
description:
|
||||||
@ -160,6 +240,78 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_widget_from_html:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_widget_from_html
|
||||||
|
sha256: "0dfebf7417df2149de93926520c703db9be0c9017e60dc5cf43cebed37f4d11e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.16.0"
|
||||||
|
flutter_widget_from_html_core:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_widget_from_html_core
|
||||||
|
sha256: f77ea1aa1ba29a38fcce04483f44f12382f541b9e8c2150df37166c23bbbd30f
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.16.0"
|
||||||
|
fwfh_cached_network_image:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: fwfh_cached_network_image
|
||||||
|
sha256: "8f4896109ff3e42424ccacf9058ba3afe5d575b58946c8ac646ac85ae882ce23"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.16.0"
|
||||||
|
fwfh_chewie:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: fwfh_chewie
|
||||||
|
sha256: "1ce7c56894db19881a997813b933835dec142878431370c0eb40f1f878396a25"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.16.0"
|
||||||
|
fwfh_just_audio:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: fwfh_just_audio
|
||||||
|
sha256: "17816168de1fd180fd3d1fd4500e23136630a248a6889b553e2d2067e133c1a6"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.16.0"
|
||||||
|
fwfh_svg:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: fwfh_svg
|
||||||
|
sha256: "82f3eb378186fe39b3e2e01ed48a1830d34b0b9a237d951077e74ff0d99e2ac3"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.16.0"
|
||||||
|
fwfh_url_launcher:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: fwfh_url_launcher
|
||||||
|
sha256: "5cf1b1baa16740abaef8eb41a8e16ba430295d5ec20b880e4cb94e2924774f0a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.16.0"
|
||||||
|
fwfh_webview:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: fwfh_webview
|
||||||
|
sha256: "894aa7d98ebdc2d86d79ac2309173043dec7f102575de87bf9626ddb26104e49"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.15.4"
|
||||||
|
html:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: html
|
||||||
|
sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.15.6"
|
||||||
http:
|
http:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -192,6 +344,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.2"
|
version: "0.7.2"
|
||||||
|
just_audio:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: just_audio
|
||||||
|
sha256: f978d5b4ccea08f267dae0232ec5405c1b05d3f3cd63f82097ea46c015d5c09e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.46"
|
||||||
|
just_audio_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: just_audio_platform_interface
|
||||||
|
sha256: "4cd94536af0219fa306205a58e78d67e02b0555283c1c094ee41e402a14a5c4a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.5.0"
|
||||||
|
just_audio_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: just_audio_web
|
||||||
|
sha256: "6ba8a2a7e87d57d32f0f7b42856ade3d6a9fbe0f1a11fabae0a4f00bb73f0663"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.4.16"
|
||||||
leak_tracker:
|
leak_tracker:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -224,6 +400,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.1"
|
||||||
|
logging:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: logging
|
||||||
|
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.0"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -264,6 +448,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
|
octo_image:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: octo_image
|
||||||
|
sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
|
package_info_plus:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: package_info_plus
|
||||||
|
sha256: "7976bfe4c583170d6cdc7077e3237560b364149fcd268b5f53d95a991963b191"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "8.3.0"
|
||||||
|
package_info_plus_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: package_info_plus_platform_interface
|
||||||
|
sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.0"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -501,6 +709,54 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.1"
|
version: "1.10.1"
|
||||||
|
sprintf:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sprintf
|
||||||
|
sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.0"
|
||||||
|
sqflite:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sqflite
|
||||||
|
sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.2"
|
||||||
|
sqflite_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sqflite_android
|
||||||
|
sha256: "2b3070c5fa881839f8b402ee4a39c1b4d561704d4ebbbcfb808a119bc2a1701b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.1"
|
||||||
|
sqflite_common:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sqflite_common
|
||||||
|
sha256: "84731e8bfd8303a3389903e01fb2141b6e59b5973cacbb0929021df08dddbe8b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.5.5"
|
||||||
|
sqflite_darwin:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sqflite_darwin
|
||||||
|
sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.2"
|
||||||
|
sqflite_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sqflite_platform_interface
|
||||||
|
sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.0"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -629,6 +885,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.4"
|
version: "3.1.4"
|
||||||
|
uuid:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: uuid
|
||||||
|
sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.5.1"
|
||||||
vector_graphics:
|
vector_graphics:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -661,6 +925,46 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.1.4"
|
||||||
|
video_player:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: video_player
|
||||||
|
sha256: "7d78f0cfaddc8c19d4cb2d3bebe1bfef11f2103b0a03e5398b303a1bf65eeb14"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.9.5"
|
||||||
|
video_player_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: video_player_android
|
||||||
|
sha256: "28dcc4122079f40f93a0965b3679aff1a5f4251cf79611bd8011f937eb6b69de"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.8.4"
|
||||||
|
video_player_avfoundation:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: video_player_avfoundation
|
||||||
|
sha256: "9ee764e5cd2fc1e10911ae8ad588e1a19db3b6aa9a6eb53c127c42d3a3c3f22f"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.7.1"
|
||||||
|
video_player_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: video_player_platform_interface
|
||||||
|
sha256: df534476c341ab2c6a835078066fc681b8265048addd853a1e3c78740316a844
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.3.0"
|
||||||
|
video_player_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: video_player_web
|
||||||
|
sha256: e8bba2e5d1e159d5048c9a491bb2a7b29c535c612bb7d10c1e21107f5bd365ba
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.5"
|
||||||
vm_service:
|
vm_service:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -669,6 +973,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "15.0.0"
|
version: "15.0.0"
|
||||||
|
wakelock_plus:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: wakelock_plus
|
||||||
|
sha256: a474e314c3e8fb5adef1f9ae2d247e57467ad557fa7483a2b895bc1b421c5678
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.2"
|
||||||
|
wakelock_plus_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: wakelock_plus_platform_interface
|
||||||
|
sha256: e10444072e50dbc4999d7316fd303f7ea53d31c824aa5eb05d7ccbdd98985207
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.3"
|
||||||
web:
|
web:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -677,6 +997,46 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.1.1"
|
||||||
|
webview_flutter:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: webview_flutter
|
||||||
|
sha256: c3e4fe614b1c814950ad07186007eff2f2e5dd2935eba7b9a9a1af8e5885f1ba
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.13.0"
|
||||||
|
webview_flutter_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: webview_flutter_android
|
||||||
|
sha256: f6e6afef6e234801da77170f7a1847ded8450778caf2fe13979d140484be3678
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.7.0"
|
||||||
|
webview_flutter_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: webview_flutter_platform_interface
|
||||||
|
sha256: "7cb32b21825bd65569665c32bb00a34ded5779786d6201f5350979d2d529940d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.13.0"
|
||||||
|
webview_flutter_wkwebview:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: webview_flutter_wkwebview
|
||||||
|
sha256: a3d461fe3467014e05f3ac4962e5fdde2a4bf44c561cb53e9ae5c586600fdbc3
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.22.0"
|
||||||
|
win32:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: win32
|
||||||
|
sha256: "329edf97fdd893e0f1e3b9e88d6a0e627128cc17cc316a8d67fda8f1451178ba"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.13.0"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -26,6 +26,7 @@ dependencies:
|
|||||||
pdfrx: ^1.0.94
|
pdfrx: ^1.0.94
|
||||||
photo_view: ^0.15.0
|
photo_view: ^0.15.0
|
||||||
web: ^1.1.1
|
web: ^1.1.1
|
||||||
|
flutter_widget_from_html: ^0.16.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Loading…
Reference in New Issue
Block a user