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:typed_data';
|
||||
|
||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||
import 'collapsableEmails.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;
|
||||
import 'package:web/web.dart' as web;
|
||||
import 'dart:js_interop' as js;
|
||||
|
||||
|
||||
class ApiService {
|
||||
static String ip = "";
|
||||
@ -423,236 +416,3 @@ class ApiService {
|
||||
// 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;
|
||||
import 'package:web/web.dart' as web;
|
||||
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)
|
||||
);
|
||||
}
|
||||
}
|
||||
export 'attachamentDownloadStub.dart'
|
||||
if (dart.library.io) 'attachmentDownloadAndroid.dart';
|
||||
// if (dart.library.js_interop) 'attachmentDownloadWeb.dart';
|
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";
|
||||
|
||||
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),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
]));
|
||||
}
|
||||
}
|
||||
export 'attachmentWidgetStub.dart'
|
||||
if (dart.library.js_interop) 'attachmentWidgetWeb.dart'
|
||||
if (dart.library.io) 'attachmentWidgetAndroid.dart';
|
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/attachmentDownload.dart';
|
||||
import 'package:crab_ui/structs.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 'attachmentWidget.dart';
|
||||
|
||||
|
@ -1,132 +1,3 @@
|
||||
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());
|
||||
}
|
||||
}
|
||||
export 'collapsableEmailsStub.dart'
|
||||
if (dart.library.io) 'collapsableEmailsAndroid.dart'
|
||||
if (dart.library.js_interop) 'collapsableEmailsWeb.dart';
|
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:http/http.dart' as http;
|
||||
import 'package:flutter_html/flutter_html.dart';
|
||||
// import 'package:http/http.dart' as http;
|
||||
// import 'package:flutter_html/flutter_html.dart';
|
||||
|
||||
class ContactsPage extends StatefulWidget {
|
||||
const ContactsPage({super.key});
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'api_service.dart';
|
||||
import 'structs.dart';
|
||||
import 'emailView.dart';
|
||||
|
||||
class EmailListScreen extends StatelessWidget {
|
||||
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 'structs.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
// import 'package:flutter/widgets.dart';
|
||||
import 'api_service.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'email.dart';
|
||||
@ -266,40 +266,45 @@ class _HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: 800,
|
||||
height: 40,
|
||||
child: TextField(
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Search...',
|
||||
border: OutlineInputBorder(),
|
||||
prefixIcon: Icon(Icons.search),
|
||||
Flexible(
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: 800,
|
||||
),
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
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(
|
||||
width: 16,
|
||||
width: 8,
|
||||
),
|
||||
Container(
|
||||
width: 80,
|
||||
height: 40,
|
||||
child: ElevatedButton(
|
||||
onPressed: _showOptionsSearchDialog,
|
||||
|
@ -1,145 +1,3 @@
|
||||
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(),
|
||||
);
|
||||
}
|
||||
}
|
||||
export 'SonicEmailViewStub.dart'
|
||||
if (dart.library.js_interop) 'SonicEmailViewWeb.dart'
|
||||
if (dart.library.io) 'SonicEmailViewAndroid.dart';
|
360
pubspec.lock
360
pubspec.lock
@ -25,6 +25,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -33,6 +41,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -41,6 +73,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
chewie:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: chewie
|
||||
sha256: "4d9554a8f87cc2dc6575dfd5ad20a4375015a29edd567fd6733febe6365e2566"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.11.3"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -73,6 +113,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -113,11 +177,27 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.1"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fixnum
|
||||
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
source: sdk
|
||||
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:
|
||||
dependency: "direct overridden"
|
||||
description:
|
||||
@ -160,6 +240,78 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
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:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -192,6 +344,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -224,6 +400,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: logging
|
||||
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -264,6 +448,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -501,6 +709,54 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -629,6 +885,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.4"
|
||||
uuid:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: uuid
|
||||
sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.5.1"
|
||||
vector_graphics:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -661,6 +925,46 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -669,6 +973,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -677,6 +997,46 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -26,6 +26,7 @@ dependencies:
|
||||
pdfrx: ^1.0.94
|
||||
photo_view: ^0.15.0
|
||||
web: ^1.1.1
|
||||
flutter_widget_from_html: ^0.16.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
Loading…
Reference in New Issue
Block a user