Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52e6e8842a |
@@ -13,7 +13,6 @@ android {
|
|||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
targetCompatibility = JavaVersion.VERSION_17
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
isCoreLibraryDesugaringEnabled = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
@@ -66,8 +65,6 @@ flutter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// Required for flutter_local_notifications and other plugins that need Java 8+ APIs on API < 26.
|
|
||||||
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4")
|
|
||||||
// integration_test is a dev dependency; the Flutter plugin loader adds it as
|
// integration_test is a dev dependency; the Flutter plugin loader adds it as
|
||||||
// debugImplementation only, but GeneratedPluginRegistrant.java (in src/main)
|
// debugImplementation only, but GeneratedPluginRegistrant.java (in src/main)
|
||||||
// references its class in all variants. Make it available for release compilation
|
// references its class in all variants. Make it available for release compilation
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ class _EmailDetailScreenState extends ConsumerState<EmailDetailScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
_SafeHtml(
|
Html(
|
||||||
data: body.htmlBody!,
|
data: body.htmlBody!,
|
||||||
extensions: [if (!_loadRemoteImages) _BlockRemoteImagesExtension()],
|
extensions: [if (!_loadRemoteImages) _BlockRemoteImagesExtension()],
|
||||||
),
|
),
|
||||||
@@ -501,57 +501,6 @@ class _UnsubscribeChip extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renders [Html] and falls back to an error message if the widget throws
|
|
||||||
/// during build, preventing a malformed body from crashing the whole screen.
|
|
||||||
class _SafeHtml extends StatefulWidget {
|
|
||||||
const _SafeHtml({required this.data, required this.extensions});
|
|
||||||
final String data;
|
|
||||||
final List<HtmlExtension> extensions;
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<_SafeHtml> createState() => _SafeHtmlState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _SafeHtmlState extends State<_SafeHtml> {
|
|
||||||
bool _failed = false;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
if (_failed) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.all(8),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
Icons.warning_amber_outlined,
|
|
||||||
color: Theme.of(context).colorScheme.error,
|
|
||||||
size: 16,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
const Expanded(child: Text('Message body could not be rendered.')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Intercept any build-phase throw from flutter_html for this subtree.
|
|
||||||
// We save/restore via postFrameCallback so other widgets are unaffected.
|
|
||||||
final prev = ErrorWidget.builder;
|
|
||||||
ErrorWidget.builder = (FlutterErrorDetails details) {
|
|
||||||
ErrorWidget.builder = prev;
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
||||||
if (mounted) setState(() => _failed = true);
|
|
||||||
});
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
};
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback(
|
|
||||||
(_) => ErrorWidget.builder = prev,
|
|
||||||
);
|
|
||||||
|
|
||||||
return Html(data: widget.data, extensions: widget.extensions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _BlockRemoteImagesExtension extends HtmlExtension {
|
class _BlockRemoteImagesExtension extends HtmlExtension {
|
||||||
@override
|
@override
|
||||||
Set<String> get supportedTags => {'img'};
|
Set<String> get supportedTags => {'img'};
|
||||||
|
|||||||
Reference in New Issue
Block a user