TF-105 [BUG] Fix long line should be wrapped
This commit is contained in:
@@ -1,24 +0,0 @@
|
|||||||
|
|
||||||
import 'package:core/presentation/utils/html_transformer/base/dom_transformer.dart';
|
|
||||||
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
|
|
||||||
import 'package:html/dom.dart';
|
|
||||||
|
|
||||||
class SetStyleBlockQuoteTransformer extends DomTransformer {
|
|
||||||
|
|
||||||
const SetStyleBlockQuoteTransformer();
|
|
||||||
|
|
||||||
@override
|
|
||||||
void process(Document document, String message, TransformConfiguration configuration) {
|
|
||||||
final quoteElements = document.getElementsByTagName('blockquote');
|
|
||||||
for (final quote in quoteElements) {
|
|
||||||
final style = quote.attributes['style'];
|
|
||||||
if (style == null) {
|
|
||||||
quote.attributes['style'] = '''
|
|
||||||
margin: 0px 8px 0px 8px;
|
|
||||||
padding: 8px 16px 8px 16px;
|
|
||||||
border-left:5px solid #eee;
|
|
||||||
''';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -12,23 +12,12 @@ class ImageTransformer extends DomTransformer {
|
|||||||
final imageElements = document.getElementsByTagName('img');
|
final imageElements = document.getElementsByTagName('img');
|
||||||
for (final imageElement in imageElements) {
|
for (final imageElement in imageElements) {
|
||||||
final src = imageElement.attributes['src'];
|
final src = imageElement.attributes['src'];
|
||||||
if (src != null) {
|
if (src != null && src.startsWith('http:')) {
|
||||||
if (src.startsWith('http')) {
|
// always at least enforce HTTPS images:
|
||||||
if (configuration.blockExternalImages) {
|
final url = src.substring('http:'.length);
|
||||||
imageElement.attributes.remove('src');
|
imageElement.attributes['src'] = 'https:$url';
|
||||||
} else if (src.startsWith('http:')) {
|
|
||||||
// always at least enforce HTTPS images:
|
|
||||||
final url = src.substring('http:'.length);
|
|
||||||
imageElement.attributes['src'] = 'https:$url';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final style = imageElement.attributes['style'];
|
|
||||||
if (style == null) {
|
|
||||||
imageElement.attributes['style'] = 'display: inline;max-width: 100%;height: auto;';
|
|
||||||
} else {
|
|
||||||
imageElement.attributes['style'] = 'display: inline;max-width: 100%;height: auto;' + style;
|
|
||||||
}
|
}
|
||||||
|
imageElement.attributes['style'] = 'display: inline;max-width: 100%;height: auto;';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
|
|
||||||
import 'package:core/presentation/utils/html_transformer/base/dom_transformer.dart';
|
|
||||||
import 'package:core/presentation/utils/html_transformer/transform_configuration.dart';
|
|
||||||
import 'package:html/dom.dart';
|
|
||||||
|
|
||||||
class SetStyleTableTransformer extends DomTransformer {
|
|
||||||
|
|
||||||
const SetStyleTableTransformer();
|
|
||||||
|
|
||||||
@override
|
|
||||||
void process(Document document, String message, TransformConfiguration configuration) {
|
|
||||||
final tableElements = document.getElementsByTagName('table');
|
|
||||||
for (final table in tableElements) {
|
|
||||||
final style = table.attributes['style'];
|
|
||||||
if (style == null) {
|
|
||||||
table.attributes['style'] = 'width: 100%;max-width: 100%;border:1px solid #f0f0f0;border-collapse: collapse;border-spacing: 2px;';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final tdElements = document.getElementsByTagName('td');
|
|
||||||
for (final tdTag in tdElements) {
|
|
||||||
final style = tdTag.attributes['style'];
|
|
||||||
if (style == null) {
|
|
||||||
tdTag.attributes['style'] = 'padding: 13px;margin: 0px;border:1px solid #f0f0f0;';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final thElements = document.getElementsByTagName('th');
|
|
||||||
for (final thTag in thElements) {
|
|
||||||
final style = thTag.attributes['style'];
|
|
||||||
if (style == null) {
|
|
||||||
thTag.attributes['style'] = 'padding: 13px;margin: 0px;border:1px solid #f0f0f0;';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,39 +4,22 @@ import 'package:html/dom.dart';
|
|||||||
|
|
||||||
class HtmlTransform {
|
class HtmlTransform {
|
||||||
|
|
||||||
final String _message;
|
final String _contentHtml;
|
||||||
|
|
||||||
HtmlTransform(this._message);
|
HtmlTransform(this._contentHtml);
|
||||||
|
|
||||||
/// Transforms this message to HTML code.
|
/// Transforms this message to HTML code.
|
||||||
///
|
/// Optionally specify the [transformConfiguration] to control all aspects of the transformation
|
||||||
/// Set [blockExternalImages] to `true` in case external images should be blocked.
|
/// - in that case other parameters are ignored.
|
||||||
/// Optionally specify the [transformConfiguration] to control all aspects of the transformation - in that case other parameters are ignored.
|
String transformToHtml({TransformConfiguration? transformConfiguration}) {
|
||||||
String transformToHtml({
|
final document = transformToDocument(transformConfiguration: transformConfiguration);
|
||||||
bool? blockExternalImages,
|
|
||||||
TransformConfiguration? transformConfiguration,
|
|
||||||
}) {
|
|
||||||
final document = transformToDocument(
|
|
||||||
blockExternalImages: blockExternalImages,
|
|
||||||
transformConfiguration: transformConfiguration,
|
|
||||||
);
|
|
||||||
return document.outerHtml;
|
return document.outerHtml;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transforms this message to Document.
|
/// Transforms this message to Document.
|
||||||
///
|
Document transformToDocument({TransformConfiguration? transformConfiguration}) {
|
||||||
/// Set [blockExternalImages] to `true` in case external images should be blocked.
|
transformConfiguration ??= TransformConfiguration.create();
|
||||||
/// Optionally specify the [transformConfiguration] to control all aspects of the transformation - in that case other parameters are ignored.
|
|
||||||
Document transformToDocument({
|
|
||||||
bool? blockExternalImages,
|
|
||||||
int? maxImageWidth,
|
|
||||||
TransformConfiguration? transformConfiguration,
|
|
||||||
}) {
|
|
||||||
transformConfiguration ??= TransformConfiguration.create(
|
|
||||||
blockExternalImages: blockExternalImages,
|
|
||||||
maxImageWidth: maxImageWidth,
|
|
||||||
);
|
|
||||||
final transformer = MessageContentTransformer(transformConfiguration);
|
final transformer = MessageContentTransformer(transformConfiguration);
|
||||||
return transformer.toDocument(_message);
|
return transformer.toDocument(_contentHtml);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
|
|
||||||
import 'package:core/presentation/utils/html_transformer/dom/blockquote_transformers.dart';
|
|
||||||
import 'package:core/presentation/utils/html_transformer/dom/image_transformers.dart';
|
import 'package:core/presentation/utils/html_transformer/dom/image_transformers.dart';
|
||||||
import 'package:core/presentation/utils/html_transformer/dom/link_transformers.dart';
|
import 'package:core/presentation/utils/html_transformer/dom/link_transformers.dart';
|
||||||
import 'package:core/presentation/utils/html_transformer/dom/meta_transformers.dart';
|
import 'package:core/presentation/utils/html_transformer/dom/meta_transformers.dart';
|
||||||
import 'package:core/presentation/utils/html_transformer/dom/script_transformers.dart';
|
import 'package:core/presentation/utils/html_transformer/dom/script_transformers.dart';
|
||||||
import 'package:core/presentation/utils/html_transformer/base/dom_transformer.dart';
|
import 'package:core/presentation/utils/html_transformer/base/dom_transformer.dart';
|
||||||
import 'package:core/presentation/utils/html_transformer/dom/table_transformers.dart';
|
|
||||||
import 'package:core/presentation/utils/html_transformer/text/convert_tags_text_transformer.dart';
|
import 'package:core/presentation/utils/html_transformer/text/convert_tags_text_transformer.dart';
|
||||||
import 'package:core/presentation/utils/html_transformer/text/linebreak_text_transformer.dart';
|
import 'package:core/presentation/utils/html_transformer/text/linebreak_text_transformer.dart';
|
||||||
import 'package:core/presentation/utils/html_transformer/text/links_text_transformer.dart';
|
import 'package:core/presentation/utils/html_transformer/text/links_text_transformer.dart';
|
||||||
@@ -14,12 +12,6 @@ import 'package:core/presentation/utils/html_transformer/base/text_transformer.d
|
|||||||
/// Contains the configuration for all transformations.
|
/// Contains the configuration for all transformations.
|
||||||
class TransformConfiguration {
|
class TransformConfiguration {
|
||||||
|
|
||||||
/// Should external images be blocked?
|
|
||||||
final bool blockExternalImages;
|
|
||||||
|
|
||||||
/// The maximum width for embedded images. It make sense to limit this to reduce the generated HTML size.
|
|
||||||
final int? maxImageWidth;
|
|
||||||
|
|
||||||
/// The list of DOM transformers being used
|
/// The list of DOM transformers being used
|
||||||
final List<DomTransformer> domTransformers;
|
final List<DomTransformer> domTransformers;
|
||||||
|
|
||||||
@@ -30,16 +22,12 @@ class TransformConfiguration {
|
|||||||
///
|
///
|
||||||
/// Compare [create] to have an easier to use building function
|
/// Compare [create] to have an easier to use building function
|
||||||
const TransformConfiguration(
|
const TransformConfiguration(
|
||||||
this.blockExternalImages,
|
|
||||||
this.maxImageWidth,
|
|
||||||
this.domTransformers,
|
this.domTransformers,
|
||||||
this.textTransformers
|
this.textTransformers
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Provides easy access to a standard configuration that does not block external images.
|
/// Provides easy access to a standard configuration that does not block external images.
|
||||||
static const TransformConfiguration standardConfiguration = TransformConfiguration(
|
static const TransformConfiguration standardConfiguration = TransformConfiguration(
|
||||||
false,
|
|
||||||
standardMaxImageWidth,
|
|
||||||
standardDomTransformers,
|
standardDomTransformers,
|
||||||
standardTextTransformers
|
standardTextTransformers
|
||||||
);
|
);
|
||||||
@@ -61,8 +49,6 @@ class TransformConfiguration {
|
|||||||
: standardTextTransformers;
|
: standardTextTransformers;
|
||||||
maxImageWidth ??= standardMaxImageWidth;
|
maxImageWidth ??= standardMaxImageWidth;
|
||||||
return TransformConfiguration(
|
return TransformConfiguration(
|
||||||
blockExternalImages ?? false,
|
|
||||||
maxImageWidth,
|
|
||||||
domTransformers,
|
domTransformers,
|
||||||
textTransformers
|
textTransformers
|
||||||
);
|
);
|
||||||
@@ -75,8 +61,6 @@ class TransformConfiguration {
|
|||||||
RemoveScriptTransformer(),
|
RemoveScriptTransformer(),
|
||||||
ImageTransformer(),
|
ImageTransformer(),
|
||||||
EnsureRelationNoReferrerTransformer(),
|
EnsureRelationNoReferrerTransformer(),
|
||||||
SetStyleBlockQuoteTransformer(),
|
|
||||||
SetStyleTableTransformer(),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
static const List<TextTransformer> standardTextTransformers = [
|
static const List<TextTransformer> standardTextTransformers = [
|
||||||
|
|||||||
@@ -1,55 +1,31 @@
|
|||||||
import 'package:core/presentation/utils/html_transformer/html_transform.dart';
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart' as launcher;
|
import 'package:url_launcher/url_launcher.dart' as launcher;
|
||||||
|
|
||||||
class _HtmlGenerationArguments {
|
|
||||||
final String message;
|
|
||||||
final bool blockExternalImages;
|
|
||||||
|
|
||||||
const _HtmlGenerationArguments(
|
|
||||||
this.message,
|
|
||||||
this.blockExternalImages,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
class _HtmlGenerationResult {
|
|
||||||
final String? html;
|
|
||||||
final String? errorDetails;
|
|
||||||
|
|
||||||
const _HtmlGenerationResult.success(this.html) : errorDetails = null;
|
|
||||||
|
|
||||||
const _HtmlGenerationResult.error(this.errorDetails) : this.html = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
class HtmlContentViewer extends StatefulWidget {
|
class HtmlContentViewer extends StatefulWidget {
|
||||||
|
|
||||||
final String message;
|
final String contentHtml;
|
||||||
final bool blockExternalImages;
|
final int minHeight;
|
||||||
|
|
||||||
/// Is notified about any errors that might occur
|
|
||||||
final void Function(Object? exception, StackTrace? stackTrace)? onError;
|
|
||||||
|
|
||||||
/// Register this callback if you want a reference to the [InAppWebViewController].
|
/// Register this callback if you want a reference to the [InAppWebViewController].
|
||||||
final void Function(InAppWebViewController controller)? onWebViewCreated;
|
final void Function(InAppWebViewController controller)? onCreated;
|
||||||
|
|
||||||
final void Function(InAppWebViewController controller, Uri? uri)? onWebViewLoadStart;
|
final void Function(InAppWebViewController controller, Uri? uri)? onLoadStart;
|
||||||
|
|
||||||
final void Function(InAppWebViewController controller, Uri? uri)? onWebViewLoadStop;
|
final void Function(InAppWebViewController controller, Uri? uri)? onLoadStop;
|
||||||
|
|
||||||
/// Handler for mailto: links
|
/// Handler for mailto: links
|
||||||
final Future Function(Uri mailto)? mailtoDelegate;
|
final Future Function(Uri mailto)? mailtoDelegate;
|
||||||
|
|
||||||
const HtmlContentViewer({
|
const HtmlContentViewer({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.message,
|
required this.contentHtml,
|
||||||
this.blockExternalImages = false,
|
this.minHeight = 100,
|
||||||
this.onError,
|
this.onCreated,
|
||||||
this.onWebViewCreated,
|
this.onLoadStart,
|
||||||
this.onWebViewLoadStart,
|
this.onLoadStop,
|
||||||
this.onWebViewLoadStop,
|
|
||||||
this.mailtoDelegate,
|
this.mailtoDelegate,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@@ -59,123 +35,126 @@ class HtmlContentViewer extends StatefulWidget {
|
|||||||
|
|
||||||
class _HtmlContentViewState extends State<HtmlContentViewer> {
|
class _HtmlContentViewState extends State<HtmlContentViewer> {
|
||||||
|
|
||||||
String? _htmlData;
|
double? _documentHeight = 1.0;
|
||||||
bool? _wereExternalImagesBlocked;
|
double? _documentWidth = 1.0;
|
||||||
bool _isGenerating = false;
|
String? _initialPageContent;
|
||||||
double? _webViewContentHeight = 1.0;
|
late InAppWebViewController _webViewController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_generateHtml(widget.blockExternalImages);
|
|
||||||
super.initState();
|
super.initState();
|
||||||
|
_initialPageContent = _generateHtmlDocument(widget.contentHtml);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _generateHtml(bool blockExternalImages) async {
|
String _generateHtmlDocument(String content) {
|
||||||
_wereExternalImagesBlocked = blockExternalImages;
|
final htmlTemplate = '''
|
||||||
_isGenerating = true;
|
<!DOCTYPE html>
|
||||||
final args = _HtmlGenerationArguments(
|
<html>
|
||||||
widget.message,
|
<head>
|
||||||
blockExternalImages,
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
);
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
final result = await compute(_generateHtmlImpl, args);
|
<style>
|
||||||
_htmlData = result.html;
|
#editor {
|
||||||
if (_htmlData == null) {
|
outline: 0px solid transparent;
|
||||||
final onError = widget.onError;
|
min-height: ${widget.minHeight}px;
|
||||||
if (onError != null) {
|
min-width: 300px;
|
||||||
onError(result.errorDetails, null);
|
color: #182952;
|
||||||
}
|
font-family: verdana;
|
||||||
}
|
}
|
||||||
if (mounted) {
|
blockquote {
|
||||||
setState(() {
|
font: normal helvetica, verdana;
|
||||||
_isGenerating = false;
|
margin-top: 10px;
|
||||||
});
|
margin-bottom: 10px;
|
||||||
}
|
margin-left: 20px;
|
||||||
}
|
padding-left: 15px;
|
||||||
|
border-left: 5px solid #eee;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
padding: 13px;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
padding: 13px;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
var documentHeight;
|
||||||
|
|
||||||
static _HtmlGenerationResult _generateHtmlImpl(_HtmlGenerationArguments args) {
|
function onLoaded() {
|
||||||
try {
|
documentHeight = document.body.scrollHeight;
|
||||||
final htmlTransform = HtmlTransform(args.message);
|
document.execCommand("styleWithCSS", false, true);
|
||||||
final html = htmlTransform.transformToHtml(
|
}
|
||||||
blockExternalImages: args.blockExternalImages,
|
</script>
|
||||||
);
|
</head>
|
||||||
return _HtmlGenerationResult.success(html);
|
<body onload="onLoaded();">
|
||||||
} catch (e, s) {
|
<div id="editor">$content</div>
|
||||||
String errorDetails = e.toString() + '\n\n' + s.toString();
|
</body>
|
||||||
return _HtmlGenerationResult.error(errorDetails);
|
</html>
|
||||||
}
|
''';
|
||||||
|
return htmlTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (_isGenerating) {
|
|
||||||
return SizedBox.shrink();
|
|
||||||
}
|
|
||||||
if (widget.blockExternalImages != _wereExternalImagesBlocked) {
|
|
||||||
_generateHtml(widget.blockExternalImages);
|
|
||||||
}
|
|
||||||
|
|
||||||
final size = MediaQuery.of(context).size;
|
final size = MediaQuery.of(context).size;
|
||||||
|
_documentWidth = size.width - 30;
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: _webViewContentHeight,
|
height: _documentHeight,
|
||||||
width: size.width,
|
width: _documentWidth,
|
||||||
child: Padding(
|
child: _buildWebView(),
|
||||||
padding: EdgeInsets.only(top: 16),
|
|
||||||
child: _buildWebView(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildWebView() {
|
Widget _buildWebView() {
|
||||||
if (_htmlData == null) {
|
if (_initialPageContent == null || _initialPageContent?.isEmpty == true) {
|
||||||
return Container();
|
return Container();
|
||||||
}
|
}
|
||||||
|
|
||||||
return InAppWebView(
|
return InAppWebView(
|
||||||
key: ValueKey(_htmlData),
|
key: ValueKey(_initialPageContent),
|
||||||
initialData: InAppWebViewInitialData(data: _htmlData!),
|
initialData: InAppWebViewInitialData(data: _initialPageContent!),
|
||||||
initialOptions: InAppWebViewGroupOptions(
|
initialOptions: InAppWebViewGroupOptions(
|
||||||
crossPlatform: InAppWebViewOptions(
|
crossPlatform: InAppWebViewOptions(
|
||||||
useShouldOverrideUrlLoading: true,
|
useShouldOverrideUrlLoading: true,
|
||||||
verticalScrollBarEnabled: false,
|
verticalScrollBarEnabled: false,
|
||||||
disableVerticalScroll: true,
|
disableVerticalScroll: false,
|
||||||
transparentBackground: true,
|
disableHorizontalScroll: false,
|
||||||
|
supportZoom: true,
|
||||||
),
|
),
|
||||||
android: AndroidInAppWebViewOptions(
|
android: AndroidInAppWebViewOptions(
|
||||||
|
useWideViewPort: false,
|
||||||
|
loadWithOverviewMode: true,
|
||||||
useHybridComposition: true,
|
useHybridComposition: true,
|
||||||
),
|
),
|
||||||
ios: IOSInAppWebViewOptions(
|
ios: IOSInAppWebViewOptions(
|
||||||
allowsInlineMediaPlayback: true,
|
enableViewportScale: false,
|
||||||
enableViewportScale: true,
|
|
||||||
allowsLinkPreview: false
|
allowsLinkPreview: false
|
||||||
)
|
),
|
||||||
),
|
),
|
||||||
onLoadStart: (controller, uri) {
|
onLoadStart: (controller, uri) {
|
||||||
if (widget.onWebViewLoadStart != null) {
|
if (widget.onLoadStart != null) {
|
||||||
widget.onWebViewLoadStart!(controller, uri);
|
widget.onLoadStart!(controller, uri);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onWebViewCreated: widget.onWebViewCreated,
|
onWebViewCreated: _onWebViewCreated,
|
||||||
onLoadStop: (controller, uri) async {
|
onLoadStop: (controller, uri) async {
|
||||||
var scrollHeight = (await controller.evaluateJavascript(source: 'document.body.scrollHeight'));
|
final scrollHeight = await _webViewController.evaluateJavascript(source: 'document.body.scrollHeight');
|
||||||
if (scrollHeight != null) {
|
if ((scrollHeight != null) && mounted && (scrollHeight + 30.0 > widget.minHeight)) {
|
||||||
final scrollWidth = (await controller.evaluateJavascript(source: 'document.body.scrollWidth'));
|
|
||||||
final size = MediaQuery.of(context).size;
|
|
||||||
final containerWidth = size.width - 60.0;
|
|
||||||
if (scrollWidth > containerWidth) {
|
|
||||||
var scale = (containerWidth / scrollWidth);
|
|
||||||
if (scale < 0.2) {
|
|
||||||
scale = 0.2;
|
|
||||||
}
|
|
||||||
await controller.zoomBy(zoomFactor: scale, iosAnimated: true);
|
|
||||||
scrollHeight = (scrollHeight * scale).ceil();
|
|
||||||
}
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_webViewContentHeight = double.tryParse('${scrollHeight + 24}');
|
_documentHeight = (scrollHeight + 30.0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (widget.onLoadStop != null) {
|
||||||
if (widget.onWebViewLoadStop != null) {
|
widget.onLoadStop!(controller, uri);
|
||||||
widget.onWebViewLoadStop!(controller, uri);
|
}
|
||||||
|
},
|
||||||
|
onScrollChanged: (controller, x, y) {
|
||||||
|
if (y != 0) {
|
||||||
|
controller.scrollTo(x: 0, y: 0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
shouldOverrideUrlLoading: _shouldOverrideUrlLoading,
|
shouldOverrideUrlLoading: _shouldOverrideUrlLoading,
|
||||||
@@ -185,6 +164,13 @@ class _HtmlContentViewState extends State<HtmlContentViewer> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _onWebViewCreated(InAppWebViewController controller) {
|
||||||
|
_webViewController = controller;
|
||||||
|
if (widget.onCreated != null) {
|
||||||
|
widget.onCreated!(_webViewController);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<NavigationActionPolicy> _shouldOverrideUrlLoading(
|
Future<NavigationActionPolicy> _shouldOverrideUrlLoading(
|
||||||
InAppWebViewController controller,
|
InAppWebViewController controller,
|
||||||
NavigationAction request
|
NavigationAction request
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import 'package:tmail_ui_user/features/composer/domain/usecases/save_email_addre
|
|||||||
import 'package:tmail_ui_user/features/composer/domain/usecases/send_email_interactor.dart';
|
import 'package:tmail_ui_user/features/composer/domain/usecases/send_email_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/domain/usecases/upload_mutiple_attachment_interactor.dart';
|
import 'package:tmail_ui_user/features/composer/domain/usecases/upload_mutiple_attachment_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/extensions/email_action_type_extension.dart';
|
import 'package:tmail_ui_user/features/composer/presentation/extensions/email_action_type_extension.dart';
|
||||||
import 'package:tmail_ui_user/features/email/presentation/constants/email_constants.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart';
|
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart';
|
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart';
|
||||||
import 'package:tmail_ui_user/features/upload/domain/state/local_file_picker_state.dart';
|
import 'package:tmail_ui_user/features/upload/domain/state/local_file_picker_state.dart';
|
||||||
@@ -215,18 +214,11 @@ class ComposerController extends BaseController {
|
|||||||
final headerEmailQuoted = getHeaderEmailQuoted(Localizations.localeOf(context).toLanguageTag());
|
final headerEmailQuoted = getHeaderEmailQuoted(Localizations.localeOf(context).toLanguageTag());
|
||||||
|
|
||||||
final headerEmailQuotedAsHtml = headerEmailQuoted != null
|
final headerEmailQuotedAsHtml = headerEmailQuoted != null
|
||||||
? AppLocalizations.of(context).header_email_quoted(headerEmailQuoted.value1, headerEmailQuoted.value2)
|
? AppLocalizations.of(context).header_email_quoted(headerEmailQuoted.value1, headerEmailQuoted.value2)
|
||||||
.addBlockTag('p', attribute: 'style=\"font-size:14px;font-style:italic;color:#182952;\"')
|
.addBlockTag('p', attribute: 'style=\"font-size:14px;font-style:italic;color:#182952;\"')
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
var trustAsHtml = '';
|
final trustAsHtml = composerArguments.value?.emailContent?.content ?? '';
|
||||||
|
|
||||||
if (composerArguments.value != null) {
|
|
||||||
final emailContents = composerArguments.value!.emailContents;
|
|
||||||
if (emailContents != null && emailContents.isNotEmpty) {
|
|
||||||
trustAsHtml = emailContents.first.content;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final emailQuotedHtml = '</br></br></br>$headerEmailQuotedAsHtml${trustAsHtml.addBlockQuoteTag()}</br>';
|
final emailQuotedHtml = '</br></br></br>$headerEmailQuotedAsHtml${trustAsHtml.addBlockQuoteTag()}</br>';
|
||||||
|
|
||||||
@@ -256,7 +248,7 @@ class ComposerController extends BaseController {
|
|||||||
EmailBodyPart(
|
EmailBodyPart(
|
||||||
partId: generatePartId,
|
partId: generatePartId,
|
||||||
blobId: generateBlobId,
|
blobId: generateBlobId,
|
||||||
type: MediaType.parse(EmailConstants.HTML_TEXT)
|
type: MediaType.parse('text/html')
|
||||||
)},
|
)},
|
||||||
bodyValues: {
|
bodyValues: {
|
||||||
generatePartId: EmailBodyValue(emailBodyText, false, false)
|
generatePartId: EmailBodyValue(emailBodyText, false, false)
|
||||||
|
|||||||
@@ -174,17 +174,23 @@ class ComposerView extends GetWidget<ComposerController> {
|
|||||||
Widget _buildComposerEditor(BuildContext context) {
|
Widget _buildComposerEditor(BuildContext context) {
|
||||||
return Obx(() {
|
return Obx(() {
|
||||||
if (controller.composerArguments.value?.emailActionType == EmailActionType.compose) {
|
if (controller.composerArguments.value?.emailActionType == EmailActionType.compose) {
|
||||||
return PackagedHtmlEditor(
|
return HtmlEditor(
|
||||||
key: Key('composer_editor'),
|
key: Key('composer_editor'),
|
||||||
minHeight: 400,
|
minHeight: 400,
|
||||||
|
supportZoom: true,
|
||||||
|
disableHorizontalScroll: false,
|
||||||
|
disableVerticalScroll: false,
|
||||||
onCreated: (editorApi) => controller.htmlEditorApi = editorApi,
|
onCreated: (editorApi) => controller.htmlEditorApi = editorApi,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
final message = controller.getContentEmail();
|
final message = controller.getContentEmail();
|
||||||
return message.isNotEmpty
|
return message.isNotEmpty
|
||||||
? PackagedHtmlEditor(
|
? HtmlEditor(
|
||||||
key: Key('composer_editor'),
|
key: Key('composer_editor'),
|
||||||
minHeight: 400,
|
minHeight: 400,
|
||||||
|
supportZoom: true,
|
||||||
|
disableHorizontalScroll: false,
|
||||||
|
disableVerticalScroll: false,
|
||||||
onCreated: (editorApi) => controller.htmlEditorApi = editorApi,
|
onCreated: (editorApi) => controller.htmlEditorApi = editorApi,
|
||||||
initialContent: message,
|
initialContent: message,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
import 'package:model/model.dart';
|
||||||
|
|
||||||
|
abstract class HtmlDataSource {
|
||||||
|
Future<String> transformToHtml(EmailContent emailContent);
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import 'package:model/email/email_content.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/data/datasource/html_datasource.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/data/local/html_analyzer.dart';
|
||||||
|
|
||||||
|
class HtmlDataSourceImpl extends HtmlDataSource {
|
||||||
|
|
||||||
|
final HtmlAnalyzer _htmlAnalyzer;
|
||||||
|
|
||||||
|
HtmlDataSourceImpl(this._htmlAnalyzer);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<String> transformToHtml(EmailContent emailContent) {
|
||||||
|
return Future.sync(() async {
|
||||||
|
return await _htmlAnalyzer.transformToHtml(emailContent);
|
||||||
|
}).catchError((error) {
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
import 'package:core/presentation/utils/html_transformer/html_transform.dart';
|
||||||
|
import 'package:model/email/email_content_type.dart';
|
||||||
|
import 'package:model/model.dart';
|
||||||
|
|
||||||
|
class HtmlAnalyzer {
|
||||||
|
|
||||||
|
Future<String> transformToHtml(EmailContent emailContent) async {
|
||||||
|
switch(emailContent.type) {
|
||||||
|
case EmailContentType.textHtml:
|
||||||
|
final htmlTransform = HtmlTransform(emailContent.content);
|
||||||
|
return htmlTransform.transformToHtml();
|
||||||
|
default:
|
||||||
|
return emailContent.content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,14 +5,16 @@ import 'package:jmap_dart_client/jmap/mail/email/email.dart';
|
|||||||
import 'package:model/model.dart';
|
import 'package:model/model.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart';
|
import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart';
|
import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/data/datasource/html_datasource.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/model/move_request.dart';
|
import 'package:tmail_ui_user/features/email/domain/model/move_request.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
|
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
|
||||||
|
|
||||||
class EmailRepositoryImpl extends EmailRepository {
|
class EmailRepositoryImpl extends EmailRepository {
|
||||||
|
|
||||||
final EmailDataSource emailDataSource;
|
final EmailDataSource emailDataSource;
|
||||||
|
final HtmlDataSource _htmlDataSource;
|
||||||
|
|
||||||
EmailRepositoryImpl(this.emailDataSource);
|
EmailRepositoryImpl(this.emailDataSource, this._htmlDataSource);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Email> getEmailContent(AccountId accountId, EmailId emailId) {
|
Future<Email> getEmailContent(AccountId accountId, EmailId emailId) {
|
||||||
@@ -68,4 +70,9 @@ class EmailRepositoryImpl extends EmailRepository {
|
|||||||
) {
|
) {
|
||||||
return emailDataSource.markAsStar(accountId, emails, markStarAction);
|
return emailDataSource.markAsStar(accountId, emails, markStarAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<String> transformEmailContentToHtml(EmailContent emailContent) {
|
||||||
|
return _htmlDataSource.transformToHtml(emailContent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -34,4 +34,6 @@ abstract class EmailRepository {
|
|||||||
List<Email> emails,
|
List<Email> emails,
|
||||||
MarkStarAction markStarAction
|
MarkStarAction markStarAction
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Future<String> transformEmailContentToHtml(EmailContent emailContent);
|
||||||
}
|
}
|
||||||
@@ -2,13 +2,13 @@ import 'package:core/core.dart';
|
|||||||
import 'package:model/model.dart';
|
import 'package:model/model.dart';
|
||||||
|
|
||||||
class GetEmailContentSuccess extends UIState {
|
class GetEmailContentSuccess extends UIState {
|
||||||
final List<EmailContent> emailContents;
|
final EmailContent emailContent;
|
||||||
final List<Attachment> attachments;
|
final List<Attachment> attachments;
|
||||||
|
|
||||||
GetEmailContentSuccess(this.emailContents, this.attachments);
|
GetEmailContentSuccess(this.emailContent, this.attachments);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [emailContents, attachments];
|
List<Object?> get props => [emailContent, attachments];
|
||||||
}
|
}
|
||||||
|
|
||||||
class GetEmailContentFailure extends FeatureFailure {
|
class GetEmailContentFailure extends FeatureFailure {
|
||||||
|
|||||||
@@ -15,9 +15,20 @@ class GetEmailContentInteractor {
|
|||||||
try {
|
try {
|
||||||
yield Right<Failure, Success>(LoadingState());
|
yield Right<Failure, Success>(LoadingState());
|
||||||
final email = await emailRepository.getEmailContent(accountId, emailId);
|
final email = await emailRepository.getEmailContent(accountId, emailId);
|
||||||
yield Right<Failure, Success>(GetEmailContentSuccess(
|
|
||||||
email.emailContentList,
|
if (email.emailContentList.isNotEmpty) {
|
||||||
email.allAttachments));
|
final emailContent = email.emailContentList.first;
|
||||||
|
if (emailContent.type == EmailContentType.textHtml) {
|
||||||
|
final contentHtml = await emailRepository.transformEmailContentToHtml(emailContent);
|
||||||
|
yield Right<Failure, Success>(GetEmailContentSuccess(
|
||||||
|
EmailContent(emailContent.type, contentHtml),
|
||||||
|
email.allAttachments));
|
||||||
|
} else {
|
||||||
|
yield Right<Failure, Success>(GetEmailContentSuccess(emailContent, email.allAttachments));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
yield Left(GetEmailContentFailure(null));
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
yield Left(GetEmailContentFailure(e));
|
yield Left(GetEmailContentFailure(e));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
|
|
||||||
class EmailConstants {
|
|
||||||
static const HTML_TEXT = 'text/html';
|
|
||||||
static const PLAIN_TEXT = 'text/plain';
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,10 @@ import 'package:get/get.dart';
|
|||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/domain/usecases/send_email_interactor.dart';
|
import 'package:tmail_ui_user/features/composer/domain/usecases/send_email_interactor.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart';
|
import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/data/datasource/html_datasource.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/datasource_impl/email_datasource_impl.dart';
|
import 'package:tmail_ui_user/features/email/data/datasource_impl/email_datasource_impl.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/data/datasource_impl/html_datasource_impl.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/data/local/html_analyzer.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/network/email_api.dart';
|
import 'package:tmail_ui_user/features/email/data/network/email_api.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/repository/email_repository_impl.dart';
|
import 'package:tmail_ui_user/features/email/data/repository/email_repository_impl.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
|
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
|
||||||
@@ -22,7 +25,11 @@ class EmailBindings extends Bindings {
|
|||||||
void dependencies() {
|
void dependencies() {
|
||||||
Get.lazyPut(() => EmailDataSourceImpl(Get.find<EmailAPI>()));
|
Get.lazyPut(() => EmailDataSourceImpl(Get.find<EmailAPI>()));
|
||||||
Get.lazyPut<EmailDataSource>(() => Get.find<EmailDataSourceImpl>());
|
Get.lazyPut<EmailDataSource>(() => Get.find<EmailDataSourceImpl>());
|
||||||
Get.lazyPut(() => EmailRepositoryImpl(Get.find<EmailDataSource>()));
|
Get.lazyPut(() => HtmlDataSourceImpl(Get.find<HtmlAnalyzer>()));
|
||||||
|
Get.lazyPut<HtmlDataSource>(() => Get.find<HtmlDataSourceImpl>());
|
||||||
|
Get.lazyPut(() => EmailRepositoryImpl(
|
||||||
|
Get.find<EmailDataSource>(),
|
||||||
|
Get.find<HtmlDataSource>()));
|
||||||
Get.lazyPut<EmailRepository>(() => Get.find<EmailRepositoryImpl>());
|
Get.lazyPut<EmailRepository>(() => Get.find<EmailRepositoryImpl>());
|
||||||
Get.put(SendEmailInteractor(Get.find<EmailRepository>()));
|
Get.put(SendEmailInteractor(Get.find<EmailRepository>()));
|
||||||
Get.lazyPut(() => GetEmailContentInteractor(Get.find<EmailRepository>()));
|
Get.lazyPut(() => GetEmailContentInteractor(Get.find<EmailRepository>()));
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class EmailController extends BaseController {
|
|||||||
|
|
||||||
final emailAddressExpandMode = ExpandMode.COLLAPSE.obs;
|
final emailAddressExpandMode = ExpandMode.COLLAPSE.obs;
|
||||||
final attachmentsExpandMode = ExpandMode.COLLAPSE.obs;
|
final attachmentsExpandMode = ExpandMode.COLLAPSE.obs;
|
||||||
final emailContents = <EmailContent>[].obs;
|
final emailContent = Rxn<EmailContent>();
|
||||||
final attachments = <Attachment>[].obs;
|
final attachments = <Attachment>[].obs;
|
||||||
EmailId? _currentEmailId;
|
EmailId? _currentEmailId;
|
||||||
|
|
||||||
@@ -129,9 +129,9 @@ class EmailController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _getEmailContentSuccess(GetEmailContentSuccess success) {
|
void _getEmailContentSuccess(GetEmailContentSuccess success) {
|
||||||
emailContents.value = success.emailContents;
|
emailContent.value = success.emailContent;
|
||||||
attachments.value = success.attachments;
|
attachments.value = success.attachments;
|
||||||
if (emailContents.isNotEmpty) {
|
if (emailContent.value != null && emailContent.value!.type == EmailContentType.textHtml) {
|
||||||
dispatchState(Right(WebViewLoadingState()));
|
dispatchState(Right(WebViewLoadingState()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,7 +139,7 @@ class EmailController extends BaseController {
|
|||||||
void _clearEmailContent() {
|
void _clearEmailContent() {
|
||||||
toggleDisplayEmailAddressAction(expandMode: ExpandMode.COLLAPSE);
|
toggleDisplayEmailAddressAction(expandMode: ExpandMode.COLLAPSE);
|
||||||
attachmentsExpandMode.value = ExpandMode.COLLAPSE;
|
attachmentsExpandMode.value = ExpandMode.COLLAPSE;
|
||||||
emailContents.clear();
|
emailContent.value = null;
|
||||||
attachments.clear();
|
attachments.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,24 +347,17 @@ class EmailController extends BaseController {
|
|||||||
&& mailboxDashBoardController.selectedEmail.value != null;
|
&& mailboxDashBoardController.selectedEmail.value != null;
|
||||||
|
|
||||||
void backToThreadView() {
|
void backToThreadView() {
|
||||||
if (emailContents.isNotEmpty) {
|
|
||||||
dispatchState(Right(WebViewLoadCompletedState()));
|
|
||||||
}
|
|
||||||
popBack();
|
popBack();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pressEmailAction(EmailActionType emailActionType) {
|
void pressEmailAction(EmailActionType emailActionType) {
|
||||||
if (canComposeEmail()) {
|
if (canComposeEmail()) {
|
||||||
if (emailContents.isNotEmpty) {
|
|
||||||
clearState();
|
|
||||||
}
|
|
||||||
|
|
||||||
push(
|
push(
|
||||||
AppRoutes.COMPOSER,
|
AppRoutes.COMPOSER,
|
||||||
arguments: ComposerArguments(
|
arguments: ComposerArguments(
|
||||||
emailActionType: emailActionType,
|
emailActionType: emailActionType,
|
||||||
presentationEmail: mailboxDashBoardController.selectedEmail.value!,
|
presentationEmail: mailboxDashBoardController.selectedEmail.value!,
|
||||||
emailContents: emailContents,
|
emailContent: emailContent.value,
|
||||||
attachments: attachments,
|
attachments: attachments,
|
||||||
mailboxRole: mailboxDashBoardController.selectedMailbox.value?.role,
|
mailboxRole: mailboxDashBoardController.selectedMailbox.value?.role,
|
||||||
session: mailboxDashBoardController.sessionCurrent!,
|
session: mailboxDashBoardController.sessionCurrent!,
|
||||||
|
|||||||
@@ -27,11 +27,6 @@ class EmailView extends GetView {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
emailController.viewState.value.map((success) {
|
|
||||||
if (success is WebViewLoadCompletedState && emailController.emailContents.isNotEmpty) {
|
|
||||||
emailController.dispatchState(Right(WebViewLoadingState()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
resizeToAvoidBottomInset: false,
|
resizeToAvoidBottomInset: false,
|
||||||
backgroundColor: AppColor.primaryLightColor,
|
backgroundColor: AppColor.primaryLightColor,
|
||||||
@@ -279,11 +274,27 @@ class EmailView extends GetView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildEmailContent() {
|
Widget _buildEmailContent() {
|
||||||
return Obx(() => emailController.emailContents.isNotEmpty
|
return Obx(() {
|
||||||
? HtmlContentViewer(
|
if (emailController.emailContent.value != null) {
|
||||||
message: emailController.emailContents.first.content,
|
switch(emailController.emailContent.value!.type) {
|
||||||
onWebViewLoadStop: (webController, uri) => emailController.dispatchState(Right(WebViewLoadCompletedState())),
|
case EmailContentType.textHtml:
|
||||||
mailtoDelegate: (uri) async {})
|
return HtmlContentViewer(
|
||||||
: SizedBox.shrink());
|
contentHtml: emailController.emailContent.value!.content,
|
||||||
|
onLoadStart: (webController, uri) => emailController.dispatchState(Right(WebViewLoadingState())),
|
||||||
|
onLoadStop: (webController, uri) => emailController.dispatchState(Right(WebViewLoadCompletedState())),
|
||||||
|
mailtoDelegate: (uri) async {});
|
||||||
|
case EmailContentType.textPlain:
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.only(top: 16),
|
||||||
|
child: Text(
|
||||||
|
emailController.emailContent.value!.content,
|
||||||
|
style: TextStyle(fontSize: 14, color: AppColor.nameUserColor)));
|
||||||
|
case EmailContentType.other:
|
||||||
|
return SizedBox.shrink();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return SizedBox.shrink();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,7 +7,7 @@ import 'package:model/model.dart';
|
|||||||
class ComposerArguments with EquatableMixin {
|
class ComposerArguments with EquatableMixin {
|
||||||
final EmailActionType emailActionType;
|
final EmailActionType emailActionType;
|
||||||
final PresentationEmail? presentationEmail;
|
final PresentationEmail? presentationEmail;
|
||||||
final List<EmailContent>? emailContents;
|
final EmailContent? emailContent;
|
||||||
final List<Attachment>? attachments;
|
final List<Attachment>? attachments;
|
||||||
final Session session;
|
final Session session;
|
||||||
final UserProfile userProfile;
|
final UserProfile userProfile;
|
||||||
@@ -17,7 +17,7 @@ class ComposerArguments with EquatableMixin {
|
|||||||
ComposerArguments({
|
ComposerArguments({
|
||||||
this.emailActionType = EmailActionType.compose,
|
this.emailActionType = EmailActionType.compose,
|
||||||
this.presentationEmail,
|
this.presentationEmail,
|
||||||
this.emailContents,
|
this.emailContent,
|
||||||
this.attachments,
|
this.attachments,
|
||||||
this.mailboxRole,
|
this.mailboxRole,
|
||||||
required this.session,
|
required this.session,
|
||||||
@@ -29,7 +29,7 @@ class ComposerArguments with EquatableMixin {
|
|||||||
List<Object?> get props => [
|
List<Object?> get props => [
|
||||||
emailActionType,
|
emailActionType,
|
||||||
presentationEmail,
|
presentationEmail,
|
||||||
emailContents,
|
emailContent,
|
||||||
attachments,
|
attachments,
|
||||||
mailboxRole,
|
mailboxRole,
|
||||||
session,
|
session,
|
||||||
|
|||||||
@@ -4,7 +4,10 @@ import 'package:flutter/cupertino.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:tmail_ui_user/features/caching/state_cache_client.dart';
|
import 'package:tmail_ui_user/features/caching/state_cache_client.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart';
|
import 'package:tmail_ui_user/features/email/data/datasource/email_datasource.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/data/datasource/html_datasource.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/datasource_impl/email_datasource_impl.dart';
|
import 'package:tmail_ui_user/features/email/data/datasource_impl/email_datasource_impl.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/data/datasource_impl/html_datasource_impl.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/data/local/html_analyzer.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/network/email_api.dart';
|
import 'package:tmail_ui_user/features/email/data/network/email_api.dart';
|
||||||
import 'package:tmail_ui_user/features/email/data/repository/email_repository_impl.dart';
|
import 'package:tmail_ui_user/features/email/data/repository/email_repository_impl.dart';
|
||||||
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
|
import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart';
|
||||||
@@ -48,7 +51,11 @@ class ThreadBindings extends Bindings {
|
|||||||
Get.lazyPut(() => ScrollController());
|
Get.lazyPut(() => ScrollController());
|
||||||
Get.lazyPut(() => EmailDataSourceImpl(Get.find<EmailAPI>()));
|
Get.lazyPut(() => EmailDataSourceImpl(Get.find<EmailAPI>()));
|
||||||
Get.lazyPut<EmailDataSource>(() => Get.find<EmailDataSourceImpl>());
|
Get.lazyPut<EmailDataSource>(() => Get.find<EmailDataSourceImpl>());
|
||||||
Get.lazyPut(() => EmailRepositoryImpl(Get.find<EmailDataSource>()));
|
Get.lazyPut(() => HtmlDataSourceImpl(Get.find<HtmlAnalyzer>()));
|
||||||
|
Get.lazyPut<HtmlDataSource>(() => Get.find<HtmlDataSourceImpl>());
|
||||||
|
Get.lazyPut(() => EmailRepositoryImpl(
|
||||||
|
Get.find<EmailDataSource>(),
|
||||||
|
Get.find<HtmlDataSource>()));
|
||||||
Get.lazyPut<EmailRepository>(() => Get.find<EmailRepositoryImpl>());
|
Get.lazyPut<EmailRepository>(() => Get.find<EmailRepositoryImpl>());
|
||||||
Get.lazyPut(() => MarkAsEmailReadInteractor(Get.find<EmailRepository>()));
|
Get.lazyPut(() => MarkAsEmailReadInteractor(Get.find<EmailRepository>()));
|
||||||
Get.lazyPut(() => MarkAsMultipleEmailReadInteractor(Get.find<EmailRepository>()));
|
Get.lazyPut(() => MarkAsMultipleEmailReadInteractor(Get.find<EmailRepository>()));
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:core/presentation/utils/app_toast.dart';
|
|||||||
import 'package:device_info/device_info.dart';
|
import 'package:device_info/device_info.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/data/local/html_analyzer.dart';
|
||||||
|
|
||||||
class CoreBindings extends Bindings {
|
class CoreBindings extends Bindings {
|
||||||
|
|
||||||
@@ -35,6 +36,7 @@ class CoreBindings extends Bindings {
|
|||||||
|
|
||||||
void _bindingValidator() {
|
void _bindingValidator() {
|
||||||
Get.put(HtmlMessagePurifier());
|
Get.put(HtmlMessagePurifier());
|
||||||
|
Get.put(HtmlAnalyzer());
|
||||||
}
|
}
|
||||||
|
|
||||||
void _bindingToast() {
|
void _bindingToast() {
|
||||||
|
|||||||
Reference in New Issue
Block a user