Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 0 additions & 38 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,64 +1,26 @@
PODS:
- Flutter (1.0.0)
- integration_test (0.0.1):
- Flutter
- open_filex (0.0.2):
- Flutter
- package_info_plus (0.4.5):
- Flutter
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- share_plus (0.0.1):
- Flutter
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- url_launcher_ios (0.0.1):
- Flutter
- workmanager_apple (0.0.1):
- Flutter

DEPENDENCIES:
- Flutter (from `Flutter`)
- integration_test (from `.symlinks/plugins/integration_test/ios`)
- open_filex (from `.symlinks/plugins/open_filex/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- workmanager_apple (from `.symlinks/plugins/workmanager_apple/ios`)

EXTERNAL SOURCES:
Flutter:
:path: Flutter
integration_test:
:path: ".symlinks/plugins/integration_test/ios"
open_filex:
:path: ".symlinks/plugins/open_filex/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
share_plus:
:path: ".symlinks/plugins/share_plus/ios"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
workmanager_apple:
:path: ".symlinks/plugins/workmanager_apple/ios"

SPEC CHECKSUMS:
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e
open_filex: 432f3cd11432da3e39f47fcc0df2b1603854eff1
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
workmanager_apple: 904529ae31e97fc5be632cf628507652294a0778

PODFILE CHECKSUM: ec1ad48fafee7989ae02b93f14e4d03d1f0e05bb
Expand Down
40 changes: 30 additions & 10 deletions ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
Expand Down Expand Up @@ -38,6 +39,7 @@
4CC19D185F571E45AC7BB4FF /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
Expand All @@ -56,6 +58,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
D0190EC4023141C93A5318E8 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -84,6 +87,7 @@
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
Expand Down Expand Up @@ -148,6 +152,9 @@
dependencies = (
);
name = Runner;
packageProductDependencies = (
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */,
);
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
Expand Down Expand Up @@ -176,6 +183,9 @@
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
packageReferences = (
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */,
);
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
Expand Down Expand Up @@ -209,14 +219,10 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
Expand Down Expand Up @@ -365,7 +371,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 11;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 78WP6ZX639;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
Expand All @@ -375,7 +381,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 0.8.7;
MARKETING_VERSION = 0.8.8;
PRODUCT_BUNDLE_IDENTIFIER = net.4training.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
Expand Down Expand Up @@ -502,7 +508,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 11;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 78WP6ZX639;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
Expand All @@ -512,7 +518,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 0.8.7;
MARKETING_VERSION = 0.8.8;
PRODUCT_BUNDLE_IDENTIFIER = net.4training.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
Expand All @@ -533,7 +539,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 11;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 78WP6ZX639;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
Expand All @@ -543,7 +549,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 0.8.7;
MARKETING_VERSION = 0.8.8;
PRODUCT_BUNDLE_IDENTIFIER = net.4training.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
Expand Down Expand Up @@ -581,6 +587,20 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */

/* Begin XCLocalSwiftPackageReference section */
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
};
/* End XCLocalSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = {
isa = XCSwiftPackageProductDependency;
productName = FlutterGeneratedPluginSwiftPackage;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}
18 changes: 18 additions & 0 deletions ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,24 @@
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<PreActions>
<ExecutionAction
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
<ActionContent
title = "Run Prepare Flutter Framework Script"
scriptText = "/bin/sh &quot;$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh&quot; prepare&#10;">
<EnvironmentBuildable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</EnvironmentBuildable>
</ActionContent>
</ExecutionAction>
</PreActions>
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
Expand Down
21 changes: 16 additions & 5 deletions lib/widgets/html_view.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:app4training/widgets/invertible_image_builtin.dart';
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_html_table/flutter_html_table.dart';
Expand All @@ -17,6 +18,7 @@ class HtmlView extends StatelessWidget {

@override
Widget build(BuildContext context) {
final bool isDarkMode = Theme.of(context).brightness == Brightness.dark;
return Padding(
padding: const EdgeInsets.all(8),
child: SingleChildScrollView(
Expand All @@ -28,11 +30,11 @@ class HtmlView extends StatelessWidget {
// child: Html(
// data: content,
child: Html.fromDom(
document: sanitize(
content,
MediaQuery.of(context).platformBrightness ==
Brightness.dark,
),
// The theme's brightness (not the platform brightness)
// is the canonical dark-mode source for this widget:
// the sanitize pass and the image inversion must flip
// together with the widget colors.
document: sanitize(content, isDarkMode),
extensions: [
// Order matters: TagWrapExtension must come BEFORE
// TableHtmlExtension so it matches <table> first
Expand Down Expand Up @@ -63,6 +65,15 @@ class HtmlView extends StatelessWidget {
builder: (child) => _HorizontalTableScroll(child: child),
),
const TableHtmlExtension(),
// Renders images like the built-in renderer, but
// inverts their colors (keeping hue) in dark mode so
// black-on-transparent drawings stay visible.
// Deliberately a subclass of the built-in image
// renderer and not a TagWrapExtension: at build time
// TagWrapExtension matches any wrapper element,
// which would collide with the table wrapper above
// under first-match-wins dispatch.
InvertibleImageBuiltIn(invert: isDarkMode),
],
style: {
"body": Style(fontSize: FontSize(15)),
Expand Down
54 changes: 54 additions & 0 deletions lib/widgets/invertible_image_builtin.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// ImageBuiltIn is not exported by package:flutter_html/flutter_html.dart,
// only reachable via this implementation import. flutter_html's own
// ImageExtension helper subclasses it through the same import, but its
// builder API *replaces* the built-in rendering instead of wrapping it,
// so it can't be used to filter the widget the built-in builds.
// ignore_for_file: implementation_imports
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_html/src/builtins/image_builtin.dart';

/// Renders `<img>` elements exactly like flutter_html's built-in image
/// renderer, optionally drawing the image through a hue-preserving color
/// inversion for dark mode: black becomes white, grays flip lightness,
/// transparency passes through unchanged and colored artwork keeps its
/// hue with lightness flipped.
///
/// With [invert] false the built-in rendering is returned unchanged —
/// no wrapper widget is added at all.
class InvertibleImageBuiltIn extends ImageBuiltIn {
final bool invert;

const InvertibleImageBuiltIn({required this.invert});

@override
InlineSpan build(ExtensionContext context) {
final span = super.build(context);
if (!invert || span is! WidgetSpan) {
// Light mode stays untouched; so do images the built-in renderer
// can't decode (super returns a plain TextSpan with the alt text).
return span;
}
return WidgetSpan(
alignment: span.alignment,
baseline: span.baseline,
style: span.style,
child: ColorFiltered(
colorFilter: const ColorFilter.matrix(_invertKeepHueMatrix),
child: span.child,
),
);
}
}

/// Color inversion that keeps hues, like CSS
/// `filter: invert(1) hue-rotate(180deg)` ("smart invert"):
/// black -> white, grays invert exactly (each row sums to -1, plus the
/// 255 offset), alpha is untouched (last row) and colors keep their hue
/// with flipped lightness.
const List<double> _invertKeepHueMatrix = [
0.574, -1.430, -0.144, 0, 255, //
-0.426, -0.430, -0.144, 0, 255, //
-0.426, -1.430, 0.856, 0, 255, //
0, 0, 0, 1, 0,
];
16 changes: 8 additions & 8 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -496,10 +496,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349"
url: "https://pub.dev"
source: hosted
version: "1.17.0"
version: "1.18.0"
mime:
dependency: transitive
description:
Expand Down Expand Up @@ -893,26 +893,26 @@ packages:
dependency: "direct dev"
description:
name: test
sha256: "280d6d890011ca966ad08df7e8a4ddfab0fb3aa49f96ed6de56e3521347a9ae7"
sha256: "8d9ceddbab833f180fbefed08afa76d7c03513dfdba87ffcec2718b02bbcbf20"
url: "https://pub.dev"
source: hosted
version: "1.30.0"
version: "1.31.0"
test_api:
dependency: transitive
description:
name: test_api
sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e"
url: "https://pub.dev"
source: hosted
version: "0.7.10"
version: "0.7.11"
test_core:
dependency: transitive
description:
name: test_core
sha256: "0381bd1585d1a924763c308100f2138205252fb90c9d4eeaf28489ee65ccde51"
sha256: "1991d4cfe85d5043241acac92962c3977c8d2f2add1ee73130c7b286417d1d34"
url: "https://pub.dev"
source: hosted
version: "0.6.16"
version: "0.6.17"
typed_data:
dependency: transitive
description:
Expand Down
Loading
Loading